refactor: openpitrix module
Signed-off-by: hongming <talonwan@yunify.com>
This commit is contained in:
@@ -7,6 +7,7 @@ import (
|
||||
kubesphereconfig "kubesphere.io/kubesphere/pkg/server/config"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/devops"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/openpitrix"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/s2is3"
|
||||
"strings"
|
||||
)
|
||||
@@ -15,6 +16,7 @@ type KubeSphereControllerManagerOptions struct {
|
||||
KubernetesOptions *k8s.KubernetesOptions
|
||||
DevopsOptions *devops.DevopsOptions
|
||||
S3Options *s2is3.S3Options
|
||||
OpenPitrixOptions *openpitrix.OpenPitrixOptions
|
||||
}
|
||||
|
||||
func NewKubeSphereControllerManagerOptions() *KubeSphereControllerManagerOptions {
|
||||
@@ -22,6 +24,7 @@ func NewKubeSphereControllerManagerOptions() *KubeSphereControllerManagerOptions
|
||||
KubernetesOptions: k8s.NewKubernetesOptions(),
|
||||
DevopsOptions: devops.NewDevopsOptions(),
|
||||
S3Options: s2is3.NewS3Options(),
|
||||
OpenPitrixOptions: openpitrix.NewOpenPitrixOptions(),
|
||||
}
|
||||
|
||||
return s
|
||||
@@ -31,7 +34,7 @@ func (s *KubeSphereControllerManagerOptions) ApplyTo(conf *kubesphereconfig.Conf
|
||||
s.S3Options.ApplyTo(conf.S3Options)
|
||||
s.KubernetesOptions.ApplyTo(conf.KubernetesOptions)
|
||||
s.DevopsOptions.ApplyTo(conf.DevopsOptions)
|
||||
|
||||
s.OpenPitrixOptions.ApplyTo(conf.OpenPitrixOptions)
|
||||
}
|
||||
|
||||
func (s *KubeSphereControllerManagerOptions) Flags() cliflag.NamedFlagSets {
|
||||
@@ -40,6 +43,7 @@ func (s *KubeSphereControllerManagerOptions) Flags() cliflag.NamedFlagSets {
|
||||
s.KubernetesOptions.AddFlags(fss.FlagSet("kubernetes"))
|
||||
s.DevopsOptions.AddFlags(fss.FlagSet("devops"))
|
||||
s.S3Options.AddFlags(fss.FlagSet("s3"))
|
||||
s.OpenPitrixOptions.AddFlags(fss.FlagSet("openpitrix"))
|
||||
|
||||
fs := fss.FlagSet("klog")
|
||||
local := flag.NewFlagSet("klog", flag.ExitOnError)
|
||||
@@ -54,10 +58,9 @@ func (s *KubeSphereControllerManagerOptions) Flags() cliflag.NamedFlagSets {
|
||||
|
||||
func (s *KubeSphereControllerManagerOptions) Validate() []error {
|
||||
var errs []error
|
||||
|
||||
errs = append(errs, s.DevopsOptions.Validate()...)
|
||||
errs = append(errs, s.KubernetesOptions.Validate()...)
|
||||
errs = append(errs, s.S3Options.Validate()...)
|
||||
|
||||
errs = append(errs, s.OpenPitrixOptions.Validate()...)
|
||||
return errs
|
||||
}
|
||||
|
||||
@@ -49,10 +49,7 @@ func NewControllerManagerCommand() *cobra.Command {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
err = Complete(s)
|
||||
if err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
s = Complete(s)
|
||||
|
||||
if errs := s.Validate(); len(errs) != 0 {
|
||||
klog.Error(utilerrors.NewAggregate(errs))
|
||||
@@ -81,22 +78,24 @@ func NewControllerManagerCommand() *cobra.Command {
|
||||
return cmd
|
||||
}
|
||||
|
||||
func Complete(s *options.KubeSphereControllerManagerOptions) error {
|
||||
func Complete(s *options.KubeSphereControllerManagerOptions) *options.KubeSphereControllerManagerOptions {
|
||||
conf := controllerconfig.Get()
|
||||
|
||||
conf.Apply(&controllerconfig.Config{
|
||||
DevopsOptions: s.DevopsOptions,
|
||||
KubernetesOptions: s.KubernetesOptions,
|
||||
S3Options: s.S3Options,
|
||||
OpenPitrixOptions: s.OpenPitrixOptions,
|
||||
})
|
||||
|
||||
s = &options.KubeSphereControllerManagerOptions{
|
||||
out := &options.KubeSphereControllerManagerOptions{
|
||||
KubernetesOptions: conf.KubernetesOptions,
|
||||
DevopsOptions: conf.DevopsOptions,
|
||||
S3Options: conf.S3Options,
|
||||
OpenPitrixOptions: conf.OpenPitrixOptions,
|
||||
}
|
||||
|
||||
return nil
|
||||
return out
|
||||
}
|
||||
|
||||
func CreateClientSet(s *options.KubeSphereControllerManagerOptions, stopCh <-chan struct{}) error {
|
||||
@@ -104,7 +103,8 @@ func CreateClientSet(s *options.KubeSphereControllerManagerOptions, stopCh <-cha
|
||||
|
||||
csop.SetKubernetesOptions(s.KubernetesOptions).
|
||||
SetDevopsOptions(s.DevopsOptions).
|
||||
SetS3Options(s.S3Options)
|
||||
SetS3Options(s.S3Options).
|
||||
SetOpenPitrixOptions(s.OpenPitrixOptions)
|
||||
client.NewClientSetFactory(csop, stopCh)
|
||||
|
||||
return nil
|
||||
|
||||
@@ -24,6 +24,7 @@ import (
|
||||
_ "kubesphere.io/kubesphere/pkg/apis/devops/install"
|
||||
_ "kubesphere.io/kubesphere/pkg/apis/logging/install"
|
||||
_ "kubesphere.io/kubesphere/pkg/apis/monitoring/install"
|
||||
_ "kubesphere.io/kubesphere/pkg/apis/openpitrix/install"
|
||||
_ "kubesphere.io/kubesphere/pkg/apis/operations/install"
|
||||
_ "kubesphere.io/kubesphere/pkg/apis/resources/install"
|
||||
_ "kubesphere.io/kubesphere/pkg/apis/servicemesh/metrics/install"
|
||||
|
||||
43
go.mod
43
go.mod
@@ -11,11 +11,12 @@ require (
|
||||
code.cloudfoundry.org/bytefmt v0.0.0-20190710193110-1eb035ffe2b6
|
||||
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 // indirect
|
||||
github.com/Azure/go-autorest/autorest v0.5.0 // indirect
|
||||
github.com/Masterminds/semver v1.5.0 // indirect
|
||||
github.com/Microsoft/go-winio v0.4.12 // indirect
|
||||
github.com/NYTimes/gziphandler v1.1.1 // indirect
|
||||
github.com/PuerkitoBio/goquery v1.5.0
|
||||
github.com/appscode/jsonpatch v0.0.0-20190108182946-7c0e3b262f30 // indirect
|
||||
github.com/asaskevich/govalidator v0.0.0-20180315120708-ccb8e960c48f
|
||||
github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf
|
||||
github.com/aws/aws-sdk-go v1.22.2
|
||||
github.com/beevik/etree v1.1.0
|
||||
github.com/beorn7/perks v1.0.0 // indirect
|
||||
@@ -24,7 +25,6 @@ require (
|
||||
github.com/coreos/etcd v3.3.13+incompatible // indirect
|
||||
github.com/coreos/go-semver v0.3.0 // indirect
|
||||
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f // indirect
|
||||
github.com/deckarep/golang-set v1.7.1 // indirect
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
||||
github.com/docker/distribution v2.7.1+incompatible
|
||||
github.com/docker/docker v1.4.2-0.20190822205725-ed20165a37b4
|
||||
@@ -49,6 +49,7 @@ require (
|
||||
github.com/go-openapi/jsonpointer v0.19.0 // indirect
|
||||
github.com/go-openapi/jsonreference v0.19.0 // indirect
|
||||
github.com/go-openapi/spec v0.19.0
|
||||
github.com/go-openapi/strfmt v0.19.0
|
||||
github.com/go-openapi/swag v0.19.0 // indirect
|
||||
github.com/go-playground/locales v0.12.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.16.0 // indirect
|
||||
@@ -57,6 +58,7 @@ require (
|
||||
github.com/gobuffalo/flect v0.1.5 // indirect
|
||||
github.com/gocraft/dbr v0.0.0-20180507214907-a0fd650918f6
|
||||
github.com/golang/example v0.0.0-20170904185048-46695d81d1fa
|
||||
github.com/golang/protobuf v1.3.1
|
||||
github.com/google/go-querystring v1.0.0 // indirect
|
||||
github.com/google/gofuzz v1.0.0 // indirect
|
||||
github.com/google/uuid v1.1.1
|
||||
@@ -97,7 +99,6 @@ require (
|
||||
github.com/openshift/api v3.9.0+incompatible // indirect
|
||||
github.com/pborman/uuid v0.0.0-20180906182336-adf5a7427709 // indirect
|
||||
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
|
||||
github.com/pkg/errors v0.8.1 // indirect
|
||||
github.com/projectcalico/go-json v0.0.0-20161128004156-6219dc7339ba // indirect
|
||||
github.com/projectcalico/go-yaml v0.0.0-20161201183616-955bc3e451ef // indirect
|
||||
github.com/projectcalico/go-yaml-wrapper v0.0.0-20161127220527-598e54215bee // indirect
|
||||
@@ -120,6 +121,7 @@ require (
|
||||
golang.org/x/tools v0.0.0-20190710153321-831012c29e42 // indirect
|
||||
google.golang.org/appengine v1.5.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7 // indirect
|
||||
google.golang.org/grpc v1.21.0
|
||||
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d // indirect
|
||||
gopkg.in/go-playground/assert.v1 v1.2.1 // indirect
|
||||
gopkg.in/go-playground/validator.v9 v9.29.1 // indirect
|
||||
@@ -141,6 +143,9 @@ require (
|
||||
k8s.io/klog v0.4.0
|
||||
k8s.io/kube-openapi v0.0.0-20181109181836-c59034cc13d5
|
||||
k8s.io/kubernetes v1.13.6
|
||||
kubesphere.io/im v0.1.0 // indirect
|
||||
openpitrix.io/iam v0.1.0 // indirect
|
||||
openpitrix.io/openpitrix v0.4.1-0.20190920134345-4d2be6e4965c
|
||||
sigs.k8s.io/application v0.0.0-20190404151855-67ae7f915d4e
|
||||
sigs.k8s.io/controller-runtime v0.1.10
|
||||
sigs.k8s.io/controller-tools v0.1.12
|
||||
@@ -161,6 +166,7 @@ replace (
|
||||
github.com/Azure/go-autorest/logger => github.com/Azure/go-autorest/logger v0.1.0
|
||||
github.com/Azure/go-autorest/tracing => github.com/Azure/go-autorest/tracing v0.1.0
|
||||
github.com/BurntSushi/toml => github.com/BurntSushi/toml v0.3.1
|
||||
github.com/Masterminds/semver => github.com/Masterminds/semver v1.5.0
|
||||
github.com/Microsoft/go-winio => github.com/Microsoft/go-winio v0.4.12
|
||||
github.com/NYTimes/gziphandler => github.com/NYTimes/gziphandler v1.1.1
|
||||
github.com/PuerkitoBio/goquery => github.com/PuerkitoBio/goquery v1.5.0
|
||||
@@ -168,6 +174,7 @@ replace (
|
||||
github.com/PuerkitoBio/urlesc => github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578
|
||||
github.com/Shopify/sarama => github.com/Shopify/sarama v1.19.0
|
||||
github.com/Shopify/toxiproxy => github.com/Shopify/toxiproxy v2.1.4+incompatible
|
||||
github.com/StackExchange/wmi => github.com/StackExchange/wmi v0.0.0-20170410192909-ea383cf3ba6e
|
||||
github.com/alcortesm/tgz => github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7
|
||||
github.com/alecthomas/template => github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc
|
||||
github.com/alecthomas/units => github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf
|
||||
@@ -180,7 +187,9 @@ replace (
|
||||
github.com/aws/aws-sdk-go => github.com/aws/aws-sdk-go v1.22.2
|
||||
github.com/beevik/etree => github.com/beevik/etree v1.1.0
|
||||
github.com/beorn7/perks => github.com/beorn7/perks v1.0.0
|
||||
github.com/bitly/go-simplejson => github.com/bitly/go-simplejson v0.5.0
|
||||
github.com/blang/semver => github.com/blang/semver v3.5.0+incompatible
|
||||
github.com/bmizerany/assert => github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869
|
||||
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.0
|
||||
github.com/cheekybits/genny => github.com/cheekybits/genny v1.0.0
|
||||
@@ -192,6 +201,7 @@ replace (
|
||||
github.com/coreos/pkg => github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f
|
||||
github.com/davecgh/go-spew => github.com/davecgh/go-spew v1.1.1
|
||||
github.com/deckarep/golang-set => github.com/deckarep/golang-set v1.7.1
|
||||
github.com/denisenkom/go-mssqldb => github.com/denisenkom/go-mssqldb v0.0.0-20190204142019-df6d76eb9289
|
||||
github.com/dgrijalva/jwt-go => github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
||||
github.com/docker/distribution => github.com/docker/distribution v2.7.1+incompatible
|
||||
github.com/docker/docker => github.com/docker/engine v1.4.2-0.20190822205725-ed20165a37b4
|
||||
@@ -212,21 +222,27 @@ replace (
|
||||
github.com/emicklei/go-restful-openapi => github.com/emicklei/go-restful-openapi v1.0.0
|
||||
github.com/emicklei/go-restful-swagger12 => github.com/emicklei/go-restful-swagger12 v0.0.0-20170926063155-7524189396c6
|
||||
github.com/emirpasic/gods => github.com/emirpasic/gods v1.12.0
|
||||
github.com/erikstmartin/go-testdb => github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5
|
||||
github.com/evanphx/json-patch => github.com/evanphx/json-patch v4.2.0+incompatible
|
||||
github.com/fatih/camelcase => github.com/fatih/camelcase v1.0.0
|
||||
github.com/fatih/structs => github.com/fatih/structs v1.1.0
|
||||
github.com/flynn/go-shlex => github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568
|
||||
github.com/fsnotify/fsnotify => github.com/fsnotify/fsnotify v1.4.7
|
||||
github.com/ghodss/yaml => github.com/ghodss/yaml v1.0.0
|
||||
github.com/gliderlabs/ssh => github.com/gliderlabs/ssh v0.1.1
|
||||
github.com/globalsign/mgo => github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb
|
||||
github.com/go-acme/lego => github.com/go-acme/lego v2.5.0+incompatible
|
||||
github.com/go-kit/kit => github.com/go-kit/kit v0.8.0
|
||||
github.com/go-ldap/ldap => github.com/go-ldap/ldap v3.0.3+incompatible
|
||||
github.com/go-logfmt/logfmt => github.com/go-logfmt/logfmt v0.3.0
|
||||
github.com/go-logr/logr => github.com/go-logr/logr v0.1.0
|
||||
github.com/go-logr/zapr => github.com/go-logr/zapr v0.1.1
|
||||
github.com/go-ole/go-ole => github.com/go-ole/go-ole v1.2.1
|
||||
github.com/go-openapi/errors => github.com/go-openapi/errors v0.17.0
|
||||
github.com/go-openapi/jsonpointer => github.com/go-openapi/jsonpointer v0.19.0
|
||||
github.com/go-openapi/jsonreference => github.com/go-openapi/jsonreference v0.19.0
|
||||
github.com/go-openapi/spec => github.com/go-openapi/spec v0.19.0
|
||||
github.com/go-openapi/strfmt => github.com/go-openapi/strfmt v0.19.0
|
||||
github.com/go-openapi/swag => github.com/go-openapi/swag v0.19.0
|
||||
github.com/go-playground/locales => github.com/go-playground/locales v0.12.1
|
||||
github.com/go-playground/universal-translator => github.com/go-playground/universal-translator v0.16.0
|
||||
@@ -235,6 +251,7 @@ replace (
|
||||
github.com/go-stack/stack => github.com/go-stack/stack v1.8.0
|
||||
github.com/gobuffalo/flect => github.com/gobuffalo/flect v0.1.5
|
||||
github.com/gocraft/dbr => github.com/gocraft/dbr v0.0.0-20180507214907-a0fd650918f6
|
||||
github.com/gofrs/uuid => github.com/gofrs/uuid v3.2.0+incompatible
|
||||
github.com/gogo/protobuf => github.com/gogo/protobuf v1.2.0
|
||||
github.com/golang/example => github.com/golang/example v0.0.0-20170904185048-46695d81d1fa
|
||||
github.com/golang/glog => github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b
|
||||
@@ -246,6 +263,7 @@ replace (
|
||||
github.com/google/go-cmp => github.com/google/go-cmp v0.2.0
|
||||
github.com/google/go-querystring => github.com/google/go-querystring v1.0.0
|
||||
github.com/google/gofuzz => github.com/google/gofuzz v1.0.0
|
||||
github.com/google/gops => github.com/google/gops v0.3.6
|
||||
github.com/google/uuid => github.com/google/uuid v1.1.1
|
||||
github.com/googleapis/gnostic => github.com/googleapis/gnostic v0.2.0
|
||||
github.com/gophercloud/gophercloud => github.com/gophercloud/gophercloud v0.3.0
|
||||
@@ -267,15 +285,21 @@ 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/jimstudt/http-authentication => github.com/jimstudt/http-authentication v0.0.0-20140401203705-3eca13d6893a
|
||||
github.com/jinzhu/gorm => github.com/jinzhu/gorm v1.9.2
|
||||
github.com/jinzhu/inflection => github.com/jinzhu/inflection v0.0.0-20180308033659-04140366298a
|
||||
github.com/jinzhu/now => github.com/jinzhu/now v1.0.0
|
||||
github.com/jmespath/go-jmespath => github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af
|
||||
github.com/jonboulle/clockwork => github.com/jonboulle/clockwork v0.1.0
|
||||
github.com/json-iterator/go => github.com/json-iterator/go v1.1.6
|
||||
github.com/julienschmidt/httprouter => github.com/julienschmidt/httprouter v1.2.0
|
||||
github.com/kardianos/osext => github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1
|
||||
github.com/kelseyhightower/envconfig => github.com/kelseyhightower/envconfig v1.4.0
|
||||
github.com/kevinburke/ssh_config => github.com/kevinburke/ssh_config v0.0.0-20180830205328-81db2a75821e
|
||||
github.com/keybase/go-ps => github.com/keybase/go-ps v0.0.0-20161005175911-668c8856d999
|
||||
github.com/kiali/kiali => github.com/kubesphere/kiali v0.15.1-0.20190407071308-6b5b818211c3
|
||||
github.com/klauspost/cpuid => github.com/klauspost/cpuid v1.2.1
|
||||
github.com/knative/pkg => github.com/knative/pkg v0.0.0-20190314204845-cd278f2d3394
|
||||
github.com/koding/multiconfig => github.com/koding/multiconfig v0.0.0-20171124222453-69c27309b2d7
|
||||
github.com/konsorten/go-windows-terminal-sequences => github.com/konsorten/go-windows-terminal-sequences v1.0.2
|
||||
github.com/kr/logfmt => github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515
|
||||
github.com/kr/pretty => github.com/kr/pretty v0.1.0
|
||||
@@ -331,6 +355,8 @@ replace (
|
||||
github.com/russross/blackfriday => github.com/russross/blackfriday v1.5.2
|
||||
github.com/satori/go.uuid => github.com/satori/go.uuid v1.2.0
|
||||
github.com/sergi/go-diff => github.com/sergi/go-diff v1.0.0
|
||||
github.com/shirou/gopsutil => github.com/shirou/gopsutil v0.0.0-20180427012116-c95755e4bcd7
|
||||
github.com/shirou/w32 => github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4
|
||||
github.com/sirupsen/logrus => github.com/sirupsen/logrus v1.2.0
|
||||
github.com/soheilhy/cmux => github.com/soheilhy/cmux v0.1.4
|
||||
github.com/sony/sonyflake => github.com/sony/sonyflake v0.0.0-20181109022403-6d5bd6181009
|
||||
@@ -344,14 +370,12 @@ replace (
|
||||
github.com/src-d/gcfg => github.com/src-d/gcfg v1.4.0
|
||||
github.com/stretchr/objx => github.com/stretchr/objx v0.1.1
|
||||
github.com/stretchr/testify => github.com/stretchr/testify v1.3.0
|
||||
github.com/tidwall/gjson => github.com/tidwall/gjson v1.3.2
|
||||
github.com/tidwall/match => github.com/tidwall/match v1.0.1
|
||||
github.com/tidwall/pretty => github.com/tidwall/pretty v1.0.0
|
||||
github.com/tidwall/sjson => github.com/tidwall/sjson v1.0.4
|
||||
github.com/tmc/grpc-websocket-proxy => github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5
|
||||
github.com/ugorji/go => github.com/ugorji/go v1.1.4
|
||||
github.com/urfave/cli => github.com/urfave/cli v1.20.0
|
||||
github.com/xanzy/ssh-agent => github.com/xanzy/ssh-agent v0.2.1
|
||||
github.com/xiang90/probing => github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2
|
||||
github.com/xlab/treeprint => github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6
|
||||
github.com/xordataexchange/crypt => github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77
|
||||
go.etcd.io/bbolt => go.etcd.io/bbolt v1.3.3
|
||||
go.opencensus.io => go.opencensus.io v0.20.2
|
||||
@@ -404,6 +428,11 @@ replace (
|
||||
k8s.io/kube-openapi => k8s.io/kube-openapi v0.0.0-20181109181836-c59034cc13d5
|
||||
k8s.io/kubernetes => k8s.io/kubernetes v1.13.6
|
||||
k8s.io/utils => k8s.io/utils v0.0.0-20190506122338-8fab8cb257d5
|
||||
kubesphere.io/im => kubesphere.io/im v0.1.0
|
||||
openpitrix.io/iam => openpitrix.io/iam v0.1.0
|
||||
openpitrix.io/logger v0.1.0 => github.com/openpitrix/logger v0.1.0
|
||||
openpitrix.io/openpitrix => openpitrix.io/openpitrix v0.4.1-0.20190920134345-4d2be6e4965c
|
||||
rsc.io/goversion => rsc.io/goversion v1.0.0
|
||||
sigs.k8s.io/application => sigs.k8s.io/application v0.0.0-20190404151855-67ae7f915d4e
|
||||
sigs.k8s.io/controller-runtime => sigs.k8s.io/controller-runtime v0.1.10
|
||||
sigs.k8s.io/controller-tools => sigs.k8s.io/controller-tools v0.1.12
|
||||
|
||||
40
go.sum
40
go.sum
@@ -22,6 +22,8 @@ github.com/Azure/go-autorest/tracing v0.1.0 h1:TRBxC5Pj/fIuh4Qob0ZpkggbfT8RC0Sub
|
||||
github.com/Azure/go-autorest/tracing v0.1.0/go.mod h1:ROEEAFwXycQw7Sn3DXNtEedEvdeRAgDr0izn4z5Ij88=
|
||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
|
||||
github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
|
||||
github.com/Microsoft/go-winio v0.4.12 h1:xAfWHN1IrQ0NJ9TBC0KBZoqLjzDTr1ML+4MywiUOryc=
|
||||
github.com/Microsoft/go-winio v0.4.12/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
|
||||
github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I=
|
||||
@@ -34,6 +36,7 @@ github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
||||
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
||||
github.com/StackExchange/wmi v0.0.0-20170410192909-ea383cf3ba6e/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
|
||||
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-20160405071501-a0175ee3bccc h1:cAKDfWh5VpdgMhJosfJnn5/FoN2SRZ4p7fJNX58YPaU=
|
||||
@@ -56,7 +59,11 @@ github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs=
|
||||
github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A=
|
||||
github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/bitly/go-simplejson v0.5.0 h1:6IH+V8/tVMab511d5bn4M7EwGXZf9Hj6i2xSwkNEM+Y=
|
||||
github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA=
|
||||
github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
|
||||
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY=
|
||||
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
|
||||
github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=
|
||||
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.0 h1:LzQXZOgg4CQfE6bFvXGM30YZL1WW/M337pXml+GrcZ4=
|
||||
@@ -78,6 +85,7 @@ 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/deckarep/golang-set v1.7.1 h1:SCQV0S6gTtp6itiFrTqI+pfmJ4LN85S1YzhDf9rTHJQ=
|
||||
github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20190204142019-df6d76eb9289/go.mod h1:xN/JuLBIz4bjkxNmByTiV1IbhfnYb6oo99phBn4Eqhc=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug=
|
||||
@@ -115,8 +123,11 @@ github.com/emicklei/go-restful-swagger12 v0.0.0-20170926063155-7524189396c6 h1:V
|
||||
github.com/emicklei/go-restful-swagger12 v0.0.0-20170926063155-7524189396c6/go.mod h1:qr0VowGBT4CS4Q8vFF8BSeKz34PuqKGxs/L0IAQA9DQ=
|
||||
github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg=
|
||||
github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
|
||||
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0=
|
||||
github.com/evanphx/json-patch v4.2.0+incompatible h1:fUDGZCv/7iAN7u0puUVhvKCcsR6vRfwrJatElLBEf0I=
|
||||
github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||
github.com/fatih/camelcase v1.0.0 h1:hxNvNX/xYBp0ovncs8WyWZrOrpBNub/JfaMvbURyft8=
|
||||
github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc=
|
||||
github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
|
||||
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ=
|
||||
@@ -127,6 +138,8 @@ 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/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb h1:D4uzjWwKYQ5XnAvUbuvHW93esHg7F8N/OYeBBcJoTr0=
|
||||
github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
|
||||
github.com/go-acme/lego v2.5.0+incompatible h1:5fNN9yRQfv8ymH3DSsxla+4aYeQt2IgfZqHKVnK8f0s=
|
||||
github.com/go-acme/lego v2.5.0+incompatible/go.mod h1:yzMNe9CasVUhkquNvti5nAtPmG94USbYxYrZfTkIn0M=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
@@ -137,12 +150,17 @@ github.com/go-logr/logr v0.1.0 h1:M1Tv3VzNlEHg6uyACnRdtrploV2P7wZqH8BoQMtz0cg=
|
||||
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
|
||||
github.com/go-logr/zapr v0.1.1 h1:qXBXPDdNncunGs7XeEpsJt8wCjYBygluzfdLO0G5baE=
|
||||
github.com/go-logr/zapr v0.1.1/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk=
|
||||
github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8=
|
||||
github.com/go-openapi/errors v0.17.0 h1:g5DzIh94VpuR/dd6Ff8KqyHNnw7yBa2xSHIPPzjRDUo=
|
||||
github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
|
||||
github.com/go-openapi/jsonpointer v0.19.0 h1:FTUMcX77w5rQkClIzDtTxvn6Bsa894CcrzNj2MMfeg8=
|
||||
github.com/go-openapi/jsonpointer v0.19.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
|
||||
github.com/go-openapi/jsonreference v0.19.0 h1:BqWKpV1dFd+AuiKlgtddwVIFQsuMpxfBDBHGfM2yNpk=
|
||||
github.com/go-openapi/jsonreference v0.19.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
|
||||
github.com/go-openapi/spec v0.19.0 h1:A4SZ6IWh3lnjH0rG0Z5lkxazMGBECtrZcbyYQi+64k4=
|
||||
github.com/go-openapi/spec v0.19.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
|
||||
github.com/go-openapi/strfmt v0.19.0 h1:0Dn9qy1G9+UJfRU7TR8bmdGxb4uifB7HNrJjOnV0yPk=
|
||||
github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY=
|
||||
github.com/go-openapi/swag v0.19.0 h1:Kg7Wl7LkTPlmc393QZQ/5rQadPhi7pBVEMZxyTi0Ii8=
|
||||
github.com/go-openapi/swag v0.19.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
|
||||
github.com/go-playground/locales v0.12.1 h1:2FITxuFt/xuCNP1Acdhv62OzaCiviiE4kotfhkmOqEc=
|
||||
@@ -153,11 +171,13 @@ github.com/go-redis/redis v6.15.2+incompatible h1:9SpNVG76gr6InJGxoZ6IuuxaCOQwDA
|
||||
github.com/go-redis/redis v6.15.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
|
||||
github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA=
|
||||
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
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/flect v0.1.5 h1:xpKq9ap8MbYfhuPCF0dBH854Gp9CxZjr/IocxELFflo=
|
||||
github.com/gobuffalo/flect v0.1.5/go.mod h1:W3K3X9ksuZfir8f/LrfVtWmCDQFfayuylOJ7sz/Fj80=
|
||||
github.com/gocraft/dbr v0.0.0-20180507214907-a0fd650918f6 h1:kumyNm8Vr8cbVm/aLQYTbDE3SKCbbn5HEVoDp/Dyyfc=
|
||||
github.com/gocraft/dbr v0.0.0-20180507214907-a0fd650918f6/go.mod h1:K/9g3pPouf13kP5K7pdriQEJAy272R9yXuWuDIEWJTM=
|
||||
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/gogo/protobuf v1.2.0 h1:xU6/SpYbvkNYiptHJYEDRseDLvYE7wSqhYYNy0QSUzI=
|
||||
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/golang/example v0.0.0-20170904185048-46695d81d1fa h1:iqCQC2Z53KkwGgTN9szyL4q0OQHmuNjeoNnMT6lk66k=
|
||||
@@ -179,6 +199,7 @@ github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASu
|
||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||
github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/gops v0.3.6/go.mod h1:RZ1rH95wsAGX4vMWKmqBOIWynmWisBf4QFdgT/k/xOI=
|
||||
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/googleapis/gnostic v0.2.0 h1:l6N3VoaVzTncYYW+9yOz2LJJammFZGBO13sqgEhpy9g=
|
||||
@@ -219,6 +240,9 @@ 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/jimstudt/http-authentication v0.0.0-20140401203705-3eca13d6893a h1:BcF8coBl0QFVhe8vAMMlD+CV8EISiu9MGKLoj6ZEyJA=
|
||||
github.com/jimstudt/http-authentication v0.0.0-20140401203705-3eca13d6893a/go.mod h1:wK6yTYYcgjHE1Z1QtXACPDjcFJyBskHEdagmnq3vsP8=
|
||||
github.com/jinzhu/gorm v1.9.2/go.mod h1:Vla75njaFJ8clLU1W44h34PjIkijhjHIYnZxMqCdxqo=
|
||||
github.com/jinzhu/inflection v0.0.0-20180308033659-04140366298a/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||
github.com/jinzhu/now v1.0.0/go.mod h1:oHTiXerJ20+SfYcrdlBO7rzZRJWGwSTQ0iUY2jI6Gfc=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo=
|
||||
@@ -226,14 +250,18 @@ github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22
|
||||
github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
|
||||
github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8=
|
||||
github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg=
|
||||
github.com/kevinburke/ssh_config v0.0.0-20180830205328-81db2a75821e h1:RgQk53JHp/Cjunrr1WlsXSZpqXn+uREuHvUVcK82CV8=
|
||||
github.com/kevinburke/ssh_config v0.0.0-20180830205328-81db2a75821e/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||
github.com/keybase/go-ps v0.0.0-20161005175911-668c8856d999/go.mod h1:hY+WOq6m2FpbvyrI93sMaypsttvaIL5nhVR92dTMUcQ=
|
||||
github.com/klauspost/cpuid v1.2.1 h1:vJi+O/nMdFt0vqm8NZBI6wzALWdA2X+egi0ogNyrC/w=
|
||||
github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
github.com/knative/pkg v0.0.0-20190314204845-cd278f2d3394 h1:Lg2DviikLeZmY0rnPpVLMC77h7vqZG5mjh33apZl76o=
|
||||
github.com/knative/pkg v0.0.0-20190314204845-cd278f2d3394/go.mod h1:7Ijfhw7rfB+H9VtosIsDYvZQ+qYTz7auK3fHW/5z4ww=
|
||||
github.com/koding/multiconfig v0.0.0-20171124222453-69c27309b2d7 h1:SWlt7BoQNASbhTUD0Oy5yysI2seJ7vWuGUp///OM4TM=
|
||||
github.com/koding/multiconfig v0.0.0-20171124222453-69c27309b2d7/go.mod h1:Y2SaZf2Rzd0pXkLVhLlCiAXFCLSXAIbTKDivVgff/AM=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
@@ -297,6 +325,7 @@ github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2i
|
||||
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
||||
github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI=
|
||||
github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
|
||||
github.com/openpitrix/logger v0.1.0/go.mod h1:SV8Btt2cTSmeL9H/1XCkYmQ+WQ2upVY4e0wlr07RP28=
|
||||
github.com/openshift/api v3.9.0+incompatible h1:fJ/KsefYuZAjmrr3+5U9yZIZbTOpVkDDLDLFresAeYs=
|
||||
github.com/openshift/api v3.9.0+incompatible/go.mod h1:dh9o4Fs58gpFXGSYfnVxGR9PnV53I8TW84pQaJDdGiY=
|
||||
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
|
||||
@@ -338,6 +367,8 @@ github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
|
||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
github.com/shirou/gopsutil v0.0.0-20180427012116-c95755e4bcd7/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
||||
github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc=
|
||||
github.com/sirupsen/logrus v1.2.0 h1:juTguoYk5qI21pwyTXY3B3Y5cOTH3ZUyZCg1v/mihuo=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/soheilhy/cmux v0.1.4 h1:0HKaf1o97UwFjHH9o5XsHUOF+tqmdA7KEzXLpiyaw0E=
|
||||
@@ -367,10 +398,12 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5 h1:LnC5Kc/wtumK+WB441p7ynQJzVuNRJiqddSIE3IlSEQ=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
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/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70=
|
||||
github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=
|
||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
go.etcd.io/bbolt v1.3.3 h1:MUGmc65QhB3pIlaQ5bB4LwqSj6GIonVJXpZiaKNyaKk=
|
||||
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
@@ -470,6 +503,13 @@ k8s.io/kubernetes v1.13.6 h1:eUAUryzMLFmi4ZY8kMOUtLG5lHp2PUx5WOmy4RVaobk=
|
||||
k8s.io/kubernetes v1.13.6/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk=
|
||||
k8s.io/utils v0.0.0-20190506122338-8fab8cb257d5 h1:VBM/0P5TWxwk+Nw6Z+lAw3DKgO76g90ETOiA6rfLV1Y=
|
||||
k8s.io/utils v0.0.0-20190506122338-8fab8cb257d5/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
|
||||
kubesphere.io/im v0.1.0 h1:Isu/WBOawUb4fzSlQeD1f6Vbq9pqFS0PmDg8v8iFYaY=
|
||||
kubesphere.io/im v0.1.0/go.mod h1:DHJj/JngMUFyaXecLjBPXj/zk5Oi7ifIixLRp0qJkyA=
|
||||
openpitrix.io/iam v0.1.0 h1:cb1mCusim7EGeoXEfuaVa1m7Co/pzim3keoxxKdv944=
|
||||
openpitrix.io/iam v0.1.0/go.mod h1:EcZE8CPBg+1fEKCDEhpsIZ8isWWO7javpu84mSqoVn4=
|
||||
openpitrix.io/openpitrix v0.4.1-0.20190920134345-4d2be6e4965c h1:r/wQNNzFE0Blbf42Dl8pRNSRc+YiYdgOclNcP3VMeTs=
|
||||
openpitrix.io/openpitrix v0.4.1-0.20190920134345-4d2be6e4965c/go.mod h1:8rZSFeUp2Np5kfKAXfRL/1HSh6BYywNCALt+ZnxFQ/4=
|
||||
rsc.io/goversion v1.0.0/go.mod h1:Eih9y/uIBS3ulggl7KNJ09xGSLcuNaLgmvvqa07sgfo=
|
||||
sigs.k8s.io/application v0.0.0-20190404151855-67ae7f915d4e h1:/TWUhUxC+Q5uMFUizxYzNAZjwbjlYXOsfnmSC2WpyuI=
|
||||
sigs.k8s.io/application v0.0.0-20190404151855-67ae7f915d4e/go.mod h1:9C86g0wiFn8jtZjgJepSx188uJeWLGWTbcCycu5p8mU=
|
||||
sigs.k8s.io/controller-runtime v0.1.10 h1:amLOmcekVdnsD1uIpmgRqfTbQWJ2qxvQkcdeFhcotn4=
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
Copyright 2019 The KubeSphere authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -14,11 +14,5 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// +k8s:deepcopy-gen=package
|
||||
|
||||
// Package api contains the latest (or "internal") version of the
|
||||
// Kubernetes API objects. This is the API objects as represented in memory.
|
||||
// The contract presented to clients is located in the versioned packages,
|
||||
// which are sub-directories. The first one is "v1". Those packages
|
||||
// describe how a particular version is serialized to storage/network.
|
||||
package core // import "k8s.io/kubernetes/pkg/apis/core"
|
||||
// Package operations contains operations API versions
|
||||
package openpitrix
|
||||
33
pkg/apis/openpitrix/install/install.go
Normal file
33
pkg/apis/openpitrix/install/install.go
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 The KubeSphere Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
package install
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
urlruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
openpitrixv1 "kubesphere.io/kubesphere/pkg/apis/openpitrix/v1"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Install(runtime.Container)
|
||||
}
|
||||
|
||||
func Install(container *restful.Container) {
|
||||
urlruntime.Must(openpitrixv1.AddToContainer(container))
|
||||
}
|
||||
346
pkg/apis/openpitrix/v1/register.go
Normal file
346
pkg/apis/openpitrix/v1/register.go
Normal file
@@ -0,0 +1,346 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2019 The KubeSphere Authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* /
|
||||
*/
|
||||
package v1
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"github.com/emicklei/go-restful-openapi"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/openpitrix"
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
opmodels "kubesphere.io/kubesphere/pkg/models/openpitrix"
|
||||
"kubesphere.io/kubesphere/pkg/server/errors"
|
||||
"kubesphere.io/kubesphere/pkg/server/params"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
const GroupName = "openpitrix.io"
|
||||
|
||||
var GroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1"}
|
||||
|
||||
var (
|
||||
WebServiceBuilder = runtime.NewContainerBuilder(addWebService)
|
||||
AddToContainer = WebServiceBuilder.AddToContainer
|
||||
)
|
||||
|
||||
func addWebService(c *restful.Container) error {
|
||||
|
||||
ok := "ok"
|
||||
mimePatch := []string{restful.MIME_JSON, runtime.MimeMergePatchJson, runtime.MimeJsonPatchJson}
|
||||
webservice := runtime.NewWebService(GroupVersion)
|
||||
|
||||
webservice.Route(webservice.GET("/applications").
|
||||
To(openpitrix.ListApplications).
|
||||
Returns(http.StatusOK, ok, models.PageableResponse{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.NamespaceResourcesTag}).
|
||||
Doc("List all applications").
|
||||
Param(webservice.QueryParameter(params.ConditionsParam, "query conditions, connect multiple conditions with commas, equal symbol for exact query, wave symbol for fuzzy query e.g. name~a").
|
||||
Required(false).
|
||||
DataFormat("key=value,key~value").
|
||||
DefaultValue("")).
|
||||
Param(webservice.PathParameter("namespace", "the name of the project")).
|
||||
Param(webservice.QueryParameter(params.PagingParam, "paging query, e.g. limit=100,page=1").
|
||||
Required(false).
|
||||
DataFormat("limit=%d,page=%d").
|
||||
DefaultValue("limit=10,page=1")))
|
||||
|
||||
webservice.Route(webservice.GET("/namespaces/{namespace}/applications").
|
||||
To(openpitrix.ListApplications).
|
||||
Returns(http.StatusOK, ok, models.PageableResponse{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.NamespaceResourcesTag}).
|
||||
Doc("List all applications within the specified namespace").
|
||||
Param(webservice.QueryParameter(params.ConditionsParam, "query conditions, connect multiple conditions with commas, equal symbol for exact query, wave symbol for fuzzy query e.g. name~a").
|
||||
Required(false).
|
||||
DataFormat("key=value,key~value").
|
||||
DefaultValue("")).
|
||||
Param(webservice.PathParameter("namespace", "the name of the project")).
|
||||
Param(webservice.QueryParameter(params.PagingParam, "paging query, e.g. limit=100,page=1").
|
||||
Required(false).
|
||||
DataFormat("limit=%d,page=%d").
|
||||
DefaultValue("limit=10,page=1")))
|
||||
|
||||
webservice.Route(webservice.GET("/namespaces/{namespace}/applications/{application}").
|
||||
To(openpitrix.DescribeApplication).
|
||||
Returns(http.StatusOK, ok, opmodels.Application{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.NamespaceResourcesTag}).
|
||||
Doc("Describe the specified application of the namespace").
|
||||
Param(webservice.PathParameter("namespace", "the name of the project")).
|
||||
Param(webservice.PathParameter("application", "application ID")))
|
||||
|
||||
webservice.Route(webservice.POST("/namespaces/{namespace}/applications").
|
||||
To(openpitrix.CreateApplication).
|
||||
Doc("Deploy a new application").
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.NamespaceResourcesTag}).
|
||||
Reads(opmodels.CreateClusterRequest{}).
|
||||
Returns(http.StatusOK, ok, errors.Error{}).
|
||||
Param(webservice.PathParameter("namespace", "the name of the project")))
|
||||
|
||||
webservice.Route(webservice.PATCH("/namespaces/{namespace}/applications/{application}").
|
||||
Consumes(mimePatch...).
|
||||
To(openpitrix.ModifyApplication).
|
||||
Doc("Modify application").
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.NamespaceResourcesTag}).
|
||||
Reads(opmodels.ModifyClusterAttributesRequest{}).
|
||||
Returns(http.StatusOK, ok, errors.Error{}).
|
||||
Param(webservice.PathParameter("namespace", "the name of the project")).
|
||||
Param(webservice.PathParameter("application", "the id of the application cluster")))
|
||||
|
||||
webservice.Route(webservice.DELETE("/namespaces/{namespace}/applications/{application}").
|
||||
To(openpitrix.DeleteApplication).
|
||||
Doc("Delete the specified application").
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.NamespaceResourcesTag}).
|
||||
Returns(http.StatusOK, ok, errors.Error{}).
|
||||
Param(webservice.PathParameter("namespace", "the name of the project")).
|
||||
Param(webservice.PathParameter("application", "the id of the application cluster")))
|
||||
|
||||
webservice.Route(webservice.POST("/apps/{app}/versions").
|
||||
To(openpitrix.CreateAppVersion).
|
||||
Doc("Create a new app template version").
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}).
|
||||
Reads(opmodels.CreateAppVersionRequest{}).
|
||||
Param(webservice.QueryParameter("validate", "Validate format of package(pack by op tool)")).
|
||||
Returns(http.StatusOK, ok, opmodels.CreateAppVersionResponse{}).
|
||||
Param(webservice.PathParameter("app", "app template id")))
|
||||
webservice.Route(webservice.DELETE("/apps/{app}/versions/{version}").
|
||||
To(openpitrix.DeleteAppVersion).
|
||||
Doc("Delete the specified app template version").
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}).
|
||||
Returns(http.StatusOK, ok, errors.Error{}).
|
||||
Param(webservice.PathParameter("version", "app template version id")).
|
||||
Param(webservice.PathParameter("app", "app template id")))
|
||||
webservice.Route(webservice.PATCH("/apps/{app}/versions/{version}").
|
||||
Consumes(mimePatch...).
|
||||
To(openpitrix.ModifyAppVersion).
|
||||
Doc("Patch the specified app template version").
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}).
|
||||
Reads(opmodels.ModifyAppVersionRequest{}).
|
||||
Returns(http.StatusOK, ok, errors.Error{}).
|
||||
Param(webservice.PathParameter("version", "app template version id")).
|
||||
Param(webservice.PathParameter("app", "app template id")))
|
||||
webservice.Route(webservice.GET("/apps/{app}/versions/{version}").
|
||||
To(openpitrix.DescribeAppVersion).
|
||||
Doc("Describe the specified app template version").
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}).
|
||||
Returns(http.StatusOK, ok, opmodels.AppVersion{}).
|
||||
Param(webservice.PathParameter("version", "app template version id")).
|
||||
Param(webservice.PathParameter("app", "app template id")))
|
||||
webservice.Route(webservice.GET("/apps/{app}/versions").
|
||||
To(openpitrix.ListAppVersions).
|
||||
Doc("Get active versions of app, can filter with these fields(version_id, app_id, name, owner, description, package_name, status, type), default return all active app versions").
|
||||
Param(webservice.QueryParameter(params.ConditionsParam, "query conditions,connect multiple conditions with commas, equal symbol for exact query, wave symbol for fuzzy query e.g. name~a").
|
||||
Required(false).
|
||||
DataFormat("key=%s,key~%s")).
|
||||
Param(webservice.QueryParameter(params.PagingParam, "paging query, e.g. limit=100,page=1").
|
||||
Required(false).
|
||||
DataFormat("limit=%d,page=%d").
|
||||
DefaultValue("limit=10,page=1")).
|
||||
Param(webservice.PathParameter("app", "app template id")).
|
||||
Param(webservice.QueryParameter(params.ReverseParam, "sort parameters, e.g. reverse=true")).
|
||||
Param(webservice.QueryParameter(params.OrderByParam, "sort parameters, e.g. orderBy=createTime")).
|
||||
Returns(http.StatusOK, ok, models.PageableResponse{}))
|
||||
webservice.Route(webservice.GET("/apps/{app}/versions/{version}/audits").
|
||||
To(openpitrix.ListAppVersionAudits).
|
||||
Doc("List audits information of version-specific app template").
|
||||
Returns(http.StatusOK, ok, opmodels.AppVersionAudit{}).
|
||||
Param(webservice.PathParameter("version", "app template version id")).
|
||||
Param(webservice.PathParameter("app", "app template id")))
|
||||
webservice.Route(webservice.GET("/apps/{app}/versions/{version}/package").
|
||||
To(openpitrix.GetAppVersionPackage).
|
||||
Doc("Get packages of version-specific app").
|
||||
Returns(http.StatusOK, ok, opmodels.GetAppVersionPackageResponse{}).
|
||||
Param(webservice.PathParameter("version", "app template version id")).
|
||||
Param(webservice.PathParameter("app", "app template id")))
|
||||
webservice.Route(webservice.POST("/apps/{app}/versions/{version}/action").
|
||||
To(openpitrix.DoAppVersionAction).
|
||||
Doc("Perform submit or other operations on app").
|
||||
Returns(http.StatusOK, ok, errors.Error{}).
|
||||
Param(webservice.PathParameter("version", "app template version id")).
|
||||
Param(webservice.PathParameter("app", "app template id")))
|
||||
webservice.Route(webservice.GET("/apps/{app}/versions/{version}/files").
|
||||
To(openpitrix.GetAppVersionFiles).
|
||||
Doc("Get app template package files").
|
||||
Returns(http.StatusOK, ok, opmodels.GetAppVersionPackageFilesResponse{}).
|
||||
Param(webservice.PathParameter("version", "app template version id")).
|
||||
Param(webservice.PathParameter("app", "app template id")))
|
||||
webservice.Route(webservice.GET("/reviews").
|
||||
To(openpitrix.ListReviews).
|
||||
Doc("Get reviews of version-specific app").
|
||||
Param(webservice.QueryParameter(params.ConditionsParam, "query conditions,connect multiple conditions with commas, equal symbol for exact query, wave symbol for fuzzy query e.g. name~a").
|
||||
Required(false).
|
||||
DataFormat("key=%s,key~%s")).
|
||||
Param(webservice.QueryParameter(params.PagingParam, "paging query, e.g. limit=100,page=1").
|
||||
Required(false).
|
||||
DataFormat("limit=%d,page=%d").
|
||||
DefaultValue("limit=10,page=1")).
|
||||
Returns(http.StatusOK, ok, opmodels.AppVersionReview{}))
|
||||
webservice.Route(webservice.GET("/apps/{app}/audits").
|
||||
To(openpitrix.ListAppVersionAudits).
|
||||
Doc("List audits information of the specific app template").
|
||||
Param(webservice.PathParameter("app", "app template id")).
|
||||
Returns(http.StatusOK, ok, opmodels.AppVersionAudit{}))
|
||||
webservice.Route(webservice.POST("/apps").
|
||||
To(openpitrix.CreateApp).
|
||||
Doc("Create a new app template").
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}).
|
||||
Returns(http.StatusOK, ok, opmodels.CreateAppResponse{}).
|
||||
Reads(opmodels.CreateAppRequest{}).
|
||||
Param(webservice.PathParameter("app", "app template id")))
|
||||
webservice.Route(webservice.DELETE("/apps/{app}").
|
||||
To(openpitrix.DeleteApp).
|
||||
Doc("Delete the specified app template").
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}).
|
||||
Returns(http.StatusOK, ok, errors.Error{}).
|
||||
Param(webservice.PathParameter("app", "app template id")))
|
||||
webservice.Route(webservice.PATCH("/apps/{app}").
|
||||
Consumes(mimePatch...).
|
||||
To(openpitrix.ModifyApp).
|
||||
Doc("Patch the specified app template").
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}).
|
||||
Reads(opmodels.ModifyAppVersionRequest{}).
|
||||
Returns(http.StatusOK, ok, errors.Error{}).
|
||||
Param(webservice.PathParameter("app", "app template id")))
|
||||
webservice.Route(webservice.GET("/apps/{app}").
|
||||
To(openpitrix.DescribeApp).
|
||||
Doc("Describe the specified app template").
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}).
|
||||
Returns(http.StatusOK, ok, opmodels.AppVersion{}).
|
||||
Param(webservice.PathParameter("app", "app template id")))
|
||||
webservice.Route(webservice.POST("/apps/{app}/action").
|
||||
To(openpitrix.DoAppAction).
|
||||
Doc("Perform recover or suspend operation on app").
|
||||
Returns(http.StatusOK, ok, errors.Error{}).
|
||||
Param(webservice.PathParameter("version", "app template version id")).
|
||||
Param(webservice.PathParameter("app", "app template id")))
|
||||
webservice.Route(webservice.GET("/apps").
|
||||
To(openpitrix.ListApps).
|
||||
Doc("List app templates").
|
||||
Param(webservice.QueryParameter(params.ConditionsParam, "query conditions,connect multiple conditions with commas, equal symbol for exact query, wave symbol for fuzzy query e.g. name~a").
|
||||
Required(false).
|
||||
DataFormat("key=%s,key~%s")).
|
||||
Param(webservice.QueryParameter(params.PagingParam, "paging query, e.g. limit=100,page=1").
|
||||
Required(false).
|
||||
DataFormat("limit=%d,page=%d").
|
||||
DefaultValue("limit=10,page=1")).
|
||||
Param(webservice.QueryParameter(params.ReverseParam, "sort parameters, e.g. reverse=true")).
|
||||
Param(webservice.QueryParameter(params.OrderByParam, "sort parameters, e.g. orderBy=createTime")).
|
||||
Returns(http.StatusOK, ok, models.PageableResponse{}))
|
||||
webservice.Route(webservice.POST("/categories").
|
||||
To(openpitrix.CreateCategory).
|
||||
Doc("Create app template category").
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}).
|
||||
Reads(opmodels.CreateCategoryRequest{}).
|
||||
Returns(http.StatusOK, ok, opmodels.CreateCategoryResponse{}).
|
||||
Param(webservice.PathParameter("app", "app template id")))
|
||||
webservice.Route(webservice.DELETE("/categories/{category}").
|
||||
To(openpitrix.DeleteCategory).
|
||||
Doc("Delete the specified category").
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}).
|
||||
Returns(http.StatusOK, ok, errors.Error{}).
|
||||
Param(webservice.PathParameter("category", "category id")))
|
||||
webservice.Route(webservice.PATCH("/categories/{category}").
|
||||
Consumes(mimePatch...).
|
||||
To(openpitrix.ModifyCategory).
|
||||
Doc("Patch the specified category").
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}).
|
||||
Reads(opmodels.ModifyCategoryRequest{}).
|
||||
Returns(http.StatusOK, ok, errors.Error{}).
|
||||
Param(webservice.PathParameter("category", "category id")))
|
||||
webservice.Route(webservice.GET("/categories/{category}").
|
||||
To(openpitrix.DescribeCategory).
|
||||
Doc("Describe the specified category").
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}).
|
||||
Returns(http.StatusOK, ok, opmodels.Category{}).
|
||||
Param(webservice.PathParameter("category", "category id")))
|
||||
webservice.Route(webservice.GET("/categories").
|
||||
To(openpitrix.ListCategories).
|
||||
Doc("List categories").
|
||||
Param(webservice.QueryParameter(params.ConditionsParam, "query conditions,connect multiple conditions with commas, equal symbol for exact query, wave symbol for fuzzy query e.g. name~a").
|
||||
Required(false).
|
||||
DataFormat("key=%s,key~%s")).
|
||||
Param(webservice.QueryParameter(params.PagingParam, "paging query, e.g. limit=100,page=1").
|
||||
Required(false).
|
||||
DataFormat("limit=%d,page=%d").
|
||||
DefaultValue("limit=10,page=1")).
|
||||
Param(webservice.QueryParameter(params.ReverseParam, "sort parameters, e.g. reverse=true")).
|
||||
Param(webservice.QueryParameter(params.OrderByParam, "sort parameters, e.g. orderBy=createTime")).
|
||||
Returns(http.StatusOK, ok, models.PageableResponse{}))
|
||||
|
||||
webservice.Route(webservice.GET("/attachments/{attachment}").
|
||||
To(openpitrix.DescribeAttachment).
|
||||
Doc("Get attachment by attachment id").
|
||||
Param(webservice.PathParameter("attachment", "attachment id")).
|
||||
Returns(http.StatusOK, ok, opmodels.Attachment{}))
|
||||
|
||||
webservice.Route(webservice.POST("/repos").
|
||||
To(openpitrix.CreateRepo).
|
||||
Doc("Create repository, repository used to store package of app").
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}).
|
||||
Param(webservice.QueryParameter("validate", "Validate repository")).
|
||||
Returns(http.StatusOK, ok, opmodels.CreateRepoResponse{}).
|
||||
Reads(opmodels.CreateRepoRequest{}))
|
||||
webservice.Route(webservice.DELETE("/repos/{repo}").
|
||||
To(openpitrix.DeleteRepo).
|
||||
Doc("Delete the specified repository").
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}).
|
||||
Returns(http.StatusOK, ok, errors.Error{}).
|
||||
Param(webservice.PathParameter("repo", "repo id")))
|
||||
webservice.Route(webservice.PATCH("/repos/{repo}").
|
||||
Consumes(mimePatch...).
|
||||
To(openpitrix.ModifyRepo).
|
||||
Doc("Patch the specified repository").
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}).
|
||||
Reads(opmodels.ModifyRepoRequest{}).
|
||||
Returns(http.StatusOK, ok, errors.Error{}).
|
||||
Param(webservice.PathParameter("repo", "repo id")))
|
||||
webservice.Route(webservice.GET("/repos/{repo}").
|
||||
To(openpitrix.DescribeRepo).
|
||||
Doc("Describe the specified repository").
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}).
|
||||
Returns(http.StatusOK, ok, opmodels.Repo{}).
|
||||
Param(webservice.PathParameter("repo", "repo id")))
|
||||
webservice.Route(webservice.GET("/repos").
|
||||
To(openpitrix.ListRepos).
|
||||
Doc("List repositories").
|
||||
Param(webservice.QueryParameter(params.ConditionsParam, "query conditions,connect multiple conditions with commas, equal symbol for exact query, wave symbol for fuzzy query e.g. name~a").
|
||||
Required(false).
|
||||
DataFormat("key=%s,key~%s")).
|
||||
Param(webservice.QueryParameter(params.PagingParam, "paging query, e.g. limit=100,page=1").
|
||||
Required(false).
|
||||
DataFormat("limit=%d,page=%d").
|
||||
DefaultValue("limit=10,page=1")).
|
||||
Param(webservice.QueryParameter(params.ReverseParam, "sort parameters, e.g. reverse=true")).
|
||||
Param(webservice.QueryParameter(params.OrderByParam, "sort parameters, e.g. orderBy=createTime")).
|
||||
Returns(http.StatusOK, ok, models.PageableResponse{}))
|
||||
webservice.Route(webservice.POST("/repos/{repo}/action").
|
||||
To(openpitrix.DoRepoAction).
|
||||
Doc("Start index repository event").
|
||||
Reads(opmodels.RepoActionRequest{}).
|
||||
Returns(http.StatusOK, ok, errors.Error{}).
|
||||
Param(webservice.PathParameter("repo", "repo id")))
|
||||
webservice.Route(webservice.GET("/repos/{repo}/events").
|
||||
To(openpitrix.ListRepoEvents).
|
||||
Doc("Get repository events").
|
||||
Returns(http.StatusOK, ok, models.PageableResponse{}).
|
||||
Param(webservice.PathParameter("repo", "repo id")))
|
||||
|
||||
c.Add(webservice)
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -35,13 +35,11 @@ import (
|
||||
"kubesphere.io/kubesphere/pkg/apiserver/workloadstatuses"
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
"kubesphere.io/kubesphere/pkg/models/applications"
|
||||
gitmodel "kubesphere.io/kubesphere/pkg/models/git"
|
||||
registriesmodel "kubesphere.io/kubesphere/pkg/models/registries"
|
||||
"kubesphere.io/kubesphere/pkg/models/status"
|
||||
"kubesphere.io/kubesphere/pkg/server/errors"
|
||||
"kubesphere.io/kubesphere/pkg/server/params"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/openpitrix"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
@@ -110,61 +108,6 @@ func addWebService(c *restful.Container) error {
|
||||
Param(webservice.PathParameter("node", "node name")).
|
||||
Returns(http.StatusOK, ok, errors.Error{}))
|
||||
|
||||
webservice.Route(webservice.GET("/applications").
|
||||
To(resources.ListApplication).
|
||||
Returns(http.StatusOK, ok, models.PageableResponse{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.ClusterResourcesTag}).
|
||||
Doc("List applications in cluster").
|
||||
Param(webservice.QueryParameter(params.ConditionsParam, "query conditions, connect multiple conditions with commas, equal symbol for exact query, wave symbol for fuzzy query e.g. name~a").
|
||||
Required(false).
|
||||
DataFormat("key=value,key~value").
|
||||
DefaultValue("")).
|
||||
Param(webservice.QueryParameter("cluster_id", "equivalent to application unique ID")).
|
||||
Param(webservice.QueryParameter("runtime_id", "runtime id initialization when namespace is created, means which namespace")).
|
||||
Param(webservice.QueryParameter(params.PagingParam, "paging query, e.g. limit=100,page=1").
|
||||
Required(false).
|
||||
DataFormat("limit=%d,page=%d").
|
||||
DefaultValue("limit=10,page=1")))
|
||||
|
||||
webservice.Route(webservice.GET("/namespaces/{namespace}/applications").
|
||||
To(resources.ListNamespacedApplication).
|
||||
Returns(http.StatusOK, ok, models.PageableResponse{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.NamespaceResourcesTag}).
|
||||
Doc("List all applications within the specified namespace").
|
||||
Param(webservice.QueryParameter(params.ConditionsParam, "query conditions, connect multiple conditions with commas, equal symbol for exact query, wave symbol for fuzzy query e.g. name~a").
|
||||
Required(false).
|
||||
DataFormat("key=value,key~value").
|
||||
DefaultValue("")).
|
||||
Param(webservice.PathParameter("namespace", "the name of the project")).
|
||||
Param(webservice.QueryParameter(params.PagingParam, "paging query, e.g. limit=100,page=1").
|
||||
Required(false).
|
||||
DataFormat("limit=%d,page=%d").
|
||||
DefaultValue("limit=10,page=1")))
|
||||
|
||||
webservice.Route(webservice.GET("/namespaces/{namespace}/applications/{application}").
|
||||
To(resources.DescribeApplication).
|
||||
Returns(http.StatusOK, ok, applications.Application{}).
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.NamespaceResourcesTag}).
|
||||
Doc("Describe the specified application of the namespace").
|
||||
Param(webservice.PathParameter("namespace", "the name of the project")).
|
||||
Param(webservice.PathParameter("application", "application ID")))
|
||||
|
||||
webservice.Route(webservice.POST("/namespaces/{namespace}/applications").
|
||||
To(resources.DeployApplication).
|
||||
Doc("Deploy a new application").
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.NamespaceResourcesTag}).
|
||||
Reads(openpitrix.CreateClusterRequest{}).
|
||||
Returns(http.StatusOK, ok, errors.Error{}).
|
||||
Param(webservice.PathParameter("namespace", "the name of the project")))
|
||||
|
||||
webservice.Route(webservice.DELETE("/namespaces/{namespace}/applications/{application}").
|
||||
To(resources.DeleteApplication).
|
||||
Doc("Delete the specified application").
|
||||
Metadata(restfulspec.KeyOpenAPITags, []string{constants.NamespaceResourcesTag}).
|
||||
Returns(http.StatusOK, ok, errors.Error{}).
|
||||
Param(webservice.PathParameter("namespace", "the name of the project")).
|
||||
Param(webservice.PathParameter("application", "application ID")))
|
||||
|
||||
webservice.Route(webservice.GET("/users/{user}/kubectl").
|
||||
To(resources.GetKubectl).
|
||||
Doc("get user's kubectl pod").
|
||||
|
||||
273
pkg/apiserver/openpitrix/applications.go
Normal file
273
pkg/apiserver/openpitrix/applications.go
Normal file
@@ -0,0 +1,273 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2019 The KubeSphere Authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* /
|
||||
*/
|
||||
|
||||
package openpitrix
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/emicklei/go-restful"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/klog"
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
"kubesphere.io/kubesphere/pkg/models/openpitrix"
|
||||
"kubesphere.io/kubesphere/pkg/models/resources"
|
||||
"kubesphere.io/kubesphere/pkg/server/errors"
|
||||
"kubesphere.io/kubesphere/pkg/server/params"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func ListApplications(req *restful.Request, resp *restful.Response) {
|
||||
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
|
||||
namespaceName := req.PathParameter("namespace")
|
||||
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if namespaceName != "" {
|
||||
namespace, err := resources.GetResource("", resources.Namespaces, namespaceName)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
var runtimeId string
|
||||
|
||||
if ns, ok := namespace.(*v1.Namespace); ok {
|
||||
runtimeId = ns.Annotations[constants.OpenPitrixRuntimeAnnotationKey]
|
||||
}
|
||||
|
||||
if runtimeId == "" {
|
||||
resp.WriteAsJson(models.PageableResponse{Items: []interface{}{}, TotalCount: 0})
|
||||
return
|
||||
} else {
|
||||
conditions.Match["runtime_id"] = runtimeId
|
||||
}
|
||||
}
|
||||
|
||||
result, err := openpitrix.ListApplications(conditions, limit, offset)
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(result)
|
||||
}
|
||||
|
||||
func DescribeApplication(req *restful.Request, resp *restful.Response) {
|
||||
clusterId := req.PathParameter("application")
|
||||
namespaceName := req.PathParameter("namespace")
|
||||
app, err := openpitrix.DescribeApplication(namespaceName, clusterId)
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
if status.Code(err) == codes.NotFound {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotFound, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
namespace, err := resources.GetResource("", resources.Namespaces, namespaceName)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
var runtimeId string
|
||||
|
||||
if ns, ok := namespace.(*v1.Namespace); ok {
|
||||
runtimeId = ns.Annotations[constants.OpenPitrixRuntimeAnnotationKey]
|
||||
}
|
||||
|
||||
if runtimeId != app.Cluster.RuntimeId {
|
||||
err = fmt.Errorf("rumtime not match %s,%s", app.Cluster.RuntimeId, runtimeId)
|
||||
klog.V(4).Info(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusForbidden, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(app)
|
||||
return
|
||||
}
|
||||
|
||||
func CreateApplication(req *restful.Request, resp *restful.Response) {
|
||||
namespace := req.PathParameter("namespace")
|
||||
var createClusterRequest openpitrix.CreateClusterRequest
|
||||
err := req.ReadEntity(&createClusterRequest)
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
createClusterRequest.Username = req.HeaderParameter(constants.UserNameHeader)
|
||||
|
||||
err = openpitrix.CreateApplication(namespace, createClusterRequest)
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
resp.WriteEntity(errors.None)
|
||||
}
|
||||
|
||||
func ModifyApplication(req *restful.Request, resp *restful.Response) {
|
||||
var modifyClusterAttributesRequest openpitrix.ModifyClusterAttributesRequest
|
||||
clusterId := req.PathParameter("application")
|
||||
namespaceName := req.PathParameter("namespace")
|
||||
err := req.ReadEntity(&modifyClusterAttributesRequest)
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
app, err := openpitrix.DescribeApplication(namespaceName, clusterId)
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if status.Code(err) == codes.NotFound {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotFound, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
namespace, err := resources.GetResource("", resources.Namespaces, namespaceName)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
var runtimeId string
|
||||
|
||||
if ns, ok := namespace.(*v1.Namespace); ok {
|
||||
runtimeId = ns.Annotations[constants.OpenPitrixRuntimeAnnotationKey]
|
||||
}
|
||||
|
||||
if runtimeId != app.Cluster.RuntimeId {
|
||||
err = fmt.Errorf("rumtime not match %s,%s", app.Cluster.RuntimeId, runtimeId)
|
||||
klog.V(4).Info(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusForbidden, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
err = openpitrix.PatchApplication(&modifyClusterAttributesRequest)
|
||||
|
||||
if status.Code(err) == codes.NotFound {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotFound, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(errors.None)
|
||||
}
|
||||
|
||||
func DeleteApplication(req *restful.Request, resp *restful.Response) {
|
||||
clusterId := req.PathParameter("application")
|
||||
namespaceName := req.PathParameter("namespace")
|
||||
app, err := openpitrix.DescribeApplication(namespaceName, clusterId)
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if status.Code(err) == codes.NotFound {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotFound, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
namespace, err := resources.GetResource("", resources.Namespaces, namespaceName)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
var runtimeId string
|
||||
|
||||
if ns, ok := namespace.(*v1.Namespace); ok {
|
||||
runtimeId = ns.Annotations[constants.OpenPitrixRuntimeAnnotationKey]
|
||||
}
|
||||
|
||||
if runtimeId != app.Cluster.RuntimeId {
|
||||
err = fmt.Errorf("rumtime not match %s,%s", app.Cluster.RuntimeId, runtimeId)
|
||||
klog.V(4).Info(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusForbidden, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
err = openpitrix.DeleteApplication(clusterId)
|
||||
|
||||
if status.Code(err) == codes.NotFound {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotFound, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(errors.None)
|
||||
}
|
||||
544
pkg/apiserver/openpitrix/apps.go
Normal file
544
pkg/apiserver/openpitrix/apps.go
Normal file
@@ -0,0 +1,544 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2019 The KubeSphere Authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* /
|
||||
*/
|
||||
|
||||
package openpitrix
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"k8s.io/klog"
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/models/openpitrix"
|
||||
"kubesphere.io/kubesphere/pkg/server/errors"
|
||||
"kubesphere.io/kubesphere/pkg/server/params"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func GetAppVersionPackage(req *restful.Request, resp *restful.Response) {
|
||||
appId := req.PathParameter("app")
|
||||
versionId := req.PathParameter("version")
|
||||
|
||||
result, err := openpitrix.GetAppVersionPackage(appId, versionId)
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
|
||||
func DoAppAction(req *restful.Request, resp *restful.Response) {
|
||||
var doActionRequest openpitrix.ActionRequest
|
||||
err := req.ReadEntity(&doActionRequest)
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
appId := req.PathParameter("app")
|
||||
|
||||
err = openpitrix.DoAppAction(appId, &doActionRequest)
|
||||
if status.Code(err) == codes.NotFound {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotFound, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if status.Code(err) == codes.InvalidArgument {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(errors.None)
|
||||
}
|
||||
|
||||
func DoAppVersionAction(req *restful.Request, resp *restful.Response) {
|
||||
var doActionRequest openpitrix.ActionRequest
|
||||
err := req.ReadEntity(&doActionRequest)
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
doActionRequest.Username = req.HeaderParameter(constants.UserNameHeader)
|
||||
|
||||
versionId := req.PathParameter("version")
|
||||
|
||||
err = openpitrix.DoAppVersionAction(versionId, &doActionRequest)
|
||||
if status.Code(err) == codes.NotFound {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotFound, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if status.Code(err) == codes.InvalidArgument {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(errors.None)
|
||||
}
|
||||
|
||||
func GetAppVersionFiles(req *restful.Request, resp *restful.Response) {
|
||||
versionId := req.PathParameter("version")
|
||||
getAppVersionFilesRequest := &openpitrix.GetAppVersionFilesRequest{}
|
||||
if f := req.QueryParameter("files"); f != "" {
|
||||
getAppVersionFilesRequest.Files = strings.Split(f, ",")
|
||||
}
|
||||
|
||||
result, err := openpitrix.GetAppVersionFiles(versionId, getAppVersionFilesRequest)
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if status.Code(err) == codes.NotFound {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotFound, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
|
||||
func ListAppVersionAudits(req *restful.Request, resp *restful.Response) {
|
||||
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
|
||||
orderBy := req.QueryParameter(params.OrderByParam)
|
||||
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
|
||||
reverse := params.ParseReverse(req)
|
||||
appId := req.PathParameter("app")
|
||||
versionId := req.PathParameter("version")
|
||||
if orderBy == "" {
|
||||
orderBy = "status_time"
|
||||
reverse = true
|
||||
}
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
conditions.Match["app"] = appId
|
||||
if versionId != "" {
|
||||
conditions.Match["version"] = versionId
|
||||
}
|
||||
|
||||
result, err := openpitrix.ListAppVersionAudits(conditions, orderBy, reverse, limit, offset)
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
|
||||
func ListReviews(req *restful.Request, resp *restful.Response) {
|
||||
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
|
||||
orderBy := req.QueryParameter(params.OrderByParam)
|
||||
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
|
||||
reverse := params.ParseReverse(req)
|
||||
if orderBy == "" {
|
||||
orderBy = "status_time"
|
||||
reverse = true
|
||||
}
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
result, err := openpitrix.ListAppVersionReviews(conditions, orderBy, reverse, limit, offset)
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
|
||||
func ListAppVersions(req *restful.Request, resp *restful.Response) {
|
||||
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
|
||||
orderBy := req.QueryParameter(params.OrderByParam)
|
||||
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
|
||||
reverse := params.ParseReverse(req)
|
||||
appId := req.PathParameter("app")
|
||||
statistics, _ := strconv.ParseBool(req.QueryParameter("statistics"))
|
||||
if orderBy == "" {
|
||||
orderBy = "create_time"
|
||||
reverse = true
|
||||
}
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
conditions.Match["app"] = appId
|
||||
|
||||
result, err := openpitrix.ListAppVersions(conditions, orderBy, reverse, limit, offset)
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if statistics {
|
||||
for _, item := range result.Items {
|
||||
if version, ok := item.(*openpitrix.AppVersion); ok {
|
||||
statisticsResult, err := openpitrix.ListApplications(¶ms.Conditions{Match: map[string]string{"app_id": version.AppId, "version_id": version.VersionId}}, 0, 0)
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
version.ClusterTotal = &statisticsResult.TotalCount
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
|
||||
func ListApps(req *restful.Request, resp *restful.Response) {
|
||||
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
|
||||
orderBy := req.QueryParameter(params.OrderByParam)
|
||||
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
|
||||
reverse := params.ParseReverse(req)
|
||||
statistics, _ := strconv.ParseBool(req.QueryParameter("statistics"))
|
||||
if orderBy == "" {
|
||||
orderBy = "create_time"
|
||||
reverse = true
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
result, err := openpitrix.ListApps(conditions, orderBy, reverse, limit, offset)
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if statistics {
|
||||
for _, item := range result.Items {
|
||||
if app, ok := item.(*openpitrix.App); ok {
|
||||
statisticsResult, err := openpitrix.ListApplications(¶ms.Conditions{Match: map[string]string{"app_id": app.AppId, "status": "active|used|enabled|stopped"}}, 0, 0)
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
app.ClusterTotal = &statisticsResult.TotalCount
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
|
||||
func ModifyApp(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
var patchAppRequest openpitrix.ModifyAppRequest
|
||||
err := req.ReadEntity(&patchAppRequest)
|
||||
appId := req.PathParameter("app")
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
err = openpitrix.PatchApp(appId, &patchAppRequest)
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if status.Code(err) == codes.NotFound {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotFound, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if status.Code(err) == codes.InvalidArgument {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(errors.None)
|
||||
}
|
||||
|
||||
func DescribeApp(req *restful.Request, resp *restful.Response) {
|
||||
appId := req.PathParameter("app")
|
||||
|
||||
result, err := openpitrix.DescribeApp(appId)
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if status.Code(err) == codes.NotFound {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotFound, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
|
||||
func DeleteApp(req *restful.Request, resp *restful.Response) {
|
||||
appId := req.PathParameter("app")
|
||||
|
||||
err := openpitrix.DeleteApp(appId)
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if status.Code(err) == codes.NotFound {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotFound, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(errors.None)
|
||||
}
|
||||
|
||||
func CreateApp(req *restful.Request, resp *restful.Response) {
|
||||
createAppRequest := &openpitrix.CreateAppRequest{}
|
||||
err := req.ReadEntity(createAppRequest)
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
validate, _ := strconv.ParseBool(req.QueryParameter("validate"))
|
||||
|
||||
var result interface{}
|
||||
|
||||
if validate {
|
||||
validatePackageRequest := &openpitrix.ValidatePackageRequest{
|
||||
VersionPackage: createAppRequest.VersionPackage,
|
||||
VersionType: createAppRequest.VersionType,
|
||||
}
|
||||
result, err = openpitrix.ValidatePackage(validatePackageRequest)
|
||||
} else {
|
||||
result, err = openpitrix.CreateApp(createAppRequest)
|
||||
}
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if status.Code(err) == codes.InvalidArgument {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
|
||||
func CreateAppVersion(req *restful.Request, resp *restful.Response) {
|
||||
var createAppVersionRequest openpitrix.CreateAppVersionRequest
|
||||
err := req.ReadEntity(&createAppVersionRequest)
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
// override app id
|
||||
appId := req.PathParameter("app")
|
||||
createAppVersionRequest.AppId = appId
|
||||
|
||||
validate, _ := strconv.ParseBool(req.QueryParameter("validate"))
|
||||
|
||||
var result interface{}
|
||||
|
||||
if validate {
|
||||
validatePackageRequest := &openpitrix.ValidatePackageRequest{
|
||||
VersionPackage: createAppVersionRequest.Package,
|
||||
VersionType: createAppVersionRequest.Type,
|
||||
}
|
||||
result, err = openpitrix.ValidatePackage(validatePackageRequest)
|
||||
} else {
|
||||
result, err = openpitrix.CreateAppVersion(&createAppVersionRequest)
|
||||
}
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if status.Code(err) == codes.InvalidArgument {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
|
||||
func ModifyAppVersion(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
var patchAppVersionRequest openpitrix.ModifyAppVersionRequest
|
||||
err := req.ReadEntity(&patchAppVersionRequest)
|
||||
versionId := req.PathParameter("version")
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
err = openpitrix.PatchAppVersion(versionId, &patchAppVersionRequest)
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if status.Code(err) == codes.InvalidArgument {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(errors.None)
|
||||
}
|
||||
|
||||
func DeleteAppVersion(req *restful.Request, resp *restful.Response) {
|
||||
versionId := req.PathParameter("version")
|
||||
|
||||
err := openpitrix.DeleteAppVersion(versionId)
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if status.Code(err) == codes.NotFound {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotFound, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(errors.None)
|
||||
}
|
||||
|
||||
func DescribeAppVersion(req *restful.Request, resp *restful.Response) {
|
||||
versionId := req.PathParameter("version")
|
||||
|
||||
result, err := openpitrix.DescribeAppVersion(versionId)
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if status.Code(err) == codes.NotFound {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotFound, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
54
pkg/apiserver/openpitrix/attachments.go
Normal file
54
pkg/apiserver/openpitrix/attachments.go
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2019 The KubeSphere Authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* /
|
||||
*/
|
||||
|
||||
package openpitrix
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"kubesphere.io/kubesphere/pkg/models/openpitrix"
|
||||
"kubesphere.io/kubesphere/pkg/server/errors"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func DescribeAttachment(req *restful.Request, resp *restful.Response) {
|
||||
attachmentId := req.PathParameter("attachment")
|
||||
fileName := req.QueryParameter("filename")
|
||||
result, err := openpitrix.DescribeAttachment(attachmentId)
|
||||
// file raw
|
||||
if fileName != "" {
|
||||
data := result.AttachmentContent[fileName]
|
||||
resp.Write(data)
|
||||
resp.Header().Set("Content-Type", "text/plain")
|
||||
return
|
||||
}
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if status.Code(err) == codes.NotFound {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotFound, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
171
pkg/apiserver/openpitrix/categories.go
Normal file
171
pkg/apiserver/openpitrix/categories.go
Normal file
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2019 The KubeSphere Authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* /
|
||||
*/
|
||||
|
||||
package openpitrix
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"k8s.io/klog"
|
||||
"kubesphere.io/kubesphere/pkg/models/openpitrix"
|
||||
"kubesphere.io/kubesphere/pkg/server/errors"
|
||||
"kubesphere.io/kubesphere/pkg/server/params"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client"
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func CreateCategory(req *restful.Request, resp *restful.Response) {
|
||||
createCategoryRequest := &openpitrix.CreateCategoryRequest{}
|
||||
err := req.ReadEntity(createCategoryRequest)
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
result, err := openpitrix.CreateCategory(createCategoryRequest)
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
if status.Code(err) == codes.InvalidArgument {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
func DeleteCategory(req *restful.Request, resp *restful.Response) {
|
||||
categoryId := req.PathParameter("category")
|
||||
|
||||
err := openpitrix.DeleteCategory(categoryId)
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
if status.Code(err) == codes.NotFound {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotFound, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(errors.None)
|
||||
}
|
||||
func ModifyCategory(req *restful.Request, resp *restful.Response) {
|
||||
var modifyCategoryRequest openpitrix.ModifyCategoryRequest
|
||||
categoryId := req.PathParameter("category")
|
||||
err := req.ReadEntity(&modifyCategoryRequest)
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
err = openpitrix.PatchCategory(categoryId, &modifyCategoryRequest)
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
if status.Code(err) == codes.InvalidArgument {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(errors.None)
|
||||
}
|
||||
func DescribeCategory(req *restful.Request, resp *restful.Response) {
|
||||
categoryId := req.PathParameter("category")
|
||||
|
||||
result, err := openpitrix.DescribeCategory(categoryId)
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if status.Code(err) == codes.NotFound {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotFound, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
func ListCategories(req *restful.Request, resp *restful.Response) {
|
||||
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
|
||||
orderBy := req.QueryParameter(params.OrderByParam)
|
||||
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
|
||||
reverse := params.ParseReverse(req)
|
||||
if orderBy == "" {
|
||||
orderBy = "create_time"
|
||||
reverse = true
|
||||
}
|
||||
statistics, _ := strconv.ParseBool(req.QueryParameter("statistics"))
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
result, err := openpitrix.ListCategories(conditions, orderBy, reverse, limit, offset)
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if statistics {
|
||||
for _, item := range result.Items {
|
||||
if category, ok := item.(*openpitrix.Category); ok {
|
||||
statisticsResult, err := openpitrix.ListApps(¶ms.Conditions{Match: map[string]string{"category_id": category.CategoryID, "status": "active"}}, "", false, 0, 0)
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
category.AppTotal = &statisticsResult.TotalCount
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
222
pkg/apiserver/openpitrix/repos.go
Normal file
222
pkg/apiserver/openpitrix/repos.go
Normal file
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2019 The KubeSphere Authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* /
|
||||
*/
|
||||
|
||||
package openpitrix
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"k8s.io/klog"
|
||||
"kubesphere.io/kubesphere/pkg/models/openpitrix"
|
||||
"kubesphere.io/kubesphere/pkg/server/errors"
|
||||
"kubesphere.io/kubesphere/pkg/server/params"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client"
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func CreateRepo(req *restful.Request, resp *restful.Response) {
|
||||
createRepoRequest := &openpitrix.CreateRepoRequest{}
|
||||
err := req.ReadEntity(createRepoRequest)
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
validate, _ := strconv.ParseBool(req.QueryParameter("validate"))
|
||||
|
||||
var result interface{}
|
||||
|
||||
if validate {
|
||||
validateRepoRequest := &openpitrix.ValidateRepoRequest{
|
||||
Type: createRepoRequest.Type,
|
||||
Url: createRepoRequest.URL,
|
||||
Credential: createRepoRequest.Credential,
|
||||
}
|
||||
result, err = openpitrix.ValidateRepo(validateRepoRequest)
|
||||
} else {
|
||||
result, err = openpitrix.CreateRepo(createRepoRequest)
|
||||
}
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
if status.Code(err) == codes.InvalidArgument {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
|
||||
func DoRepoAction(req *restful.Request, resp *restful.Response) {
|
||||
repoActionRequest := &openpitrix.RepoActionRequest{}
|
||||
repoId := req.PathParameter("repo")
|
||||
err := req.ReadEntity(repoActionRequest)
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
err = openpitrix.DoRepoAction(repoId, repoActionRequest)
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
if status.Code(err) == codes.InvalidArgument {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(errors.None)
|
||||
}
|
||||
|
||||
func DeleteRepo(req *restful.Request, resp *restful.Response) {
|
||||
repoId := req.PathParameter("repo")
|
||||
|
||||
err := openpitrix.DeleteRepo(repoId)
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
if status.Code(err) == codes.NotFound {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotFound, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(errors.None)
|
||||
}
|
||||
|
||||
func ModifyRepo(req *restful.Request, resp *restful.Response) {
|
||||
var updateRepoRequest openpitrix.ModifyRepoRequest
|
||||
repoId := req.PathParameter("repo")
|
||||
err := req.ReadEntity(&updateRepoRequest)
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
err = openpitrix.PatchRepo(repoId, &updateRepoRequest)
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
if status.Code(err) == codes.InvalidArgument {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(errors.None)
|
||||
}
|
||||
|
||||
func DescribeRepo(req *restful.Request, resp *restful.Response) {
|
||||
repoId := req.PathParameter("repo")
|
||||
|
||||
result, err := openpitrix.DescribeRepo(repoId)
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
if status.Code(err) == codes.NotFound {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotFound, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
func ListRepos(req *restful.Request, resp *restful.Response) {
|
||||
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
|
||||
orderBy := req.QueryParameter(params.OrderByParam)
|
||||
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
|
||||
reverse := params.ParseReverse(req)
|
||||
if orderBy == "" {
|
||||
orderBy = "create_time"
|
||||
reverse = true
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
result, err := openpitrix.ListRepos(conditions, orderBy, reverse, limit, offset)
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
|
||||
func ListRepoEvents(req *restful.Request, resp *restful.Response) {
|
||||
repoId := req.PathParameter("repo")
|
||||
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
|
||||
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
result, err := openpitrix.ListRepoEvents(repoId, conditions, limit, offset)
|
||||
|
||||
if _, notEnabled := err.(client.ClientSetNotEnabledError); notEnabled {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotImplemented, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
@@ -1,206 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 The KubeSphere Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
package resources
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/emicklei/go-restful"
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/klog"
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
"kubesphere.io/kubesphere/pkg/models/applications"
|
||||
"kubesphere.io/kubesphere/pkg/models/resources"
|
||||
"kubesphere.io/kubesphere/pkg/server/errors"
|
||||
"kubesphere.io/kubesphere/pkg/server/params"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/openpitrix"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func ListApplication(req *restful.Request, resp *restful.Response) {
|
||||
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
|
||||
clusterId := req.QueryParameter("cluster_id")
|
||||
runtimeId := req.QueryParameter("runtime_id")
|
||||
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
|
||||
if err != nil {
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
}
|
||||
if len(clusterId) > 0 {
|
||||
app, err := applications.GetApp(clusterId)
|
||||
if err != nil {
|
||||
klog.Errorln("get application error", err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
resp.WriteEntity(app)
|
||||
return
|
||||
}
|
||||
|
||||
result, err := applications.ListApplication(runtimeId, conditions, limit, offset)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(result)
|
||||
|
||||
}
|
||||
|
||||
func ListNamespacedApplication(req *restful.Request, resp *restful.Response) {
|
||||
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
|
||||
namespaceName := req.PathParameter("namespace")
|
||||
clusterId := req.QueryParameter("cluster_id")
|
||||
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
if len(clusterId) > 0 {
|
||||
app, err := applications.GetApp(clusterId)
|
||||
if err != nil {
|
||||
klog.Errorln("get app failed", err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
resp.WriteEntity(app)
|
||||
return
|
||||
}
|
||||
|
||||
namespace, err := resources.GetResource("", resources.Namespaces, namespaceName)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln("get namespace failed", err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
var runtimeId string
|
||||
|
||||
if ns, ok := namespace.(*v1.Namespace); ok {
|
||||
runtimeId = ns.Annotations[constants.OpenPitrixRuntimeAnnotationKey]
|
||||
}
|
||||
|
||||
if runtimeId == "" {
|
||||
klog.Errorln("runtime id not found")
|
||||
resp.WriteAsJson(models.PageableResponse{Items: []interface{}{}, TotalCount: 0})
|
||||
return
|
||||
}
|
||||
|
||||
result, err := applications.ListApplication(runtimeId, conditions, limit, offset)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln("list applications failed", err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteAsJson(result)
|
||||
}
|
||||
|
||||
func DescribeApplication(req *restful.Request, resp *restful.Response) {
|
||||
clusterId := req.PathParameter("application")
|
||||
namespaceName := req.PathParameter("namespace")
|
||||
app, err := applications.GetApp(clusterId)
|
||||
if err != nil {
|
||||
klog.Errorln("get app failed", err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
namespace, err := resources.GetResource("", resources.Namespaces, namespaceName)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln("get namespace failed", err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
var runtimeId string
|
||||
|
||||
if ns, ok := namespace.(*v1.Namespace); ok {
|
||||
runtimeId = ns.Annotations[constants.OpenPitrixRuntimeAnnotationKey]
|
||||
}
|
||||
|
||||
if runtimeId != app.RuntimeId {
|
||||
klog.Errorln("runtime not match", app.RuntimeId, runtimeId)
|
||||
resp.WriteHeaderAndEntity(http.StatusForbidden, errors.New(fmt.Sprintf("rumtime not match %s,%s", app.RuntimeId, runtimeId)))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(app)
|
||||
return
|
||||
}
|
||||
|
||||
func DeployApplication(req *restful.Request, resp *restful.Response) {
|
||||
namespace := req.PathParameter("namespace")
|
||||
var app openpitrix.CreateClusterRequest
|
||||
err := req.ReadEntity(&app)
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
err = applications.DeployApplication(namespace, app)
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
resp.WriteEntity(errors.None)
|
||||
}
|
||||
|
||||
func DeleteApplication(req *restful.Request, resp *restful.Response) {
|
||||
clusterId := req.PathParameter("application")
|
||||
namespaceName := req.PathParameter("namespace")
|
||||
app, err := applications.GetApp(clusterId)
|
||||
if err != nil {
|
||||
klog.Errorln("get app failed", err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
namespace, err := resources.GetResource("", resources.Namespaces, namespaceName)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln("get namespace failed", err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
var runtimeId string
|
||||
|
||||
if ns, ok := namespace.(*v1.Namespace); ok {
|
||||
runtimeId = ns.Annotations[constants.OpenPitrixRuntimeAnnotationKey]
|
||||
}
|
||||
|
||||
if runtimeId != app.RuntimeId {
|
||||
klog.Errorln("runtime not match", app.RuntimeId, runtimeId)
|
||||
resp.WriteHeaderAndEntity(http.StatusForbidden, errors.New(fmt.Sprintf("rumtime not match %s,%s", app.RuntimeId, runtimeId)))
|
||||
return
|
||||
}
|
||||
|
||||
err = applications.DeleteApplication(clusterId)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln("delete application failed", err)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(errors.None)
|
||||
}
|
||||
@@ -31,10 +31,16 @@ var Container = restful.NewContainer()
|
||||
|
||||
type ContainerBuilder []func(c *restful.Container) error
|
||||
|
||||
//
|
||||
const MimeMergePatchJson = "application/merge-patch+json"
|
||||
const MimeJsonPatchJson = "application/json-patch+json"
|
||||
|
||||
func init() {
|
||||
restful.RegisterEntityAccessor(MimeMergePatchJson, restful.NewEntityAccessorJSON(restful.MIME_JSON))
|
||||
restful.RegisterEntityAccessor(MimeJsonPatchJson, restful.NewEntityAccessorJSON(restful.MIME_JSON))
|
||||
}
|
||||
|
||||
func NewWebService(gv schema.GroupVersion) *restful.WebService {
|
||||
webservice := restful.WebService{}
|
||||
|
||||
webservice.Path(ApiRootPath + "/" + gv.String()).
|
||||
Consumes(restful.MIME_JSON).
|
||||
Produces(restful.MIME_JSON)
|
||||
|
||||
@@ -56,6 +56,7 @@ const (
|
||||
NamespaceResourcesTag = "Namespace Resources"
|
||||
ClusterResourcesTag = "Cluster Resources"
|
||||
ComponentStatusTag = "Component Status"
|
||||
OpenpitrixTag = "Openpitrix Resources"
|
||||
VerificationTag = "Verification"
|
||||
RegistryTag = "Docker Registry"
|
||||
UserResourcesTag = "User Resources"
|
||||
|
||||
@@ -21,6 +21,7 @@ package namespace
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/golang/protobuf/ptypes/wrappers"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
rbac "k8s.io/api/rbac/v1"
|
||||
@@ -35,7 +36,7 @@ import (
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/openpitrix"
|
||||
"kubesphere.io/kubesphere/pkg/utils/k8sutil"
|
||||
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
|
||||
"math"
|
||||
"openpitrix.io/openpitrix/pkg/pb"
|
||||
"reflect"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller"
|
||||
@@ -44,7 +45,6 @@ import (
|
||||
"sigs.k8s.io/controller-runtime/pkg/manager"
|
||||
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
||||
"sigs.k8s.io/controller-runtime/pkg/source"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -137,12 +137,14 @@ func (r *ReconcileNamespace) Reconcile(request reconcile.Request) (reconcile.Res
|
||||
} else {
|
||||
// The object is being deleted
|
||||
if sliceutil.HasString(instance.ObjectMeta.Finalizers, finalizer) {
|
||||
if err := r.deleteRouter(instance.Name); err != nil {
|
||||
if err = r.deleteRouter(instance.Name); err != nil {
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
|
||||
// delete runtime in the background, retry 3 times
|
||||
go r.deleteRuntime(instance)
|
||||
// delete runtime
|
||||
if err = r.deleteRuntime(instance); err != nil {
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
|
||||
// remove our finalizer from the list and update it.
|
||||
instance.ObjectMeta.Finalizers = sliceutil.RemoveString(instance.ObjectMeta.Finalizers, func(item string) bool {
|
||||
@@ -223,8 +225,7 @@ func (r *ReconcileNamespace) checkAndCreateRoles(namespace *corev1.Namespace) er
|
||||
}
|
||||
if !reflect.DeepEqual(found.Rules, role.Rules) {
|
||||
found.Rules = role.Rules
|
||||
err := r.Update(context.TODO(), found)
|
||||
if err != nil {
|
||||
if err := r.Update(context.TODO(), found); err != nil {
|
||||
klog.Errorf("updating default role namespace: %s, role: %s,error: %s", namespace.Name, role.Name, err)
|
||||
return err
|
||||
}
|
||||
@@ -351,30 +352,73 @@ func (r *ReconcileNamespace) checkAndCreateRoleBindings(namespace *corev1.Namesp
|
||||
|
||||
// Create openpitrix runtime
|
||||
func (r *ReconcileNamespace) checkAndCreateRuntime(namespace *corev1.Namespace) error {
|
||||
openPitrixClient, err := cs.ClientSets().OpenPitrix()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if runtimeId := namespace.Annotations[constants.OpenPitrixRuntimeAnnotationKey]; runtimeId != "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
cm := &corev1.ConfigMap{}
|
||||
configName := fmt.Sprintf("kubeconfig-%s", constants.AdminUserName)
|
||||
err = r.Get(context.TODO(), types.NamespacedName{Namespace: constants.KubeSphereControlNamespace, Name: configName}, cm)
|
||||
openPitrixClient, err := cs.ClientSets().OpenPitrix()
|
||||
|
||||
if _, notEnabled := err.(cs.ClientSetNotEnabledError); notEnabled {
|
||||
return nil
|
||||
} else if err != nil {
|
||||
klog.Error(fmt.Sprintf("create runtime, namespace: %s, error: %s", namespace.Name, err))
|
||||
return err
|
||||
}
|
||||
|
||||
adminKubeConfigName := fmt.Sprintf("kubeconfig-%s", constants.AdminUserName)
|
||||
|
||||
runtimeCredentials, err := openPitrixClient.Runtime().DescribeRuntimeCredentials(openpitrix.SystemContext(), &pb.DescribeRuntimeCredentialsRequest{SearchWord: &wrappers.StringValue{Value: adminKubeConfigName}, Limit: 1})
|
||||
|
||||
if err != nil {
|
||||
klog.Error(fmt.Sprintf("create runtime, namespace: %s, error: %s", namespace.Name, err))
|
||||
return err
|
||||
}
|
||||
|
||||
runtime := &openpitrix.RunTime{Name: namespace.Name, Zone: namespace.Name, Provider: "kubernetes", RuntimeCredential: cm.Data["config"]}
|
||||
var kubesphereRuntimeCredentialId string
|
||||
|
||||
if err := openPitrixClient.CreateRuntime(runtime); err != nil {
|
||||
klog.Errorf("creating openpitrix runtime namespace: %s, error: %s", namespace.Name, err)
|
||||
// runtime credential exist
|
||||
if len(runtimeCredentials.GetRuntimeCredentialSet()) > 0 {
|
||||
kubesphereRuntimeCredentialId = runtimeCredentials.GetRuntimeCredentialSet()[0].GetRuntimeCredentialId().GetValue()
|
||||
} else {
|
||||
adminKubeConfig := corev1.ConfigMap{}
|
||||
err := r.Get(context.TODO(), types.NamespacedName{Namespace: constants.KubeSphereControlNamespace, Name: adminKubeConfigName}, &adminKubeConfig)
|
||||
|
||||
if err != nil {
|
||||
klog.Error(fmt.Sprintf("create runtime, namespace: %s, error: %s", namespace.Name, err))
|
||||
return err
|
||||
}
|
||||
|
||||
resp, err := openPitrixClient.Runtime().CreateRuntimeCredential(openpitrix.SystemContext(), &pb.CreateRuntimeCredentialRequest{
|
||||
Name: &wrappers.StringValue{Value: adminKubeConfigName},
|
||||
Provider: &wrappers.StringValue{Value: "kubernetes"},
|
||||
Description: &wrappers.StringValue{Value: "kubeconfig"},
|
||||
RuntimeUrl: &wrappers.StringValue{Value: "kubesphere"},
|
||||
RuntimeCredentialContent: &wrappers.StringValue{Value: adminKubeConfig.Data["config"]},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
klog.Error(fmt.Sprintf("create runtime, namespace: %s, error: %s", namespace.Name, err))
|
||||
return err
|
||||
}
|
||||
|
||||
kubesphereRuntimeCredentialId = resp.GetRuntimeCredentialId().GetValue()
|
||||
}
|
||||
|
||||
runtimeId, err := openPitrixClient.Runtime().CreateRuntime(openpitrix.SystemContext(), &pb.CreateRuntimeRequest{
|
||||
Name: &wrappers.StringValue{Value: namespace.Name},
|
||||
RuntimeCredentialId: &wrappers.StringValue{Value: kubesphereRuntimeCredentialId},
|
||||
Provider: &wrappers.StringValue{Value: openpitrix.KubernetesProvider},
|
||||
Zone: &wrappers.StringValue{Value: namespace.Name},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
klog.Error(fmt.Sprintf("create runtime, namespace: %s, error: %s", namespace.Name, err))
|
||||
return err
|
||||
}
|
||||
|
||||
klog.V(4).Infof("runtime created successfully, namespace: %s, runtime id: %s", namespace.Name, runtimeId)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -382,22 +426,23 @@ func (r *ReconcileNamespace) checkAndCreateRuntime(namespace *corev1.Namespace)
|
||||
func (r *ReconcileNamespace) deleteRuntime(namespace *corev1.Namespace) error {
|
||||
|
||||
if runtimeId := namespace.Annotations[constants.OpenPitrixRuntimeAnnotationKey]; runtimeId != "" {
|
||||
maxRetries := float64(3)
|
||||
for i := float64(0); i < maxRetries; i++ {
|
||||
time.Sleep(time.Duration(i*math.Pow(2, i)) * time.Second)
|
||||
|
||||
openPitrixClient, err := cs.ClientSets().OpenPitrix()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
openPitrixClient, err := cs.ClientSets().OpenPitrix()
|
||||
|
||||
err = openPitrixClient.DeleteRuntime(runtimeId)
|
||||
if _, notEnabled := err.(cs.ClientSetNotEnabledError); notEnabled {
|
||||
return nil
|
||||
} else if err != nil {
|
||||
klog.Errorf("delete openpitrix runtime: %s, error: %s", runtimeId, err)
|
||||
return err
|
||||
}
|
||||
|
||||
if err == nil || openpitrix.IsNotFound(err) || openpitrix.IsDeleted(err) {
|
||||
return nil
|
||||
}
|
||||
_, err = openPitrixClient.Runtime().DeleteRuntimes(openpitrix.SystemContext(), &pb.DeleteRuntimesRequest{RuntimeId: []string{runtimeId}, Force: &wrappers.BoolValue{Value: true}})
|
||||
|
||||
klog.Errorf("delete openpitrix runtime: %v times left, error: %s", maxRetries-i-1, err)
|
||||
if err == nil || openpitrix.IsNotFound(err) || openpitrix.IsDeleted(err) {
|
||||
return nil
|
||||
} else {
|
||||
klog.Errorf("delete openpitrix runtime: %s, error: %s", runtimeId, err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -451,12 +496,12 @@ func (r *ReconcileNamespace) deleteRouter(namespace string) error {
|
||||
if errors.IsNotFound(err) {
|
||||
return nil
|
||||
}
|
||||
klog.V(6).Info("get router service failed", err)
|
||||
klog.Error(err)
|
||||
}
|
||||
|
||||
err = r.Delete(context.TODO(), &found)
|
||||
if err != nil {
|
||||
klog.Error(err, "delete router failed")
|
||||
klog.Error(err)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -467,13 +512,13 @@ func (r *ReconcileNamespace) deleteRouter(namespace string) error {
|
||||
if errors.IsNotFound(err) {
|
||||
return nil
|
||||
}
|
||||
klog.V(6).Info("get router deployment failed", err)
|
||||
klog.Error(err)
|
||||
return err
|
||||
}
|
||||
|
||||
err = r.Delete(context.TODO(), &deploy)
|
||||
if err != nil {
|
||||
klog.Error(err, "delete router deployment failed")
|
||||
klog.Error(err)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -482,7 +527,7 @@ func (r *ReconcileNamespace) deleteRouter(namespace string) error {
|
||||
}
|
||||
|
||||
func (r *ReconcileNamespace) deleteRoleBindings(namespace *corev1.Namespace) error {
|
||||
klog.V(6).Info("deleting role bindings namespace: ", namespace.Name)
|
||||
klog.V(4).Info("deleting role bindings namespace: ", namespace.Name)
|
||||
adminBinding := &rbac.RoleBinding{}
|
||||
adminBinding.Name = admin.Name
|
||||
adminBinding.Namespace = namespace.Name
|
||||
|
||||
@@ -15,10 +15,13 @@
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
package applications
|
||||
package openpitrix
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/golang/protobuf/ptypes/wrappers"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/api/extensions/v1beta1"
|
||||
@@ -31,29 +34,20 @@ import (
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
"kubesphere.io/kubesphere/pkg/models/resources"
|
||||
"kubesphere.io/kubesphere/pkg/server/params"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client"
|
||||
cs "kubesphere.io/kubesphere/pkg/simple/client"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/openpitrix"
|
||||
"openpitrix.io/openpitrix/pkg/pb"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Application struct {
|
||||
Name string `json:"name" description:"application name"`
|
||||
RepoName string `json:"repoName" description:"repo name"`
|
||||
Runtime string `json:"namespace" description:"namespace name"`
|
||||
RuntimeId string `json:"runtime_id" description:"It is the application runtime in OpenPitrix and represents k8s namespace by annotating the namespace"`
|
||||
Version string `json:"version" description:"application version"`
|
||||
VersionId string `json:"version_id" description:"application version id"`
|
||||
Status string `json:"status" description:"application status"`
|
||||
UpdateTime time.Time `json:"updateTime" description:"the last time this application was updated"`
|
||||
CreateTime time.Time `json:"createTime" description:"application creation time"`
|
||||
App string `json:"app" description:"application template name"`
|
||||
AppId string `json:"app_id" description:"application template id"`
|
||||
Description string `json:"description,omitempty" description:"application description"`
|
||||
WorkLoads *workLoads `json:"workloads,omitempty" description:"application workloads"`
|
||||
Services []v1.Service `json:"services,omitempty" description:"application services"`
|
||||
Ingresses []v1beta1.Ingress `json:"ingresses,omitempty" description:"application ingresses"`
|
||||
ClusterID string `json:"cluster_id" description:"application id"`
|
||||
Name string `json:"name" description:"application name"`
|
||||
Cluster *Cluster `json:"cluster,omitempty" description:"application cluster info"`
|
||||
Version *AppVersion `json:"version,omitempty" description:"application template version info"`
|
||||
App *App `json:"app,omitempty" description:"application template info"`
|
||||
WorkLoads *workLoads `json:"workloads,omitempty" description:"application workloads"`
|
||||
Services []v1.Service `json:"services,omitempty" description:"application services"`
|
||||
Ingresses []v1beta1.Ingress `json:"ingresses,omitempty" description:"application ingresses"`
|
||||
}
|
||||
|
||||
type workLoads struct {
|
||||
@@ -62,92 +56,124 @@ type workLoads struct {
|
||||
Daemonsets []appsv1.DaemonSet `json:"daemonsets,omitempty" description:"daemonset list"`
|
||||
}
|
||||
|
||||
func ListApplication(runtimeId string, conditions *params.Conditions, limit, offset int) (*models.PageableResponse, error) {
|
||||
openPitrixClient, err := client.ClientSets().OpenPitrix()
|
||||
func ListApplications(conditions *params.Conditions, limit, offset int) (*models.PageableResponse, error) {
|
||||
client, err := cs.ClientSets().OpenPitrix()
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
clusterList, err := openPitrixClient.ListClusters(runtimeId, conditions.Match["keyword"], conditions.Match["status"], limit, offset)
|
||||
describeClustersRequest := &pb.DescribeClustersRequest{
|
||||
Limit: uint32(limit),
|
||||
Offset: uint32(offset)}
|
||||
if keyword := conditions.Match["keyword"]; keyword != "" {
|
||||
describeClustersRequest.SearchWord = &wrappers.StringValue{Value: keyword}
|
||||
}
|
||||
if runtimeId := conditions.Match["runtime_id"]; runtimeId != "" {
|
||||
describeClustersRequest.RuntimeId = []string{runtimeId}
|
||||
}
|
||||
if appId := conditions.Match["app_id"]; appId != "" {
|
||||
describeClustersRequest.AppId = []string{appId}
|
||||
}
|
||||
if versionId := conditions.Match["version_id"]; versionId != "" {
|
||||
describeClustersRequest.VersionId = []string{versionId}
|
||||
}
|
||||
if status := conditions.Match["status"]; status != "" {
|
||||
describeClustersRequest.Status = strings.Split(status, "|")
|
||||
}
|
||||
resp, err := client.Cluster().DescribeClusters(openpitrix.SystemContext(), describeClustersRequest)
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
return nil, err
|
||||
}
|
||||
result := models.PageableResponse{TotalCount: clusterList.Total}
|
||||
result := models.PageableResponse{TotalCount: int(resp.TotalCount)}
|
||||
result.Items = make([]interface{}, 0)
|
||||
for _, item := range clusterList.Clusters {
|
||||
var app Application
|
||||
|
||||
app.Name = item.Name
|
||||
app.ClusterID = item.ClusterID
|
||||
app.UpdateTime = item.UpdateTime
|
||||
app.Status = item.Status
|
||||
versionInfo, _ := openPitrixClient.GetVersion(item.VersionID)
|
||||
app.Version = versionInfo
|
||||
app.VersionId = item.VersionID
|
||||
runtimeInfo, _ := openPitrixClient.GetRuntime(item.RunTimeId)
|
||||
app.Runtime = runtimeInfo
|
||||
app.RuntimeId = item.RunTimeId
|
||||
appInfo, _, appId, _ := openPitrixClient.GetAppInfo(item.AppID)
|
||||
app.App = appInfo
|
||||
app.AppId = appId
|
||||
app.Description = item.Description
|
||||
|
||||
for _, cluster := range resp.ClusterSet {
|
||||
app, err := describeApplication(cluster)
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
return nil, err
|
||||
}
|
||||
result.Items = append(result.Items, app)
|
||||
}
|
||||
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
func GetApp(clusterId string) (*Application, error) {
|
||||
openPitrixClient, err := client.ClientSets().OpenPitrix()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
item, err := openPitrixClient.GetCluster(clusterId)
|
||||
|
||||
func describeApplication(cluster *pb.Cluster) (*Application, error) {
|
||||
op, err := cs.ClientSets().OpenPitrix()
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var app Application
|
||||
|
||||
app.Name = item.Name
|
||||
app.ClusterID = item.ClusterID
|
||||
app.UpdateTime = item.UpdateTime
|
||||
app.CreateTime = item.CreateTime
|
||||
app.Status = item.Status
|
||||
versionInfo, _ := openPitrixClient.GetVersion(item.VersionID)
|
||||
app.Version = versionInfo
|
||||
app.VersionId = item.VersionID
|
||||
|
||||
runtimeInfo, _ := openPitrixClient.GetRuntime(item.RunTimeId)
|
||||
app.Runtime = runtimeInfo
|
||||
app.RuntimeId = item.RunTimeId
|
||||
appInfo, repoId, appId, _ := openPitrixClient.GetAppInfo(item.AppID)
|
||||
app.App = appInfo
|
||||
app.AppId = appId
|
||||
app.Description = item.Description
|
||||
|
||||
app.RepoName, _ = openPitrixClient.GetRepo(repoId)
|
||||
|
||||
workloads, err := getWorkLoads(app.Runtime, item.ClusterRoleSets)
|
||||
app.Name = cluster.Name.Value
|
||||
app.Cluster = convertCluster(cluster)
|
||||
versionInfo, err := op.App().DescribeAppVersions(openpitrix.SystemContext(), &pb.DescribeAppVersionsRequest{VersionId: []string{cluster.GetVersionId().GetValue()}})
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
klog.Errorln(err)
|
||||
return nil, err
|
||||
}
|
||||
app.WorkLoads = workloads
|
||||
workloadLabels := getLabels(app.Runtime, app.WorkLoads)
|
||||
app.Services = getSvcs(app.Runtime, workloadLabels)
|
||||
app.Ingresses = getIng(app.Runtime, app.Services)
|
||||
|
||||
if len(versionInfo.AppVersionSet) > 0 {
|
||||
app.Version = convertAppVersion(versionInfo.AppVersionSet[0])
|
||||
}
|
||||
appInfo, err := op.App().DescribeApps(openpitrix.SystemContext(), &pb.DescribeAppsRequest{AppId: []string{cluster.GetAppId().GetValue()}, Limit: 1})
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
return nil, err
|
||||
}
|
||||
if len(appInfo.AppSet) > 0 {
|
||||
app.App = convertApp(appInfo.GetAppSet()[0])
|
||||
}
|
||||
return &app, nil
|
||||
}
|
||||
|
||||
func getWorkLoads(namespace string, clusterRoles []openpitrix.ClusterRole) (*workLoads, error) {
|
||||
func DescribeApplication(namespace string, clusterId string) (*Application, error) {
|
||||
|
||||
client, err := cs.ClientSets().OpenPitrix()
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
clusters, err := client.Cluster().DescribeClusters(openpitrix.SystemContext(), &pb.DescribeClustersRequest{ClusterId: []string{clusterId}, Limit: 1})
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var cluster *pb.Cluster
|
||||
if len(clusters.ClusterSet) > 0 {
|
||||
cluster = clusters.GetClusterSet()[0]
|
||||
} else {
|
||||
err := status.New(codes.NotFound, "resource not found").Err()
|
||||
klog.Errorln(err)
|
||||
return nil, err
|
||||
}
|
||||
app, err := describeApplication(cluster)
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
workloads, err := getWorkLoads(namespace, cluster.ClusterRoleSet)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
return nil, err
|
||||
}
|
||||
app.WorkLoads = workloads
|
||||
workloadLabels := getLabels(namespace, app.WorkLoads)
|
||||
app.Services = getSvcs(namespace, workloadLabels)
|
||||
app.Ingresses = getIng(namespace, app.Services)
|
||||
return app, nil
|
||||
}
|
||||
|
||||
func getWorkLoads(namespace string, clusterRoles []*pb.ClusterRole) (*workLoads, error) {
|
||||
|
||||
var works workLoads
|
||||
for _, clusterRole := range clusterRoles {
|
||||
workLoadName := clusterRole.Role
|
||||
workLoadName := clusterRole.Role.Value
|
||||
if len(workLoadName) > 0 {
|
||||
if strings.HasSuffix(workLoadName, openpitrix.DeploySuffix) {
|
||||
name := strings.Split(workLoadName, openpitrix.DeploySuffix)[0]
|
||||
@@ -159,7 +185,7 @@ func getWorkLoads(namespace string, clusterRoles []openpitrix.ClusterRole) (*wor
|
||||
if errors.IsNotFound(err) {
|
||||
continue
|
||||
}
|
||||
klog.Error(err)
|
||||
klog.Errorln(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -175,7 +201,7 @@ func getWorkLoads(namespace string, clusterRoles []openpitrix.ClusterRole) (*wor
|
||||
if errors.IsNotFound(err) {
|
||||
continue
|
||||
}
|
||||
klog.Error(err)
|
||||
klog.Errorln(err)
|
||||
return nil, err
|
||||
}
|
||||
works.Daemonsets = append(works.Daemonsets, *item)
|
||||
@@ -190,7 +216,7 @@ func getWorkLoads(namespace string, clusterRoles []openpitrix.ClusterRole) (*wor
|
||||
if errors.IsNotFound(err) {
|
||||
continue
|
||||
}
|
||||
klog.Error(err)
|
||||
klog.Errorln(err)
|
||||
return nil, err
|
||||
}
|
||||
works.Statefulsets = append(works.Statefulsets, *item)
|
||||
@@ -202,9 +228,9 @@ func getWorkLoads(namespace string, clusterRoles []openpitrix.ClusterRole) (*wor
|
||||
}
|
||||
|
||||
func getLabels(namespace string, workloads *workLoads) *[]map[string]string {
|
||||
k8sClient := client.ClientSets().K8s().Kubernetes()
|
||||
k8sClient := cs.ClientSets().K8s().Kubernetes()
|
||||
|
||||
var workloadLables []map[string]string
|
||||
var workloadLabels []map[string]string
|
||||
if workloads == nil {
|
||||
return nil
|
||||
}
|
||||
@@ -214,7 +240,7 @@ func getLabels(namespace string, workloads *workLoads) *[]map[string]string {
|
||||
if errors.IsNotFound(err) {
|
||||
continue
|
||||
}
|
||||
workloadLables = append(workloadLables, deploy.Labels)
|
||||
workloadLabels = append(workloadLabels, deploy.Labels)
|
||||
}
|
||||
|
||||
for _, workload := range workloads.Daemonsets {
|
||||
@@ -222,7 +248,7 @@ func getLabels(namespace string, workloads *workLoads) *[]map[string]string {
|
||||
if errors.IsNotFound(err) {
|
||||
continue
|
||||
}
|
||||
workloadLables = append(workloadLables, daemonset.Labels)
|
||||
workloadLabels = append(workloadLabels, daemonset.Labels)
|
||||
}
|
||||
|
||||
for _, workload := range workloads.Statefulsets {
|
||||
@@ -230,10 +256,10 @@ func getLabels(namespace string, workloads *workLoads) *[]map[string]string {
|
||||
if errors.IsNotFound(err) {
|
||||
continue
|
||||
}
|
||||
workloadLables = append(workloadLables, statefulset.Labels)
|
||||
workloadLabels = append(workloadLabels, statefulset.Labels)
|
||||
}
|
||||
|
||||
return &workloadLables
|
||||
return &workloadLabels
|
||||
}
|
||||
|
||||
func isExist(svcs []v1.Service, svc v1.Service) bool {
|
||||
@@ -249,7 +275,7 @@ func getSvcs(namespace string, workLoadLabels *[]map[string]string) []v1.Service
|
||||
if len(*workLoadLabels) == 0 {
|
||||
return nil
|
||||
}
|
||||
k8sClient := client.ClientSets().K8s().Kubernetes()
|
||||
k8sClient := cs.ClientSets().K8s().Kubernetes()
|
||||
var services []v1.Service
|
||||
for _, label := range *workLoadLabels {
|
||||
labelSelector := labels.Set(label).AsSelector().String()
|
||||
@@ -276,11 +302,10 @@ func getIng(namespace string, services []v1.Service) []v1beta1.Ingress {
|
||||
for _, svc := range services {
|
||||
result, err := resources.ListResources(namespace, "ingress", ¶ms.Conditions{Fuzzy: map[string]string{"serviceName": svc.Name}}, "", false, -1, 0)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
klog.Errorln(err)
|
||||
return nil
|
||||
}
|
||||
|
||||
klog.Error(result)
|
||||
for _, i := range result.Items {
|
||||
ingress := i.(*v1beta1.Ingress)
|
||||
|
||||
@@ -308,31 +333,80 @@ func getIng(namespace string, services []v1.Service) []v1beta1.Ingress {
|
||||
return ings
|
||||
}
|
||||
|
||||
func DeployApplication(namespace string, app openpitrix.CreateClusterRequest) error {
|
||||
openPitrixClient, err := client.ClientSets().OpenPitrix()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
func CreateApplication(namespace string, request CreateClusterRequest) error {
|
||||
ns, err := informers.SharedInformerFactory().Core().V1().Namespaces().Lister().Get(namespace)
|
||||
if err != nil {
|
||||
klog.Errorf("deploy application failed: %+v", err)
|
||||
klog.Error(err)
|
||||
return err
|
||||
}
|
||||
|
||||
if runtimeId := ns.Annotations[constants.OpenPitrixRuntimeAnnotationKey]; runtimeId != "" {
|
||||
app.RuntimeId = runtimeId
|
||||
request.RuntimeId = runtimeId
|
||||
} else {
|
||||
return fmt.Errorf("runtime not init: namespace %s", namespace)
|
||||
}
|
||||
return openPitrixClient.CreateCluster(app)
|
||||
}
|
||||
|
||||
func DeleteApplication(clusterId string) error {
|
||||
openPitrixClient, err := client.ClientSets().OpenPitrix()
|
||||
client, err := cs.ClientSets().OpenPitrix()
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return err
|
||||
}
|
||||
|
||||
return openPitrixClient.DeleteCluster(openpitrix.DeleteClusterRequest{ClusterId: []string{clusterId}})
|
||||
_, err = client.Cluster().CreateCluster(openpitrix.ContextWithUsername(request.Username), &pb.CreateClusterRequest{
|
||||
AppId: &wrappers.StringValue{Value: request.AppId},
|
||||
VersionId: &wrappers.StringValue{Value: request.VersionId},
|
||||
RuntimeId: &wrappers.StringValue{Value: request.RuntimeId},
|
||||
Conf: &wrappers.StringValue{Value: request.Conf},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func PatchApplication(request *ModifyClusterAttributesRequest) error {
|
||||
op, err := cs.ClientSets().OpenPitrix()
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return err
|
||||
}
|
||||
|
||||
modifyClusterAttributesRequest := &pb.ModifyClusterAttributesRequest{ClusterId: &wrappers.StringValue{Value: request.ClusterID}}
|
||||
if request.Name != nil {
|
||||
modifyClusterAttributesRequest.Name = &wrappers.StringValue{Value: *request.Name}
|
||||
}
|
||||
if request.Description != nil {
|
||||
modifyClusterAttributesRequest.Description = &wrappers.StringValue{Value: *request.Description}
|
||||
}
|
||||
|
||||
_, err = op.Cluster().ModifyClusterAttributes(openpitrix.SystemContext(), modifyClusterAttributesRequest)
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeleteApplication(clusterId string) error {
|
||||
client, err := cs.ClientSets().OpenPitrix()
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = client.Cluster().DeleteClusters(openpitrix.SystemContext(), &pb.DeleteClustersRequest{ClusterId: []string{clusterId}, Force: &wrappers.BoolValue{Value: true}})
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln(err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
680
pkg/models/openpitrix/apps.go
Normal file
680
pkg/models/openpitrix/apps.go
Normal file
@@ -0,0 +1,680 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2019 The KubeSphere Authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* /
|
||||
*/
|
||||
|
||||
package openpitrix
|
||||
|
||||
import (
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/golang/protobuf/ptypes/wrappers"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"k8s.io/klog"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
"kubesphere.io/kubesphere/pkg/server/params"
|
||||
cs "kubesphere.io/kubesphere/pkg/simple/client"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/openpitrix"
|
||||
"openpitrix.io/openpitrix/pkg/pb"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func ListApps(conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {
|
||||
client, err := cs.ClientSets().OpenPitrix()
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
describeAppsRequest := &pb.DescribeAppsRequest{}
|
||||
if keyword := conditions.Match["keyword"]; keyword != "" {
|
||||
describeAppsRequest.SearchWord = &wrappers.StringValue{Value: keyword}
|
||||
}
|
||||
if appId := conditions.Match["app_id"]; appId != "" {
|
||||
describeAppsRequest.AppId = strings.Split(appId, "|")
|
||||
}
|
||||
if isv := conditions.Match["isv"]; isv != "" {
|
||||
describeAppsRequest.Isv = strings.Split(isv, "|")
|
||||
}
|
||||
if categoryId := conditions.Match["category_id"]; categoryId != "" {
|
||||
describeAppsRequest.CategoryId = strings.Split(categoryId, "|")
|
||||
}
|
||||
if repoId := conditions.Match["repo"]; repoId != "" {
|
||||
describeAppsRequest.RepoId = strings.Split(repoId, "|")
|
||||
}
|
||||
if status := conditions.Match["status"]; status != "" {
|
||||
describeAppsRequest.Status = strings.Split(status, "|")
|
||||
}
|
||||
if orderBy != "" {
|
||||
describeAppsRequest.SortKey = &wrappers.StringValue{Value: orderBy}
|
||||
}
|
||||
describeAppsRequest.Reverse = &wrappers.BoolValue{Value: reverse}
|
||||
describeAppsRequest.Limit = uint32(limit)
|
||||
describeAppsRequest.Offset = uint32(offset)
|
||||
resp, err := client.App().DescribeApps(openpitrix.SystemContext(), describeAppsRequest)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
items := make([]interface{}, 0)
|
||||
|
||||
for _, item := range resp.AppSet {
|
||||
items = append(items, convertApp(item))
|
||||
}
|
||||
|
||||
return &models.PageableResponse{Items: items, TotalCount: int(resp.TotalCount)}, nil
|
||||
}
|
||||
|
||||
func DescribeApp(id string) (*App, error) {
|
||||
op, err := cs.ClientSets().OpenPitrix()
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
resp, err := op.App().DescribeApps(openpitrix.SystemContext(), &pb.DescribeAppsRequest{
|
||||
AppId: []string{id},
|
||||
Limit: 1,
|
||||
})
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var app *App
|
||||
|
||||
if len(resp.AppSet) > 0 {
|
||||
app = convertApp(resp.AppSet[0])
|
||||
return app, nil
|
||||
} else {
|
||||
err := status.New(codes.NotFound, "resource not found").Err()
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
func DeleteApp(id string) error {
|
||||
op, err := cs.ClientSets().OpenPitrix()
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return err
|
||||
}
|
||||
_, err = op.App().DeleteApps(openpitrix.SystemContext(), &pb.DeleteAppsRequest{
|
||||
AppId: []string{id},
|
||||
})
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func CreateApp(request *CreateAppRequest) (*CreateAppResponse, error) {
|
||||
op, err := cs.ClientSets().OpenPitrix()
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
createAppRequest := &pb.CreateAppRequest{
|
||||
Name: &wrappers.StringValue{Value: request.Name},
|
||||
VersionType: &wrappers.StringValue{Value: request.VersionType},
|
||||
VersionName: &wrappers.StringValue{Value: request.VersionName},
|
||||
}
|
||||
if request.VersionPackage != nil {
|
||||
createAppRequest.VersionPackage = &wrappers.BytesValue{Value: request.VersionPackage}
|
||||
}
|
||||
if request.Icon != nil {
|
||||
createAppRequest.Icon = &wrappers.BytesValue{Value: request.Icon}
|
||||
}
|
||||
if request.Isv != "" {
|
||||
createAppRequest.Isv = &wrappers.StringValue{Value: request.Isv}
|
||||
}
|
||||
resp, err := op.App().CreateApp(openpitrix.SystemContext(), createAppRequest)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
return &CreateAppResponse{
|
||||
AppID: resp.GetAppId().GetValue(),
|
||||
VersionID: resp.GetVersionId().GetValue(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func PatchApp(appId string, request *ModifyAppRequest) error {
|
||||
client, err := cs.ClientSets().OpenPitrix()
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return err
|
||||
}
|
||||
|
||||
// upload app attachment
|
||||
if request.AttachmentContent != nil {
|
||||
uploadAttachmentRequest := &pb.UploadAppAttachmentRequest{
|
||||
AppId: &wrappers.StringValue{Value: appId},
|
||||
AttachmentContent: &wrappers.BytesValue{Value: request.AttachmentContent},
|
||||
}
|
||||
if request.Type != nil {
|
||||
uploadAttachmentRequest.Type = pb.UploadAppAttachmentRequest_Type(pb.UploadAppAttachmentRequest_Type_value[*request.Type])
|
||||
}
|
||||
if request.Sequence != nil {
|
||||
uploadAttachmentRequest.Sequence = &wrappers.UInt32Value{Value: uint32(*request.Sequence)}
|
||||
}
|
||||
|
||||
_, err := client.App().UploadAppAttachment(openpitrix.SystemContext(), uploadAttachmentRequest)
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return err
|
||||
}
|
||||
// patch app
|
||||
} else {
|
||||
patchAppRequest := &pb.ModifyAppRequest{
|
||||
AppId: &wrappers.StringValue{Value: appId},
|
||||
}
|
||||
|
||||
if request.Abstraction != nil {
|
||||
patchAppRequest.Abstraction = &wrappers.StringValue{Value: *request.Abstraction}
|
||||
}
|
||||
if request.CategoryID != nil {
|
||||
patchAppRequest.CategoryId = &wrappers.StringValue{Value: *request.CategoryID}
|
||||
}
|
||||
if request.Description != nil {
|
||||
patchAppRequest.Description = &wrappers.StringValue{Value: *request.Description}
|
||||
}
|
||||
if request.Home != nil {
|
||||
patchAppRequest.Home = &wrappers.StringValue{Value: *request.Home}
|
||||
}
|
||||
if request.Keywords != nil {
|
||||
patchAppRequest.Keywords = &wrappers.StringValue{Value: *request.Keywords}
|
||||
}
|
||||
if request.Maintainers != nil {
|
||||
patchAppRequest.Maintainers = &wrappers.StringValue{Value: *request.Maintainers}
|
||||
}
|
||||
if request.Name != nil {
|
||||
patchAppRequest.Name = &wrappers.StringValue{Value: *request.Name}
|
||||
}
|
||||
if request.Readme != nil {
|
||||
patchAppRequest.Readme = &wrappers.StringValue{Value: *request.Readme}
|
||||
}
|
||||
if request.Sources != nil {
|
||||
patchAppRequest.Sources = &wrappers.StringValue{Value: *request.Sources}
|
||||
}
|
||||
if request.Tos != nil {
|
||||
patchAppRequest.Tos = &wrappers.StringValue{Value: *request.Tos}
|
||||
}
|
||||
|
||||
_, err = client.App().ModifyApp(openpitrix.SystemContext(), patchAppRequest)
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func CreateAppVersion(request *CreateAppVersionRequest) (*CreateAppVersionResponse, error) {
|
||||
op, err := cs.ClientSets().OpenPitrix()
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
createAppVersionRequest := &pb.CreateAppVersionRequest{
|
||||
AppId: &wrappers.StringValue{Value: request.AppId},
|
||||
Name: &wrappers.StringValue{Value: request.Name},
|
||||
Description: &wrappers.StringValue{Value: request.Description},
|
||||
Type: &wrappers.StringValue{Value: request.Type},
|
||||
}
|
||||
|
||||
if request.Package != nil {
|
||||
createAppVersionRequest.Package = &wrappers.BytesValue{Value: request.Package}
|
||||
}
|
||||
|
||||
resp, err := op.App().CreateAppVersion(openpitrix.SystemContext(), createAppVersionRequest)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
return &CreateAppVersionResponse{
|
||||
VersionId: resp.GetVersionId().GetValue(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func ValidatePackage(request *ValidatePackageRequest) (*ValidatePackageResponse, error) {
|
||||
client, err := cs.ClientSets().OpenPitrix()
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
r := &pb.ValidatePackageRequest{}
|
||||
|
||||
if request.VersionPackage != nil {
|
||||
r.VersionPackage = request.VersionPackage
|
||||
}
|
||||
if request.VersionType != "" {
|
||||
r.VersionType = request.VersionType
|
||||
}
|
||||
|
||||
resp, err := client.App().ValidatePackage(openpitrix.SystemContext(), r)
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := &ValidatePackageResponse{}
|
||||
|
||||
if resp.Error != nil {
|
||||
result.Error = resp.Error.Value
|
||||
}
|
||||
if resp.Description != nil {
|
||||
result.Description = resp.Description.Value
|
||||
}
|
||||
if resp.Error != nil {
|
||||
result.Error = resp.Error.Value
|
||||
}
|
||||
if resp.ErrorDetails != nil {
|
||||
result.ErrorDetails = resp.ErrorDetails
|
||||
}
|
||||
if resp.Name != nil {
|
||||
result.Name = resp.Name.Value
|
||||
}
|
||||
if resp.Url != nil {
|
||||
result.URL = resp.Url.Value
|
||||
}
|
||||
if resp.VersionName != nil {
|
||||
result.VersionName = resp.VersionName.Value
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func DeleteAppVersion(id string) error {
|
||||
op, err := cs.ClientSets().OpenPitrix()
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return err
|
||||
}
|
||||
_, err = op.App().DeleteAppVersion(openpitrix.SystemContext(), &pb.DeleteAppVersionRequest{
|
||||
VersionId: &wrappers.StringValue{Value: id},
|
||||
})
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func PatchAppVersion(id string, request *ModifyAppVersionRequest) error {
|
||||
op, err := cs.ClientSets().OpenPitrix()
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return err
|
||||
}
|
||||
modifyAppVersionRequest := &pb.ModifyAppVersionRequest{
|
||||
VersionId: &wrappers.StringValue{Value: id},
|
||||
}
|
||||
|
||||
if request.Name != nil {
|
||||
modifyAppVersionRequest.Name = &wrappers.StringValue{Value: *request.Name}
|
||||
}
|
||||
if request.Description != nil {
|
||||
modifyAppVersionRequest.Description = &wrappers.StringValue{Value: *request.Description}
|
||||
}
|
||||
if request.Package != nil {
|
||||
modifyAppVersionRequest.Package = &wrappers.BytesValue{Value: request.Package}
|
||||
}
|
||||
if request.PackageFiles != nil {
|
||||
modifyAppVersionRequest.PackageFiles = request.PackageFiles
|
||||
}
|
||||
|
||||
_, err = op.App().ModifyAppVersion(openpitrix.SystemContext(), modifyAppVersionRequest)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DescribeAppVersion(id string) (*AppVersion, error) {
|
||||
op, err := cs.ClientSets().OpenPitrix()
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
resp, err := op.App().DescribeAppVersions(openpitrix.SystemContext(), &pb.DescribeAppVersionsRequest{
|
||||
VersionId: []string{id},
|
||||
Limit: 1,
|
||||
})
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var app *AppVersion
|
||||
|
||||
if len(resp.AppVersionSet) > 0 {
|
||||
app = convertAppVersion(resp.AppVersionSet[0])
|
||||
return app, nil
|
||||
} else {
|
||||
err := status.New(codes.NotFound, "resource not found").Err()
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
func GetAppVersionPackage(appId, versionId string) (*GetAppVersionPackageResponse, error) {
|
||||
op, err := cs.ClientSets().OpenPitrix()
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
resp, err := op.App().GetAppVersionPackage(openpitrix.SystemContext(), &pb.GetAppVersionPackageRequest{
|
||||
VersionId: &wrappers.StringValue{Value: versionId},
|
||||
})
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
app := &GetAppVersionPackageResponse{
|
||||
AppId: appId,
|
||||
VersionId: versionId,
|
||||
}
|
||||
|
||||
if resp.Package != nil {
|
||||
app.Package = resp.Package
|
||||
}
|
||||
|
||||
return app, nil
|
||||
}
|
||||
|
||||
func DoAppAction(appId string, request *ActionRequest) error {
|
||||
op, err := cs.ClientSets().OpenPitrix()
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return err
|
||||
}
|
||||
|
||||
switch request.Action {
|
||||
|
||||
case "recover":
|
||||
// TODO openpitrix need to implement app recover interface
|
||||
resp, err := op.App().DescribeAppVersions(openpitrix.SystemContext(), &pb.DescribeAppVersionsRequest{
|
||||
AppId: []string{appId},
|
||||
Status: []string{"suspended"},
|
||||
Limit: 200,
|
||||
Offset: 0,
|
||||
})
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return err
|
||||
}
|
||||
for _, version := range resp.AppVersionSet {
|
||||
|
||||
_, err = op.App().RecoverAppVersion(openpitrix.SystemContext(), &pb.RecoverAppVersionRequest{
|
||||
VersionId: version.VersionId,
|
||||
})
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
case "suspend":
|
||||
// TODO openpitrix need to implement app suspend interface
|
||||
resp, err := op.App().DescribeAppVersions(openpitrix.SystemContext(), &pb.DescribeAppVersionsRequest{
|
||||
AppId: []string{appId},
|
||||
Status: []string{"active"},
|
||||
Limit: 200,
|
||||
Offset: 0,
|
||||
})
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return err
|
||||
}
|
||||
for _, version := range resp.AppVersionSet {
|
||||
_, err = op.App().SuspendAppVersion(openpitrix.SystemContext(), &pb.SuspendAppVersionRequest{
|
||||
VersionId: version.VersionId,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
err = status.New(codes.InvalidArgument, "action not support").Err()
|
||||
klog.Error(err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func DoAppVersionAction(versionId string, request *ActionRequest) error {
|
||||
op, err := cs.ClientSets().OpenPitrix()
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return err
|
||||
}
|
||||
|
||||
switch request.Action {
|
||||
case "cancel":
|
||||
_, err = op.App().CancelAppVersion(openpitrix.ContextWithUsername(request.Username), &pb.CancelAppVersionRequest{
|
||||
VersionId: &wrappers.StringValue{Value: versionId},
|
||||
})
|
||||
case "pass":
|
||||
_, err = op.App().AdminPassAppVersion(openpitrix.ContextWithUsername(request.Username), &pb.PassAppVersionRequest{
|
||||
VersionId: &wrappers.StringValue{Value: versionId},
|
||||
})
|
||||
case "recover":
|
||||
_, err = op.App().RecoverAppVersion(openpitrix.ContextWithUsername(request.Username), &pb.RecoverAppVersionRequest{
|
||||
VersionId: &wrappers.StringValue{Value: versionId},
|
||||
})
|
||||
case "reject":
|
||||
_, err = op.App().AdminRejectAppVersion(openpitrix.ContextWithUsername(request.Username), &pb.RejectAppVersionRequest{
|
||||
VersionId: &wrappers.StringValue{Value: versionId},
|
||||
Message: &wrappers.StringValue{Value: request.Message},
|
||||
})
|
||||
case "submit":
|
||||
_, err = op.App().SubmitAppVersion(openpitrix.ContextWithUsername(request.Username), &pb.SubmitAppVersionRequest{
|
||||
VersionId: &wrappers.StringValue{Value: versionId},
|
||||
})
|
||||
case "suspend":
|
||||
_, err = op.App().SuspendAppVersion(openpitrix.ContextWithUsername(request.Username), &pb.SuspendAppVersionRequest{
|
||||
VersionId: &wrappers.StringValue{Value: versionId},
|
||||
})
|
||||
case "release":
|
||||
_, err = op.App().ReleaseAppVersion(openpitrix.ContextWithUsername(request.Username), &pb.ReleaseAppVersionRequest{
|
||||
VersionId: &wrappers.StringValue{Value: versionId},
|
||||
})
|
||||
default:
|
||||
err = status.New(codes.InvalidArgument, "action not support").Err()
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetAppVersionFiles(versionId string, request *GetAppVersionFilesRequest) (*GetAppVersionPackageFilesResponse, error) {
|
||||
op, err := cs.ClientSets().OpenPitrix()
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
getAppVersionPackageFilesRequest := &pb.GetAppVersionPackageFilesRequest{
|
||||
VersionId: &wrappers.StringValue{Value: versionId},
|
||||
}
|
||||
if request.Files != nil {
|
||||
getAppVersionPackageFilesRequest.Files = request.Files
|
||||
}
|
||||
|
||||
resp, err := op.App().GetAppVersionPackageFiles(openpitrix.SystemContext(), getAppVersionPackageFilesRequest)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
version := &GetAppVersionPackageFilesResponse{
|
||||
VersionId: versionId,
|
||||
}
|
||||
|
||||
if resp.Files != nil {
|
||||
version.Files = make(map[string]strfmt.Base64)
|
||||
for k, v := range resp.Files {
|
||||
version.Files[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
return version, nil
|
||||
}
|
||||
|
||||
func ListAppVersionAudits(conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {
|
||||
client, err := cs.ClientSets().OpenPitrix()
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
describeAppVersionAudits := &pb.DescribeAppVersionAuditsRequest{}
|
||||
|
||||
if keyword := conditions.Match["keyword"]; keyword != "" {
|
||||
describeAppVersionAudits.SearchWord = &wrappers.StringValue{Value: keyword}
|
||||
}
|
||||
if appId := conditions.Match["app"]; appId != "" {
|
||||
describeAppVersionAudits.AppId = []string{appId}
|
||||
}
|
||||
if versionId := conditions.Match["version"]; versionId != "" {
|
||||
describeAppVersionAudits.VersionId = []string{versionId}
|
||||
}
|
||||
if status := conditions.Match["status"]; status != "" {
|
||||
describeAppVersionAudits.Status = strings.Split(status, "|")
|
||||
}
|
||||
if orderBy != "" {
|
||||
describeAppVersionAudits.SortKey = &wrappers.StringValue{Value: orderBy}
|
||||
}
|
||||
describeAppVersionAudits.Reverse = &wrappers.BoolValue{Value: reverse}
|
||||
describeAppVersionAudits.Limit = uint32(limit)
|
||||
describeAppVersionAudits.Offset = uint32(offset)
|
||||
resp, err := client.App().DescribeAppVersionAudits(openpitrix.SystemContext(), describeAppVersionAudits)
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
items := make([]interface{}, 0)
|
||||
|
||||
for _, item := range resp.AppVersionAuditSet {
|
||||
appVersion := convertAppVersionAudit(item)
|
||||
items = append(items, appVersion)
|
||||
}
|
||||
|
||||
return &models.PageableResponse{Items: items, TotalCount: int(resp.TotalCount)}, nil
|
||||
}
|
||||
|
||||
func ListAppVersionReviews(conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {
|
||||
client, err := cs.ClientSets().OpenPitrix()
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
describeAppVersionReviews := &pb.DescribeAppVersionReviewsRequest{}
|
||||
|
||||
if keyword := conditions.Match["keyword"]; keyword != "" {
|
||||
describeAppVersionReviews.SearchWord = &wrappers.StringValue{Value: keyword}
|
||||
}
|
||||
if status := conditions.Match["status"]; status != "" {
|
||||
describeAppVersionReviews.Status = strings.Split(status, "|")
|
||||
}
|
||||
if orderBy != "" {
|
||||
describeAppVersionReviews.SortKey = &wrappers.StringValue{Value: orderBy}
|
||||
}
|
||||
describeAppVersionReviews.Reverse = &wrappers.BoolValue{Value: reverse}
|
||||
describeAppVersionReviews.Limit = uint32(limit)
|
||||
describeAppVersionReviews.Offset = uint32(offset)
|
||||
// TODO icon is needed
|
||||
resp, err := client.App().DescribeAppVersionReviews(openpitrix.SystemContext(), describeAppVersionReviews)
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
items := make([]interface{}, 0)
|
||||
|
||||
for _, item := range resp.AppVersionReviewSet {
|
||||
appVersion := convertAppVersionReview(item)
|
||||
items = append(items, appVersion)
|
||||
}
|
||||
|
||||
return &models.PageableResponse{Items: items, TotalCount: int(resp.TotalCount)}, nil
|
||||
}
|
||||
|
||||
func ListAppVersions(conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {
|
||||
client, err := cs.ClientSets().OpenPitrix()
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
describeAppVersionsRequest := &pb.DescribeAppVersionsRequest{}
|
||||
|
||||
if keyword := conditions.Match["keyword"]; keyword != "" {
|
||||
describeAppVersionsRequest.SearchWord = &wrappers.StringValue{Value: keyword}
|
||||
}
|
||||
if appId := conditions.Match["app"]; appId != "" {
|
||||
describeAppVersionsRequest.AppId = []string{appId}
|
||||
}
|
||||
if status := conditions.Match["status"]; status != "" {
|
||||
describeAppVersionsRequest.Status = strings.Split(status, "|")
|
||||
}
|
||||
if orderBy != "" {
|
||||
describeAppVersionsRequest.SortKey = &wrappers.StringValue{Value: orderBy}
|
||||
}
|
||||
describeAppVersionsRequest.Reverse = &wrappers.BoolValue{Value: reverse}
|
||||
describeAppVersionsRequest.Limit = uint32(limit)
|
||||
describeAppVersionsRequest.Offset = uint32(offset)
|
||||
resp, err := client.App().DescribeAppVersions(openpitrix.SystemContext(), describeAppVersionsRequest)
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
items := make([]interface{}, 0)
|
||||
|
||||
for _, item := range resp.AppVersionSet {
|
||||
appVersion := convertAppVersion(item)
|
||||
items = append(items, appVersion)
|
||||
}
|
||||
|
||||
return &models.PageableResponse{Items: items, TotalCount: int(resp.TotalCount)}, nil
|
||||
}
|
||||
50
pkg/models/openpitrix/attachments.go
Normal file
50
pkg/models/openpitrix/attachments.go
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2019 The KubeSphere Authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* /
|
||||
*/
|
||||
|
||||
package openpitrix
|
||||
|
||||
import (
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"k8s.io/klog"
|
||||
cs "kubesphere.io/kubesphere/pkg/simple/client"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/openpitrix"
|
||||
"openpitrix.io/openpitrix/pkg/pb"
|
||||
)
|
||||
|
||||
func DescribeAttachment(id string) (*Attachment, error) {
|
||||
op, err := cs.ClientSets().OpenPitrix()
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
resp, err := op.Attachment().GetAttachments(openpitrix.SystemContext(), &pb.GetAttachmentsRequest{
|
||||
AttachmentId: []string{id},
|
||||
})
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
if len(resp.Attachments) > 0 {
|
||||
return convertAttachment(resp.Attachments[id]), nil
|
||||
} else {
|
||||
err := status.New(codes.NotFound, "resource not found").Err()
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
163
pkg/models/openpitrix/categories.go
Normal file
163
pkg/models/openpitrix/categories.go
Normal file
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2019 The KubeSphere Authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* /
|
||||
*/
|
||||
|
||||
package openpitrix
|
||||
|
||||
import (
|
||||
"github.com/golang/protobuf/ptypes/wrappers"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"k8s.io/klog"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
"kubesphere.io/kubesphere/pkg/server/params"
|
||||
cs "kubesphere.io/kubesphere/pkg/simple/client"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/openpitrix"
|
||||
"openpitrix.io/openpitrix/pkg/pb"
|
||||
)
|
||||
|
||||
func CreateCategory(request *CreateCategoryRequest) (*CreateCategoryResponse, error) {
|
||||
op, err := cs.ClientSets().OpenPitrix()
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
r := &pb.CreateCategoryRequest{
|
||||
Name: &wrappers.StringValue{Value: request.Name},
|
||||
Locale: &wrappers.StringValue{Value: request.Locale},
|
||||
Description: &wrappers.StringValue{Value: request.Description},
|
||||
}
|
||||
if request.Icon != nil {
|
||||
r.Icon = &wrappers.BytesValue{Value: request.Icon}
|
||||
}
|
||||
|
||||
resp, err := op.Category().CreateCategory(openpitrix.SystemContext(), r)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
return &CreateCategoryResponse{
|
||||
CategoryId: resp.GetCategoryId().GetValue(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func DeleteCategory(id string) error {
|
||||
op, err := cs.ClientSets().OpenPitrix()
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return err
|
||||
}
|
||||
_, err = op.Category().DeleteCategories(openpitrix.SystemContext(), &pb.DeleteCategoriesRequest{
|
||||
CategoryId: []string{id},
|
||||
})
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func PatchCategory(id string, request *ModifyCategoryRequest) error {
|
||||
op, err := cs.ClientSets().OpenPitrix()
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return err
|
||||
}
|
||||
modifyCategoryRequest := &pb.ModifyCategoryRequest{
|
||||
CategoryId: &wrappers.StringValue{Value: id},
|
||||
}
|
||||
if request.Name != nil {
|
||||
modifyCategoryRequest.Name = &wrappers.StringValue{Value: *request.Name}
|
||||
}
|
||||
if request.Locale != nil {
|
||||
modifyCategoryRequest.Locale = &wrappers.StringValue{Value: *request.Locale}
|
||||
}
|
||||
if request.Description != nil {
|
||||
modifyCategoryRequest.Description = &wrappers.StringValue{Value: *request.Description}
|
||||
}
|
||||
if request.Icon != nil {
|
||||
modifyCategoryRequest.Icon = &wrappers.BytesValue{Value: request.Icon}
|
||||
}
|
||||
|
||||
_, err = op.Category().ModifyCategory(openpitrix.SystemContext(), modifyCategoryRequest)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DescribeCategory(id string) (*Category, error) {
|
||||
op, err := cs.ClientSets().OpenPitrix()
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
resp, err := op.Category().DescribeCategories(openpitrix.SystemContext(), &pb.DescribeCategoriesRequest{
|
||||
CategoryId: []string{id},
|
||||
Limit: 1,
|
||||
})
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var category *Category
|
||||
|
||||
if len(resp.CategorySet) > 0 {
|
||||
category = convertCategory(resp.CategorySet[0])
|
||||
return category, nil
|
||||
} else {
|
||||
err := status.New(codes.NotFound, "resource not found").Err()
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
func ListCategories(conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {
|
||||
client, err := cs.ClientSets().OpenPitrix()
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req := &pb.DescribeCategoriesRequest{}
|
||||
|
||||
if keyword := conditions.Match["keyword"]; keyword != "" {
|
||||
req.SearchWord = &wrappers.StringValue{Value: keyword}
|
||||
}
|
||||
if orderBy != "" {
|
||||
req.SortKey = &wrappers.StringValue{Value: orderBy}
|
||||
}
|
||||
req.Reverse = &wrappers.BoolValue{Value: reverse}
|
||||
req.Limit = uint32(limit)
|
||||
req.Offset = uint32(offset)
|
||||
resp, err := client.Category().DescribeCategories(openpitrix.SystemContext(), req)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
items := make([]interface{}, 0)
|
||||
|
||||
for _, item := range resp.CategorySet {
|
||||
items = append(items, convertCategory(item))
|
||||
}
|
||||
|
||||
return &models.PageableResponse{Items: items, TotalCount: int(resp.TotalCount)}, nil
|
||||
}
|
||||
647
pkg/models/openpitrix/convert.go
Normal file
647
pkg/models/openpitrix/convert.go
Normal file
@@ -0,0 +1,647 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2019 The KubeSphere Authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* /
|
||||
*/
|
||||
|
||||
package openpitrix
|
||||
|
||||
import (
|
||||
"github.com/go-openapi/strfmt"
|
||||
"openpitrix.io/openpitrix/pkg/pb"
|
||||
"time"
|
||||
)
|
||||
|
||||
func convertApp(in *pb.App) *App {
|
||||
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
categorySet := make(AppCategorySet, 0)
|
||||
|
||||
for _, item := range in.CategorySet {
|
||||
category := convertResourceCategory(item)
|
||||
categorySet = append(categorySet, category)
|
||||
}
|
||||
|
||||
out := App{
|
||||
CategorySet: categorySet,
|
||||
}
|
||||
|
||||
if in.Abstraction != nil {
|
||||
out.Abstraction = in.Abstraction.Value
|
||||
}
|
||||
if in.Active != nil {
|
||||
out.Active = in.Active.Value
|
||||
}
|
||||
if in.AppId != nil {
|
||||
out.AppId = in.AppId.Value
|
||||
}
|
||||
if in.AppVersionTypes != nil {
|
||||
out.AppVersionTypes = in.AppVersionTypes.Value
|
||||
}
|
||||
if in.ChartName != nil {
|
||||
out.ChartName = in.ChartName.Value
|
||||
}
|
||||
if in.CompanyJoinTime != nil {
|
||||
date := strfmt.DateTime(time.Unix(in.CompanyJoinTime.Seconds, 0))
|
||||
out.CompanyJoinTime = &date
|
||||
}
|
||||
if in.CompanyName != nil {
|
||||
out.CompanyName = in.CompanyName.Value
|
||||
}
|
||||
if in.CompanyProfile != nil {
|
||||
out.CompanyProfile = in.CompanyProfile.Value
|
||||
}
|
||||
if in.CompanyWebsite != nil {
|
||||
out.CompanyWebsite = in.CompanyWebsite.Value
|
||||
}
|
||||
if in.CreateTime != nil {
|
||||
date := strfmt.DateTime(time.Unix(in.CreateTime.Seconds, 0))
|
||||
out.CreateTime = &date
|
||||
}
|
||||
if in.CompanyWebsite != nil {
|
||||
out.CompanyWebsite = in.CompanyWebsite.Value
|
||||
}
|
||||
if in.Description != nil {
|
||||
out.Description = in.Description.Value
|
||||
}
|
||||
if in.Home != nil {
|
||||
out.Home = in.Home.Value
|
||||
}
|
||||
if in.Icon != nil {
|
||||
out.Icon = in.Icon.Value
|
||||
}
|
||||
if in.Isv != nil {
|
||||
out.Isv = in.Isv.Value
|
||||
}
|
||||
if in.Keywords != nil {
|
||||
out.Keywords = in.Keywords.Value
|
||||
}
|
||||
if in.LatestAppVersion != nil {
|
||||
out.LatestAppVersion = convertAppVersion(in.LatestAppVersion)
|
||||
}
|
||||
if in.Name != nil {
|
||||
out.Name = in.Name.Value
|
||||
}
|
||||
if in.Owner != nil {
|
||||
out.Owner = in.Owner.Value
|
||||
}
|
||||
if in.Readme != nil {
|
||||
out.Readme = in.Readme.Value
|
||||
}
|
||||
if in.RepoId != nil {
|
||||
out.RepoId = in.RepoId.Value
|
||||
}
|
||||
if in.StatusTime != nil {
|
||||
date := strfmt.DateTime(time.Unix(in.StatusTime.Seconds, 0))
|
||||
out.StatusTime = &date
|
||||
}
|
||||
if in.Status != nil {
|
||||
out.Status = in.Status.Value
|
||||
}
|
||||
if in.Sources != nil {
|
||||
out.Sources = in.Sources.Value
|
||||
}
|
||||
if in.Screenshots != nil {
|
||||
out.Screenshots = in.Screenshots.Value
|
||||
}
|
||||
if in.Tos != nil {
|
||||
out.Tos = in.Tos.Value
|
||||
}
|
||||
if in.UpdateTime != nil {
|
||||
date := strfmt.DateTime(time.Unix(in.UpdateTime.Seconds, 0))
|
||||
out.UpdateTime = &date
|
||||
}
|
||||
|
||||
return &out
|
||||
}
|
||||
|
||||
func convertAppVersion(in *pb.AppVersion) *AppVersion {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := AppVersion{}
|
||||
if in.AppId != nil {
|
||||
out.AppId = in.AppId.Value
|
||||
}
|
||||
if in.Active != nil {
|
||||
out.Active = in.Active.Value
|
||||
}
|
||||
if in.CreateTime != nil {
|
||||
date := strfmt.DateTime(time.Unix(in.CreateTime.Seconds, 0))
|
||||
out.CreateTime = &date
|
||||
}
|
||||
if in.Description != nil {
|
||||
out.Description = in.Description.Value
|
||||
}
|
||||
if in.Home != nil {
|
||||
out.Home = in.Home.Value
|
||||
}
|
||||
if in.Icon != nil {
|
||||
out.Icon = in.Icon.Value
|
||||
}
|
||||
if in.Maintainers != nil {
|
||||
out.Maintainers = in.Maintainers.Value
|
||||
}
|
||||
if in.Message != nil {
|
||||
out.Message = in.Message.Value
|
||||
}
|
||||
if in.Keywords != nil {
|
||||
out.Keywords = in.Keywords.Value
|
||||
}
|
||||
if in.Name != nil {
|
||||
out.Name = in.Name.Value
|
||||
}
|
||||
if in.Owner != nil {
|
||||
out.Owner = in.Owner.Value
|
||||
}
|
||||
if in.PackageName != nil {
|
||||
out.PackageName = in.PackageName.Value
|
||||
}
|
||||
if in.Readme != nil {
|
||||
out.Readme = in.Readme.Value
|
||||
}
|
||||
if in.ReviewId != nil {
|
||||
out.ReviewId = in.ReviewId.Value
|
||||
}
|
||||
if in.Screenshots != nil {
|
||||
out.Screenshots = in.Screenshots.Value
|
||||
}
|
||||
if in.Sources != nil {
|
||||
out.Sources = in.Sources.Value
|
||||
}
|
||||
if in.Status != nil {
|
||||
out.Status = in.Status.Value
|
||||
}
|
||||
if in.Sequence != nil {
|
||||
out.Sequence = int64(in.Sequence.Value)
|
||||
}
|
||||
if in.StatusTime != nil {
|
||||
date := strfmt.DateTime(time.Unix(in.StatusTime.Seconds, 0))
|
||||
out.StatusTime = &date
|
||||
}
|
||||
if in.Type != nil {
|
||||
out.Type = in.Type.Value
|
||||
}
|
||||
if in.UpdateTime != nil {
|
||||
date := strfmt.DateTime(time.Unix(in.UpdateTime.Seconds, 0))
|
||||
out.UpdateTime = &date
|
||||
}
|
||||
if in.VersionId != nil {
|
||||
out.VersionId = in.VersionId.Value
|
||||
}
|
||||
|
||||
return &out
|
||||
|
||||
}
|
||||
|
||||
func convertResourceCategory(in *pb.ResourceCategory) *ResourceCategory {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := ResourceCategory{}
|
||||
|
||||
if in.CategoryId != nil {
|
||||
out.CategoryId = in.CategoryId.Value
|
||||
}
|
||||
if in.CreateTime != nil {
|
||||
date := strfmt.DateTime(time.Unix(in.CreateTime.Seconds, 0))
|
||||
out.CreateTime = &date
|
||||
}
|
||||
if in.Locale != nil {
|
||||
out.Locale = in.Locale.Value
|
||||
}
|
||||
if in.Name != nil {
|
||||
out.Name = in.Name.Value
|
||||
}
|
||||
if in.Status != nil {
|
||||
out.Status = in.Status.Value
|
||||
}
|
||||
if in.StatusTime != nil {
|
||||
date := strfmt.DateTime(time.Unix(in.StatusTime.Seconds, 0))
|
||||
out.StatusTime = &date
|
||||
}
|
||||
|
||||
return &out
|
||||
}
|
||||
|
||||
func convertCategory(in *pb.Category) *Category {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := Category{}
|
||||
|
||||
if in.CategoryId != nil {
|
||||
out.CategoryID = in.CategoryId.Value
|
||||
}
|
||||
if in.CreateTime != nil {
|
||||
date := strfmt.DateTime(time.Unix(in.CreateTime.Seconds, 0))
|
||||
out.CreateTime = &date
|
||||
}
|
||||
if in.Locale != nil {
|
||||
out.Locale = in.Locale.Value
|
||||
}
|
||||
if in.Name != nil {
|
||||
out.Name = in.Name.Value
|
||||
}
|
||||
if in.Description != nil {
|
||||
out.Description = in.Description.Value
|
||||
}
|
||||
if in.Icon != nil {
|
||||
out.Icon = in.Icon.Value
|
||||
}
|
||||
if in.Owner != nil {
|
||||
out.Owner = in.Owner.Value
|
||||
}
|
||||
if in.UpdateTime != nil {
|
||||
date := strfmt.DateTime(time.Unix(in.UpdateTime.Seconds, 0))
|
||||
out.UpdateTime = &date
|
||||
}
|
||||
|
||||
return &out
|
||||
}
|
||||
|
||||
func convertAttachment(in *pb.Attachment) *Attachment {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := Attachment{}
|
||||
|
||||
out.AttachmentID = in.AttachmentId
|
||||
|
||||
if in.CreateTime != nil {
|
||||
date := strfmt.DateTime(time.Unix(in.CreateTime.Seconds, 0))
|
||||
out.CreateTime = &date
|
||||
}
|
||||
if in.AttachmentContent != nil {
|
||||
out.AttachmentContent = make(map[string]strfmt.Base64)
|
||||
for k, v := range in.AttachmentContent {
|
||||
out.AttachmentContent[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
return &out
|
||||
}
|
||||
|
||||
func convertRepo(in *pb.Repo) *Repo {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := Repo{}
|
||||
|
||||
if in.RepoId != nil {
|
||||
out.RepoId = in.RepoId.Value
|
||||
}
|
||||
if in.Name != nil {
|
||||
out.Name = in.Name.Value
|
||||
}
|
||||
if in.AppDefaultStatus != nil {
|
||||
out.AppDefaultStatus = in.AppDefaultStatus.Value
|
||||
}
|
||||
if in.Credential != nil {
|
||||
out.Credential = in.Credential.Value
|
||||
}
|
||||
|
||||
categorySet := make(RepoCategorySet, 0)
|
||||
|
||||
for _, item := range in.CategorySet {
|
||||
category := convertResourceCategory(item)
|
||||
categorySet = append(categorySet, category)
|
||||
}
|
||||
|
||||
out.CategorySet = categorySet
|
||||
|
||||
if in.Controller != nil {
|
||||
out.Credential = in.Credential.Value
|
||||
}
|
||||
|
||||
if in.CreateTime != nil {
|
||||
date := strfmt.DateTime(time.Unix(in.CreateTime.Seconds, 0))
|
||||
out.CreateTime = &date
|
||||
}
|
||||
|
||||
if in.Description != nil {
|
||||
out.Description = in.Description.Value
|
||||
}
|
||||
|
||||
labelSet := make(RepoLabels, 0)
|
||||
|
||||
for _, item := range in.Labels {
|
||||
label := convertRepoLabel(item)
|
||||
labelSet = append(labelSet, label)
|
||||
}
|
||||
|
||||
out.Labels = labelSet
|
||||
|
||||
if in.Owner != nil {
|
||||
out.Owner = in.Owner.Value
|
||||
}
|
||||
if in.Providers != nil {
|
||||
out.Providers = in.Providers
|
||||
}
|
||||
if in.RepoId != nil {
|
||||
out.RepoId = in.RepoId.Value
|
||||
}
|
||||
|
||||
selectorSet := make(RepoSelectors, 0)
|
||||
|
||||
for _, item := range in.Selectors {
|
||||
selector := convertRepoSelector(item)
|
||||
selectorSet = append(selectorSet, selector)
|
||||
}
|
||||
|
||||
out.Selectors = selectorSet
|
||||
|
||||
if in.Status != nil {
|
||||
out.Status = in.Status.Value
|
||||
}
|
||||
if in.StatusTime != nil {
|
||||
out.StatusTime = strfmt.DateTime(time.Unix(in.StatusTime.Seconds, 0))
|
||||
}
|
||||
if in.Type != nil {
|
||||
out.Type = in.Type.Value
|
||||
}
|
||||
if in.Url != nil {
|
||||
out.URL = in.Url.Value
|
||||
}
|
||||
if in.Visibility != nil {
|
||||
out.Visibility = in.Visibility.Value
|
||||
}
|
||||
return &out
|
||||
}
|
||||
|
||||
func convertRepoLabel(in *pb.RepoLabel) *RepoLabel {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := RepoLabel{}
|
||||
if in.CreateTime != nil {
|
||||
date := strfmt.DateTime(time.Unix(in.CreateTime.Seconds, 0))
|
||||
out.CreateTime = &date
|
||||
}
|
||||
if in.LabelKey != nil {
|
||||
out.LabelKey = in.LabelKey.Value
|
||||
}
|
||||
if in.LabelValue != nil {
|
||||
out.LabelValue = in.LabelValue.Value
|
||||
}
|
||||
return &out
|
||||
}
|
||||
|
||||
func convertRepoSelector(in *pb.RepoSelector) *RepoSelector {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := RepoSelector{}
|
||||
if in.CreateTime != nil {
|
||||
date := strfmt.DateTime(time.Unix(in.CreateTime.Seconds, 0))
|
||||
out.CreateTime = &date
|
||||
}
|
||||
if in.SelectorKey != nil {
|
||||
out.SelectorKey = in.SelectorKey.Value
|
||||
}
|
||||
if in.SelectorValue != nil {
|
||||
out.SelectorValue = in.SelectorValue.Value
|
||||
}
|
||||
return &out
|
||||
}
|
||||
|
||||
func convertAppVersionAudit(in *pb.AppVersionAudit) *AppVersionAudit {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := AppVersionAudit{}
|
||||
if in.AppId != nil {
|
||||
out.AppId = in.AppId.Value
|
||||
}
|
||||
if in.AppName != nil {
|
||||
out.AppName = in.AppName.Value
|
||||
}
|
||||
if in.Message != nil {
|
||||
out.Message = in.Message.Value
|
||||
}
|
||||
if in.Operator != nil {
|
||||
out.Operator = in.Operator.Value
|
||||
}
|
||||
if in.OperatorType != nil {
|
||||
out.OperatorType = in.OperatorType.Value
|
||||
}
|
||||
if in.ReviewId != nil {
|
||||
out.ReviewId = in.ReviewId.Value
|
||||
}
|
||||
if in.Status != nil {
|
||||
out.Status = in.Status.Value
|
||||
}
|
||||
if in.StatusTime != nil {
|
||||
date := strfmt.DateTime(time.Unix(in.StatusTime.Seconds, 0))
|
||||
out.StatusTime = &date
|
||||
}
|
||||
if in.VersionId != nil {
|
||||
out.VersionId = in.VersionId.Value
|
||||
}
|
||||
if in.VersionName != nil {
|
||||
out.VersionName = in.VersionName.Value
|
||||
}
|
||||
if in.VersionType != nil {
|
||||
out.VersionType = in.VersionType.Value
|
||||
}
|
||||
return &out
|
||||
}
|
||||
|
||||
func convertAppVersionReview(in *pb.AppVersionReview) *AppVersionReview {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := AppVersionReview{}
|
||||
if in.AppId != nil {
|
||||
out.AppId = in.AppId.Value
|
||||
}
|
||||
if in.AppName != nil {
|
||||
out.AppName = in.AppName.Value
|
||||
}
|
||||
if in.Phase != nil {
|
||||
out.Phase = make(AppVersionReviewPhaseOAIGen)
|
||||
for k, v := range in.Phase {
|
||||
out.Phase[k] = *convertAppVersionReviewPhase(v)
|
||||
}
|
||||
}
|
||||
if in.ReviewId != nil {
|
||||
out.ReviewId = in.ReviewId.Value
|
||||
}
|
||||
if in.Reviewer != nil {
|
||||
out.Reviewer = in.Reviewer.Value
|
||||
}
|
||||
if in.Status != nil {
|
||||
out.Status = in.Status.Value
|
||||
}
|
||||
if in.StatusTime != nil {
|
||||
out.StatusTime = strfmt.DateTime(time.Unix(in.StatusTime.Seconds, 0))
|
||||
}
|
||||
if in.VersionId != nil {
|
||||
out.VersionID = in.VersionId.Value
|
||||
}
|
||||
if in.VersionName != nil {
|
||||
out.VersionName = in.VersionName.Value
|
||||
}
|
||||
if in.VersionType != nil {
|
||||
out.VersionType = in.VersionType.Value
|
||||
}
|
||||
return &out
|
||||
}
|
||||
|
||||
func convertAppVersionReviewPhase(in *pb.AppVersionReviewPhase) *AppVersionReviewPhase {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := AppVersionReviewPhase{}
|
||||
if in.Message != nil {
|
||||
out.Message = in.Message.Value
|
||||
}
|
||||
if in.OperatorType != nil {
|
||||
out.OperatorType = in.OperatorType.Value
|
||||
}
|
||||
if in.ReviewTime != nil {
|
||||
date := strfmt.DateTime(time.Unix(in.ReviewTime.Seconds, 0))
|
||||
out.ReviewTime = &date
|
||||
}
|
||||
if in.Operator != nil {
|
||||
out.Operator = in.Operator.Value
|
||||
}
|
||||
if in.Status != nil {
|
||||
out.Status = in.Status.Value
|
||||
}
|
||||
if in.StatusTime != nil {
|
||||
date := strfmt.DateTime(time.Unix(in.StatusTime.Seconds, 0))
|
||||
out.StatusTime = &date
|
||||
}
|
||||
return &out
|
||||
}
|
||||
|
||||
func convertRepoEvent(in *pb.RepoEvent) *RepoEvent {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := RepoEvent{}
|
||||
if in.CreateTime != nil {
|
||||
date := strfmt.DateTime(time.Unix(in.CreateTime.Seconds, 0))
|
||||
out.CreateTime = &date
|
||||
}
|
||||
if in.Owner != nil {
|
||||
out.Owner = in.Owner.Value
|
||||
}
|
||||
if in.RepoEventId != nil {
|
||||
out.RepoEventId = in.RepoEventId.Value
|
||||
}
|
||||
if in.RepoId != nil {
|
||||
out.RepoId = in.RepoId.Value
|
||||
}
|
||||
if in.Result != nil {
|
||||
out.Result = in.Result.Value
|
||||
}
|
||||
if in.Status != nil {
|
||||
out.Status = in.Status.Value
|
||||
}
|
||||
if in.StatusTime != nil {
|
||||
date := strfmt.DateTime(time.Unix(in.StatusTime.Seconds, 0))
|
||||
out.StatusTime = &date
|
||||
}
|
||||
|
||||
return &out
|
||||
}
|
||||
|
||||
func convertCluster(in *pb.Cluster) *Cluster {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := Cluster{}
|
||||
if in.AdditionalInfo != nil {
|
||||
out.AdditionalInfo = in.AdditionalInfo.Value
|
||||
}
|
||||
if in.AppId != nil {
|
||||
out.AppId = in.AppId.Value
|
||||
}
|
||||
if in.ClusterId != nil {
|
||||
out.ClusterId = in.ClusterId.Value
|
||||
}
|
||||
if in.ClusterType != nil {
|
||||
out.ClusterType = int64(in.ClusterType.Value)
|
||||
}
|
||||
if in.CreateTime != nil {
|
||||
date := strfmt.DateTime(time.Unix(in.CreateTime.Seconds, 0))
|
||||
out.CreateTime = &date
|
||||
}
|
||||
if in.Debug != nil {
|
||||
out.Debug = in.Debug.Value
|
||||
}
|
||||
if in.Description != nil {
|
||||
out.Description = in.Description.Value
|
||||
}
|
||||
if in.Endpoints != nil {
|
||||
out.Endpoints = in.Endpoints.Value
|
||||
}
|
||||
if in.Env != nil {
|
||||
out.Env = in.Env.Value
|
||||
}
|
||||
if in.FrontgateId != nil {
|
||||
out.FrontgateId = in.FrontgateId.Value
|
||||
}
|
||||
if in.GlobalUuid != nil {
|
||||
out.GlobalUUID = in.GlobalUuid.Value
|
||||
}
|
||||
if in.MetadataRootAccess != nil {
|
||||
out.MetadataRootAccess = in.MetadataRootAccess.Value
|
||||
}
|
||||
if in.Name != nil {
|
||||
out.Name = in.Name.Value
|
||||
}
|
||||
if in.Owner != nil {
|
||||
out.Owner = in.Owner.Value
|
||||
}
|
||||
if in.RuntimeId != nil {
|
||||
out.RuntimeId = in.RuntimeId.Value
|
||||
}
|
||||
if in.Status != nil {
|
||||
out.Status = in.Status.Value
|
||||
}
|
||||
if in.StatusTime != nil {
|
||||
date := strfmt.DateTime(time.Unix(in.StatusTime.Seconds, 0))
|
||||
out.StatusTime = &date
|
||||
}
|
||||
if in.SubnetId != nil {
|
||||
out.SubnetId = in.SubnetId.Value
|
||||
}
|
||||
if in.TransitionStatus != nil {
|
||||
out.TransitionStatus = in.TransitionStatus.Value
|
||||
}
|
||||
if in.UpgradeStatus != nil {
|
||||
out.UpgradeStatus = in.UpgradeStatus.Value
|
||||
}
|
||||
if in.UpgradeTime != nil {
|
||||
date := strfmt.DateTime(time.Unix(in.UpgradeTime.Seconds, 0))
|
||||
out.UpgradeTime = &date
|
||||
}
|
||||
if in.VersionId != nil {
|
||||
out.VersionId = in.VersionId.Value
|
||||
}
|
||||
if in.VpcId != nil {
|
||||
out.VpcId = in.VpcId.Value
|
||||
}
|
||||
if in.Zone != nil {
|
||||
out.Zone = in.Zone.Value
|
||||
}
|
||||
return &out
|
||||
}
|
||||
296
pkg/models/openpitrix/repos.go
Normal file
296
pkg/models/openpitrix/repos.go
Normal file
@@ -0,0 +1,296 @@
|
||||
/*
|
||||
*
|
||||
* Copyright 2019 The KubeSphere Authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* /
|
||||
*/
|
||||
|
||||
package openpitrix
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/golang/protobuf/ptypes/wrappers"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"k8s.io/klog"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
"kubesphere.io/kubesphere/pkg/server/params"
|
||||
cs "kubesphere.io/kubesphere/pkg/simple/client"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/openpitrix"
|
||||
"openpitrix.io/openpitrix/pkg/pb"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func CreateRepo(request *CreateRepoRequest) (*CreateRepoResponse, error) {
|
||||
op, err := cs.ClientSets().OpenPitrix()
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
createRepoRequest := &pb.CreateRepoRequest{
|
||||
Name: &wrappers.StringValue{Value: request.Name},
|
||||
Description: &wrappers.StringValue{Value: request.Description},
|
||||
Type: &wrappers.StringValue{Value: request.Type},
|
||||
Url: &wrappers.StringValue{Value: request.URL},
|
||||
Credential: &wrappers.StringValue{Value: request.Credential},
|
||||
Visibility: &wrappers.StringValue{Value: request.Visibility},
|
||||
CategoryId: &wrappers.StringValue{Value: request.CategoryId},
|
||||
AppDefaultStatus: &wrappers.StringValue{Value: request.AppDefaultStatus},
|
||||
}
|
||||
|
||||
if request.Providers != nil {
|
||||
createRepoRequest.Providers = request.Providers
|
||||
}
|
||||
if request.Workspace != nil {
|
||||
createRepoRequest.Labels = &wrappers.StringValue{Value: fmt.Sprintf("workspace=%s", *request.Workspace)}
|
||||
}
|
||||
|
||||
resp, err := op.Repo().CreateRepo(openpitrix.SystemContext(), createRepoRequest)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
return &CreateRepoResponse{
|
||||
RepoID: resp.GetRepoId().GetValue(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func DeleteRepo(id string) error {
|
||||
op, err := cs.ClientSets().OpenPitrix()
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return err
|
||||
}
|
||||
_, err = op.Repo().DeleteRepos(openpitrix.SystemContext(), &pb.DeleteReposRequest{
|
||||
RepoId: []string{id},
|
||||
})
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func PatchRepo(id string, request *ModifyRepoRequest) error {
|
||||
op, err := cs.ClientSets().OpenPitrix()
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return err
|
||||
}
|
||||
modifyRepoRequest := &pb.ModifyRepoRequest{
|
||||
RepoId: &wrappers.StringValue{Value: id},
|
||||
}
|
||||
|
||||
if request.Name != nil {
|
||||
modifyRepoRequest.Name = &wrappers.StringValue{Value: *request.Name}
|
||||
}
|
||||
if request.Description != nil {
|
||||
modifyRepoRequest.Description = &wrappers.StringValue{Value: *request.Description}
|
||||
}
|
||||
if request.Type != nil {
|
||||
modifyRepoRequest.Type = &wrappers.StringValue{Value: *request.Type}
|
||||
}
|
||||
if request.URL != nil {
|
||||
modifyRepoRequest.Url = &wrappers.StringValue{Value: *request.URL}
|
||||
}
|
||||
if request.Credential != nil {
|
||||
modifyRepoRequest.Credential = &wrappers.StringValue{Value: *request.Credential}
|
||||
}
|
||||
if request.Visibility != nil {
|
||||
modifyRepoRequest.Visibility = &wrappers.StringValue{Value: *request.Visibility}
|
||||
}
|
||||
|
||||
if request.CategoryID != nil {
|
||||
modifyRepoRequest.CategoryId = &wrappers.StringValue{Value: *request.CategoryID}
|
||||
}
|
||||
if request.AppDefaultStatus != nil {
|
||||
modifyRepoRequest.AppDefaultStatus = &wrappers.StringValue{Value: *request.AppDefaultStatus}
|
||||
}
|
||||
if request.Providers != nil {
|
||||
modifyRepoRequest.Providers = request.Providers
|
||||
}
|
||||
if request.Workspace != nil {
|
||||
modifyRepoRequest.Labels = &wrappers.StringValue{Value: fmt.Sprintf("workspace=%s", *request.Workspace)}
|
||||
}
|
||||
|
||||
_, err = op.Repo().ModifyRepo(openpitrix.SystemContext(), modifyRepoRequest)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DescribeRepo(id string) (*Repo, error) {
|
||||
op, err := cs.ClientSets().OpenPitrix()
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
resp, err := op.Repo().DescribeRepos(openpitrix.SystemContext(), &pb.DescribeReposRequest{
|
||||
RepoId: []string{id},
|
||||
Limit: 1,
|
||||
})
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var repo *Repo
|
||||
|
||||
if len(resp.RepoSet) > 0 {
|
||||
repo = convertRepo(resp.RepoSet[0])
|
||||
return repo, nil
|
||||
} else {
|
||||
err := status.New(codes.NotFound, "resource not found").Err()
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
func ListRepos(conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {
|
||||
client, err := cs.ClientSets().OpenPitrix()
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req := &pb.DescribeReposRequest{}
|
||||
|
||||
if keyword := conditions.Match["keyword"]; keyword != "" {
|
||||
req.SearchWord = &wrappers.StringValue{Value: keyword}
|
||||
}
|
||||
if status := conditions.Match["status"]; status != "" {
|
||||
req.Status = strings.Split(status, "|")
|
||||
}
|
||||
if typeStr := conditions.Match["type"]; typeStr != "" {
|
||||
req.Type = strings.Split(typeStr, "|")
|
||||
}
|
||||
if visibility := conditions.Match["visibility"]; visibility != "" {
|
||||
req.Visibility = strings.Split(visibility, "|")
|
||||
}
|
||||
if status := conditions.Match["status"]; status != "" {
|
||||
req.Status = strings.Split(status, "|")
|
||||
}
|
||||
if workspace := conditions.Match["workspace"]; workspace != "" {
|
||||
req.Label = &wrappers.StringValue{Value: fmt.Sprintf("workspace=%s", workspace)}
|
||||
}
|
||||
if orderBy != "" {
|
||||
req.SortKey = &wrappers.StringValue{Value: orderBy}
|
||||
}
|
||||
req.Reverse = &wrappers.BoolValue{Value: reverse}
|
||||
req.Limit = uint32(limit)
|
||||
req.Offset = uint32(offset)
|
||||
resp, err := client.Repo().DescribeRepos(openpitrix.SystemContext(), req)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
items := make([]interface{}, 0)
|
||||
|
||||
for _, item := range resp.RepoSet {
|
||||
items = append(items, convertRepo(item))
|
||||
}
|
||||
|
||||
return &models.PageableResponse{Items: items, TotalCount: int(resp.TotalCount)}, nil
|
||||
}
|
||||
|
||||
func ValidateRepo(request *ValidateRepoRequest) (*ValidateRepoResponse, error) {
|
||||
client, err := cs.ClientSets().OpenPitrix()
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp, err := client.Repo().ValidateRepo(openpitrix.SystemContext(), &pb.ValidateRepoRequest{
|
||||
Type: &wrappers.StringValue{Value: request.Type},
|
||||
Credential: &wrappers.StringValue{Value: request.Credential},
|
||||
Url: &wrappers.StringValue{Value: request.Url},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &ValidateRepoResponse{
|
||||
ErrorCode: int64(resp.ErrorCode),
|
||||
Ok: resp.Ok.Value,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func DoRepoAction(repoId string, request *RepoActionRequest) error {
|
||||
op, err := cs.ClientSets().OpenPitrix()
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return err
|
||||
}
|
||||
|
||||
switch request.Action {
|
||||
case "index":
|
||||
indexRepoRequest := &pb.IndexRepoRequest{
|
||||
RepoId: &wrappers.StringValue{Value: repoId},
|
||||
}
|
||||
_, err := op.RepoIndexer().IndexRepo(openpitrix.SystemContext(), indexRepoRequest)
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
default:
|
||||
err = status.New(codes.InvalidArgument, "action not support").Err()
|
||||
klog.Error(err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
func ListRepoEvents(repoId string, conditions *params.Conditions, limit, offset int) (*models.PageableResponse, error) {
|
||||
op, err := cs.ClientSets().OpenPitrix()
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
describeRepoEventsRequest := &pb.DescribeRepoEventsRequest{
|
||||
RepoId: []string{repoId},
|
||||
}
|
||||
if eventId := conditions.Match["repo_event_id"]; eventId != "" {
|
||||
describeRepoEventsRequest.RepoEventId = strings.Split(eventId, "|")
|
||||
}
|
||||
if status := conditions.Match["status"]; status != "" {
|
||||
describeRepoEventsRequest.Status = strings.Split(status, "|")
|
||||
}
|
||||
describeRepoEventsRequest.Limit = uint32(limit)
|
||||
describeRepoEventsRequest.Offset = uint32(offset)
|
||||
|
||||
resp, err := op.RepoIndexer().DescribeRepoEvents(openpitrix.SystemContext(), describeRepoEventsRequest)
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
items := make([]interface{}, 0)
|
||||
|
||||
for _, item := range resp.RepoEventSet {
|
||||
items = append(items, convertRepoEvent(item))
|
||||
}
|
||||
|
||||
return &models.PageableResponse{Items: items, TotalCount: int(resp.TotalCount)}, nil
|
||||
}
|
||||
833
pkg/models/openpitrix/types.go
Normal file
833
pkg/models/openpitrix/types.go
Normal file
@@ -0,0 +1,833 @@
|
||||
package openpitrix
|
||||
|
||||
import (
|
||||
"github.com/go-openapi/strfmt"
|
||||
)
|
||||
|
||||
type ModifyAppRequest struct {
|
||||
// content of attachment
|
||||
AttachmentContent []byte `json:"attachment_content,omitempty"`
|
||||
|
||||
// only for screenshot, range: [0, 5]
|
||||
Sequence *int32 `json:"sequence,omitempty"`
|
||||
|
||||
// optional: icon/screenshot
|
||||
Type *string `json:"type,omitempty"`
|
||||
|
||||
// abstraction of app
|
||||
Abstraction *string `json:"abstraction,omitempty"`
|
||||
|
||||
// category id of the app
|
||||
CategoryID *string `json:"category_id,omitempty"`
|
||||
|
||||
// description of the app
|
||||
Description *string `json:"description,omitempty"`
|
||||
|
||||
// home page of the app
|
||||
Home *string `json:"home,omitempty"`
|
||||
|
||||
// key words of the app
|
||||
Keywords *string `json:"keywords,omitempty"`
|
||||
|
||||
// maintainers who maintainer the app
|
||||
Maintainers *string `json:"maintainers,omitempty"`
|
||||
|
||||
// name of the app
|
||||
Name *string `json:"name,omitempty"`
|
||||
|
||||
// instructions of the app
|
||||
Readme *string `json:"readme,omitempty"`
|
||||
|
||||
// sources of app
|
||||
Sources *string `json:"sources,omitempty"`
|
||||
|
||||
// tos of app
|
||||
Tos *string `json:"tos,omitempty"`
|
||||
}
|
||||
|
||||
type ModifyAppVersionRequest struct {
|
||||
// app description
|
||||
Description *string `json:"description,omitempty"`
|
||||
|
||||
// app name
|
||||
Name *string `json:"name,omitempty"`
|
||||
|
||||
// package of app to replace other
|
||||
Package []byte `json:"package,omitempty"`
|
||||
|
||||
// filename map to file_content
|
||||
PackageFiles map[string][]byte `json:"package_files,omitempty"`
|
||||
|
||||
// required, version id of app to modify
|
||||
VersionID *string `json:"version_id,omitempty"`
|
||||
}
|
||||
type AppVersionAudit struct {
|
||||
|
||||
// id of specific version app
|
||||
AppId string `json:"app_id,omitempty"`
|
||||
|
||||
// name of specific version app
|
||||
AppName string `json:"app_name,omitempty"`
|
||||
|
||||
// audit message
|
||||
Message string `json:"message,omitempty"`
|
||||
|
||||
// user of auditer
|
||||
Operator string `json:"operator,omitempty"`
|
||||
|
||||
// operator of auditer eg.[global_admin|developer|business|technical|isv]
|
||||
OperatorType string `json:"operator_type,omitempty"`
|
||||
|
||||
// review id
|
||||
ReviewId string `json:"review_id,omitempty"`
|
||||
|
||||
// audit status, eg.[draft|submitted|passed|rejected|active|in-review|deleted|suspended]
|
||||
Status string `json:"status,omitempty"`
|
||||
|
||||
// record status changed time
|
||||
StatusTime *strfmt.DateTime `json:"status_time,omitempty"`
|
||||
|
||||
// id of version to audit
|
||||
VersionId string `json:"version_id,omitempty"`
|
||||
|
||||
// version name
|
||||
VersionName string `json:"version_name,omitempty"`
|
||||
|
||||
// version type
|
||||
VersionType string `json:"version_type,omitempty"`
|
||||
}
|
||||
|
||||
type ValidatePackageRequest struct {
|
||||
|
||||
// required, version package eg.[the wordpress-0.0.1.tgz will be encoded to bytes]
|
||||
VersionPackage strfmt.Base64 `json:"version_package,omitempty"`
|
||||
|
||||
// optional, vmbased/helm
|
||||
VersionType string `json:"version_type,omitempty"`
|
||||
}
|
||||
type App struct {
|
||||
|
||||
// abstraction of app
|
||||
Abstraction string `json:"abstraction,omitempty"`
|
||||
|
||||
// whether there is a released version in the app
|
||||
Active bool `json:"active,omitempty"`
|
||||
|
||||
// app id
|
||||
AppId string `json:"app_id,omitempty"`
|
||||
|
||||
// app version types eg.[vmbased|helm]
|
||||
AppVersionTypes string `json:"app_version_types,omitempty"`
|
||||
|
||||
// category set
|
||||
CategorySet AppCategorySet `json:"category_set"`
|
||||
|
||||
// chart name of app
|
||||
ChartName string `json:"chart_name,omitempty"`
|
||||
|
||||
// company join time
|
||||
CompanyJoinTime *strfmt.DateTime `json:"company_join_time,omitempty"`
|
||||
|
||||
// company name
|
||||
CompanyName string `json:"company_name,omitempty"`
|
||||
|
||||
// company profile
|
||||
CompanyProfile string `json:"company_profile,omitempty"`
|
||||
|
||||
// company website
|
||||
CompanyWebsite string `json:"company_website,omitempty"`
|
||||
|
||||
// the time when app create
|
||||
CreateTime *strfmt.DateTime `json:"create_time,omitempty"`
|
||||
|
||||
// app description
|
||||
Description string `json:"description,omitempty"`
|
||||
|
||||
// app home page
|
||||
Home string `json:"home,omitempty"`
|
||||
|
||||
// app icon
|
||||
Icon string `json:"icon,omitempty"`
|
||||
|
||||
// the isv user who create the app
|
||||
Isv string `json:"isv,omitempty"`
|
||||
|
||||
// app key words
|
||||
Keywords string `json:"keywords,omitempty"`
|
||||
|
||||
// latest version of app
|
||||
LatestAppVersion *AppVersion `json:"latest_app_version,omitempty"`
|
||||
|
||||
// app maintainers
|
||||
Maintainers string `json:"maintainers,omitempty"`
|
||||
|
||||
// app name
|
||||
Name string `json:"name,omitempty"`
|
||||
|
||||
// owner of app
|
||||
Owner string `json:"owner,omitempty"`
|
||||
|
||||
// app instructions
|
||||
Readme string `json:"readme,omitempty"`
|
||||
|
||||
// repository(store app package) id
|
||||
RepoId string `json:"repo_id,omitempty"`
|
||||
|
||||
// app screenshots
|
||||
Screenshots string `json:"screenshots,omitempty"`
|
||||
|
||||
// sources of app
|
||||
Sources string `json:"sources,omitempty"`
|
||||
|
||||
// status eg.[modify|submit|review|cancel|release|delete|pass|reject|suspend|recover]
|
||||
Status string `json:"status,omitempty"`
|
||||
|
||||
// record status changed time
|
||||
StatusTime *strfmt.DateTime `json:"status_time,omitempty"`
|
||||
|
||||
// tos of app
|
||||
Tos string `json:"tos,omitempty"`
|
||||
|
||||
// the time when app update
|
||||
UpdateTime *strfmt.DateTime `json:"update_time,omitempty"`
|
||||
|
||||
ClusterTotal *int `json:"cluster_total,omitempty"`
|
||||
}
|
||||
type AppVersionReviewPhase struct {
|
||||
|
||||
// review message
|
||||
Message string `json:"message,omitempty"`
|
||||
|
||||
// user of reviewer
|
||||
Operator string `json:"operator,omitempty"`
|
||||
|
||||
// operator type of reviewer eg.[global_admin|developer|business|technical|isv]
|
||||
OperatorType string `json:"operator_type,omitempty"`
|
||||
|
||||
// app version review time
|
||||
ReviewTime *strfmt.DateTime `json:"review_time,omitempty"`
|
||||
|
||||
// review status of app version eg.[isv-in-review|isv-passed|isv-rejected|isv-draft|business-in-review|business-passed|business-rejected|develop-draft|develop-in-review|develop-passed|develop-rejected|develop-draft]
|
||||
Status string `json:"status,omitempty"`
|
||||
|
||||
// record status changed time
|
||||
StatusTime *strfmt.DateTime `json:"status_time,omitempty"`
|
||||
}
|
||||
|
||||
type AppVersionReviewPhaseOAIGen map[string]AppVersionReviewPhase
|
||||
|
||||
type GetAppVersionPackageResponse struct {
|
||||
|
||||
// app id of package
|
||||
AppId string `json:"app_id,omitempty"`
|
||||
|
||||
// package of specific app version
|
||||
Package strfmt.Base64 `json:"package,omitempty"`
|
||||
|
||||
// version id of package
|
||||
VersionId string `json:"version_id,omitempty"`
|
||||
}
|
||||
|
||||
type GetAppVersionPackageFilesResponse struct {
|
||||
|
||||
// filename map to content
|
||||
Files map[string]strfmt.Base64 `json:"files,omitempty"`
|
||||
|
||||
// version id
|
||||
VersionId string `json:"version_id,omitempty"`
|
||||
}
|
||||
type AppVersionReview struct {
|
||||
|
||||
// app id
|
||||
AppId string `json:"app_id,omitempty"`
|
||||
|
||||
// app name
|
||||
AppName string `json:"app_name,omitempty"`
|
||||
|
||||
// phase
|
||||
Phase AppVersionReviewPhaseOAIGen `json:"phase,omitempty"`
|
||||
|
||||
// review id
|
||||
ReviewId string `json:"review_id,omitempty"`
|
||||
|
||||
// user who review the app version
|
||||
Reviewer string `json:"reviewer,omitempty"`
|
||||
|
||||
// review status eg.[isv-in-review|isv-passed|isv-rejected|isv-draft|business-in-review|business-passed|business-rejected|develop-draft|develop-in-review|develop-passed|develop-rejected|develop-draft]
|
||||
Status string `json:"status,omitempty"`
|
||||
|
||||
// record status changed time
|
||||
StatusTime strfmt.DateTime `json:"status_time,omitempty"`
|
||||
|
||||
// id of app version
|
||||
VersionID string `json:"version_id,omitempty"`
|
||||
|
||||
// version name of specific app version
|
||||
VersionName string `json:"version_name,omitempty"`
|
||||
|
||||
// version type
|
||||
VersionType string `json:"version_type,omitempty"`
|
||||
}
|
||||
|
||||
type CreateAppRequest struct {
|
||||
|
||||
// app icon
|
||||
Icon strfmt.Base64 `json:"icon,omitempty"`
|
||||
|
||||
// isv
|
||||
Isv string `json:"isv,omitempty"`
|
||||
|
||||
// required, app name
|
||||
Name string `json:"name,omitempty"`
|
||||
|
||||
// required, version name of the app
|
||||
VersionName string `json:"version_name,omitempty"`
|
||||
|
||||
// required, version with specific app package
|
||||
VersionPackage strfmt.Base64 `json:"version_package,omitempty"`
|
||||
|
||||
// optional, vmbased/helm
|
||||
VersionType string `json:"version_type,omitempty"`
|
||||
}
|
||||
|
||||
type CreateAppResponse struct {
|
||||
|
||||
// app id
|
||||
AppID string `json:"app_id,omitempty"`
|
||||
|
||||
// version id of the app
|
||||
VersionID string `json:"version_id,omitempty"`
|
||||
}
|
||||
|
||||
type AppVersion struct {
|
||||
|
||||
// active or not
|
||||
Active bool `json:"active,omitempty"`
|
||||
|
||||
// app id
|
||||
AppId string `json:"app_id,omitempty"`
|
||||
|
||||
// the time when app version create
|
||||
CreateTime *strfmt.DateTime `json:"create_time,omitempty"`
|
||||
|
||||
// description of app of specific version
|
||||
Description string `json:"description,omitempty"`
|
||||
|
||||
// home of app of specific version
|
||||
Home string `json:"home,omitempty"`
|
||||
|
||||
// icon of app of specific version
|
||||
Icon string `json:"icon,omitempty"`
|
||||
|
||||
// keywords of app of specific version
|
||||
Keywords string `json:"keywords,omitempty"`
|
||||
|
||||
// maintainers of app of specific version
|
||||
Maintainers string `json:"maintainers,omitempty"`
|
||||
|
||||
// message path of app of specific version
|
||||
Message string `json:"message,omitempty"`
|
||||
|
||||
// version name
|
||||
Name string `json:"name,omitempty"`
|
||||
|
||||
// owner
|
||||
Owner string `json:"owner,omitempty"`
|
||||
|
||||
// package name of app of specific version
|
||||
PackageName string `json:"package_name,omitempty"`
|
||||
|
||||
// readme of app of specific version
|
||||
Readme string `json:"readme,omitempty"`
|
||||
|
||||
// review id of app of specific version
|
||||
ReviewId string `json:"review_id,omitempty"`
|
||||
|
||||
// screenshots of app of specific version
|
||||
Screenshots string `json:"screenshots,omitempty"`
|
||||
|
||||
// sequence of app of specific version
|
||||
Sequence int64 `json:"sequence,omitempty"`
|
||||
|
||||
// sources of app of specific version
|
||||
Sources string `json:"sources,omitempty"`
|
||||
|
||||
// status of app of specific version eg.[draft|submitted|passed|rejected|active|in-review|deleted|suspended]
|
||||
Status string `json:"status,omitempty"`
|
||||
|
||||
// record status changed time
|
||||
StatusTime *strfmt.DateTime `json:"status_time,omitempty"`
|
||||
|
||||
// type of app of specific version
|
||||
Type string `json:"type,omitempty"`
|
||||
|
||||
// the time when app version update
|
||||
UpdateTime *strfmt.DateTime `json:"update_time,omitempty"`
|
||||
|
||||
// version id of app
|
||||
VersionId string `json:"version_id,omitempty"`
|
||||
|
||||
ClusterTotal *int `json:"cluster_total,omitempty"`
|
||||
}
|
||||
|
||||
type CreateAppVersionResponse struct {
|
||||
|
||||
// version id
|
||||
VersionId string `json:"version_id,omitempty"`
|
||||
}
|
||||
|
||||
type ValidatePackageResponse struct {
|
||||
|
||||
// app description
|
||||
Description string `json:"description,omitempty"`
|
||||
|
||||
// error eg.[json error]
|
||||
Error string `json:"error,omitempty"`
|
||||
|
||||
// filename map to detail
|
||||
ErrorDetails map[string]string `json:"error_details,omitempty"`
|
||||
|
||||
// app name eg.[wordpress|mysql|...]
|
||||
Name string `json:"name,omitempty"`
|
||||
|
||||
// app url
|
||||
URL string `json:"url,omitempty"`
|
||||
|
||||
// app version name.eg.[0.1.0]
|
||||
VersionName string `json:"version_name,omitempty"`
|
||||
}
|
||||
|
||||
type CreateAppVersionRequest struct {
|
||||
|
||||
// required, id of app to create new version
|
||||
AppId string `json:"app_id,omitempty"`
|
||||
|
||||
// description of app of specific version
|
||||
Description string `json:"description,omitempty"`
|
||||
|
||||
// required, version name eg.[0.1.0|0.1.3|...]
|
||||
Name string `json:"name,omitempty"`
|
||||
|
||||
// package of app of specific version
|
||||
Package strfmt.Base64 `json:"package,omitempty"`
|
||||
|
||||
// optional: vmbased/helm
|
||||
Type string `json:"type,omitempty"`
|
||||
}
|
||||
|
||||
type GetAppVersionFilesRequest struct {
|
||||
Files []string `json:"files,omitempty"`
|
||||
}
|
||||
|
||||
type ActionRequest struct {
|
||||
Action string `json:"action"`
|
||||
Message string `json:"message,omitempty"`
|
||||
Username string `json:"-"`
|
||||
}
|
||||
|
||||
type Attachment struct {
|
||||
|
||||
// filename map to content
|
||||
AttachmentContent map[string]strfmt.Base64 `json:"attachment_content,omitempty"`
|
||||
|
||||
// attachment id
|
||||
AttachmentID string `json:"attachment_id,omitempty"`
|
||||
|
||||
// the time attachment create
|
||||
CreateTime *strfmt.DateTime `json:"create_time,omitempty"`
|
||||
}
|
||||
|
||||
type CreateCategoryRequest struct {
|
||||
|
||||
// category description
|
||||
Description string `json:"description,omitempty"`
|
||||
|
||||
// category icon
|
||||
Icon strfmt.Base64 `json:"icon,omitempty"`
|
||||
|
||||
// the i18n of this category, json format, sample: {"zh_cn": "数据库", "en": "database"}
|
||||
Locale string `json:"locale,omitempty"`
|
||||
|
||||
// required, category name
|
||||
Name string `json:"name,omitempty"`
|
||||
}
|
||||
type ModifyCategoryRequest struct {
|
||||
// category description
|
||||
Description *string `json:"description,omitempty"`
|
||||
|
||||
// category icon
|
||||
Icon []byte `json:"icon,omitempty"`
|
||||
|
||||
// the i18n of this category, json format, sample: {"zh_cn": "数据库", "en": "database"}
|
||||
Locale *string `json:"locale,omitempty"`
|
||||
|
||||
// category name
|
||||
Name *string `json:"name,omitempty"`
|
||||
}
|
||||
|
||||
type AppCategorySet []*ResourceCategory
|
||||
|
||||
type ResourceCategory struct {
|
||||
|
||||
// category id
|
||||
CategoryId string `json:"category_id,omitempty"`
|
||||
|
||||
// create time
|
||||
CreateTime *strfmt.DateTime `json:"create_time,omitempty"`
|
||||
|
||||
// locale
|
||||
Locale string `json:"locale,omitempty"`
|
||||
|
||||
// name
|
||||
Name string `json:"name,omitempty"`
|
||||
|
||||
// status
|
||||
Status string `json:"status,omitempty"`
|
||||
|
||||
// status time
|
||||
StatusTime *strfmt.DateTime `json:"status_time,omitempty"`
|
||||
}
|
||||
|
||||
type Category struct {
|
||||
|
||||
// category id
|
||||
CategoryID string `json:"category_id,omitempty"`
|
||||
|
||||
// the time when category create
|
||||
CreateTime *strfmt.DateTime `json:"create_time,omitempty"`
|
||||
|
||||
// category description
|
||||
Description string `json:"description,omitempty"`
|
||||
|
||||
// category icon
|
||||
Icon string `json:"icon,omitempty"`
|
||||
|
||||
// the i18n of this category, json format, sample: {"zh_cn": "数据库", "en": "database"}
|
||||
Locale string `json:"locale,omitempty"`
|
||||
|
||||
// category name,app belong to a category,eg.[AI|Firewall|cache|...]
|
||||
Name string `json:"name,omitempty"`
|
||||
|
||||
// owner
|
||||
Owner string `json:"owner,omitempty"`
|
||||
|
||||
AppTotal *int `json:"app_total,omitempty"`
|
||||
|
||||
// the time when category update
|
||||
UpdateTime *strfmt.DateTime `json:"update_time,omitempty"`
|
||||
}
|
||||
|
||||
type CreateCategoryResponse struct {
|
||||
|
||||
// id of category created
|
||||
CategoryId string `json:"category_id,omitempty"`
|
||||
}
|
||||
|
||||
type RepoEvent struct {
|
||||
// repository event create time
|
||||
CreateTime *strfmt.DateTime `json:"create_time,omitempty"`
|
||||
|
||||
// owner
|
||||
Owner string `json:"owner,omitempty"`
|
||||
|
||||
// repository event id
|
||||
RepoEventId string `json:"repo_event_id,omitempty"`
|
||||
|
||||
// repository id
|
||||
RepoId string `json:"repo_id,omitempty"`
|
||||
|
||||
// result
|
||||
Result string `json:"result,omitempty"`
|
||||
|
||||
// repository event status eg.[failed|successful|working|pending]
|
||||
Status string `json:"status,omitempty"`
|
||||
|
||||
// record status changed time
|
||||
StatusTime *strfmt.DateTime `json:"status_time,omitempty"`
|
||||
}
|
||||
|
||||
type CreateRepoRequest struct {
|
||||
// required app default status.eg:[draft|active]
|
||||
AppDefaultStatus string `json:"app_default_status,omitempty"`
|
||||
|
||||
// category id
|
||||
CategoryId string `json:"category_id,omitempty"`
|
||||
|
||||
// required, credential of visiting the repository
|
||||
Credential string `json:"credential,omitempty"`
|
||||
|
||||
// repository description
|
||||
Description string `json:"description,omitempty"`
|
||||
|
||||
// workspace
|
||||
Workspace *string `json:"workspace,omitempty"`
|
||||
|
||||
// required, repository name
|
||||
Name string `json:"name,omitempty"`
|
||||
|
||||
// required, runtime provider eg.[qingcloud|aliyun|aws|kubernetes]
|
||||
Providers []string `json:"providers"`
|
||||
|
||||
// repository type
|
||||
Type string `json:"type,omitempty"`
|
||||
|
||||
// required, url of visiting the repository
|
||||
URL string `json:"url,omitempty"`
|
||||
|
||||
// required, visibility eg:[public|private]
|
||||
Visibility string `json:"visibility,omitempty"`
|
||||
}
|
||||
|
||||
type RepoCategorySet []*ResourceCategory
|
||||
|
||||
type ModifyRepoRequest struct {
|
||||
// app default status eg:[draft|active]
|
||||
AppDefaultStatus *string `json:"app_default_status,omitempty"`
|
||||
|
||||
// category id
|
||||
CategoryID *string `json:"category_id,omitempty"`
|
||||
|
||||
// credential of visiting the repository
|
||||
Credential *string `json:"credential,omitempty"`
|
||||
|
||||
// repository description
|
||||
Description *string `json:"description,omitempty"`
|
||||
|
||||
Workspace *string `json:"workspace,omitempty"`
|
||||
|
||||
// repository name
|
||||
Name *string `json:"name,omitempty"`
|
||||
|
||||
// runtime provider eg.[qingcloud|aliyun|aws|kubernetes]
|
||||
Providers []string `json:"providers"`
|
||||
|
||||
// repository type
|
||||
Type *string `json:"type,omitempty"`
|
||||
|
||||
// url of visiting the repository
|
||||
URL *string `json:"url,omitempty"`
|
||||
|
||||
// visibility eg:[public|private]
|
||||
Visibility *string `json:"visibility,omitempty"`
|
||||
}
|
||||
|
||||
type RepoActionRequest struct {
|
||||
Action string `json:"action"`
|
||||
}
|
||||
|
||||
type ValidateRepoRequest struct {
|
||||
Type string `json:"type"`
|
||||
Credential string `json:"credential"`
|
||||
Url string `json:"url"`
|
||||
}
|
||||
|
||||
type RepoSelector struct {
|
||||
// the time when repository selector create
|
||||
CreateTime *strfmt.DateTime `json:"create_time,omitempty"`
|
||||
|
||||
// selector key
|
||||
SelectorKey string `json:"selector_key,omitempty"`
|
||||
|
||||
// selector value
|
||||
SelectorValue string `json:"selector_value,omitempty"`
|
||||
}
|
||||
type RepoLabel struct {
|
||||
// the time when repository label create
|
||||
CreateTime *strfmt.DateTime `json:"create_time,omitempty"`
|
||||
|
||||
// label key
|
||||
LabelKey string `json:"label_key,omitempty"`
|
||||
|
||||
// label value
|
||||
LabelValue string `json:"label_value,omitempty"`
|
||||
}
|
||||
|
||||
type RepoLabels []*RepoLabel
|
||||
type RepoSelectors []*RepoSelector
|
||||
|
||||
type Repo struct {
|
||||
// app default status eg[active|draft]
|
||||
AppDefaultStatus string `json:"app_default_status,omitempty"`
|
||||
|
||||
// category set
|
||||
CategorySet RepoCategorySet `json:"category_set"`
|
||||
|
||||
// controller, value 0 for self resource, value 1 for openpitrix resource
|
||||
Controller int32 `json:"controller,omitempty"`
|
||||
|
||||
// the time when repository create
|
||||
CreateTime *strfmt.DateTime `json:"create_time,omitempty"`
|
||||
|
||||
// credential of visiting the repository
|
||||
Credential string `json:"credential,omitempty"`
|
||||
|
||||
// repository description
|
||||
Description string `json:"description,omitempty"`
|
||||
|
||||
// labels
|
||||
Labels RepoLabels `json:"labels"`
|
||||
|
||||
// repository name
|
||||
Name string `json:"name,omitempty"`
|
||||
|
||||
// owner
|
||||
Owner string `json:"owner,omitempty"`
|
||||
|
||||
// runtime provider eg.[qingcloud|aliyun|aws|kubernetes]
|
||||
Providers []string `json:"providers"`
|
||||
|
||||
// repository id
|
||||
RepoId string `json:"repo_id,omitempty"`
|
||||
|
||||
// selectors
|
||||
Selectors RepoSelectors `json:"selectors"`
|
||||
|
||||
// status eg.[active|deleted]
|
||||
Status string `json:"status,omitempty"`
|
||||
|
||||
// record status changed time
|
||||
StatusTime strfmt.DateTime `json:"status_time,omitempty"`
|
||||
|
||||
// type of repository eg.[http|https|s3]
|
||||
Type string `json:"type,omitempty"`
|
||||
|
||||
// url of visiting the repository
|
||||
URL string `json:"url,omitempty"`
|
||||
|
||||
// visibility.eg:[public|private]
|
||||
Visibility string `json:"visibility,omitempty"`
|
||||
}
|
||||
|
||||
type CreateRepoResponse struct {
|
||||
|
||||
// id of repository created
|
||||
RepoID string `json:"repo_id,omitempty"`
|
||||
}
|
||||
|
||||
type ValidateRepoResponse struct {
|
||||
|
||||
// if validate error,return error code
|
||||
ErrorCode int64 `json:"errorCode,omitempty"`
|
||||
|
||||
// validate repository ok or not
|
||||
Ok bool `json:"ok,omitempty"`
|
||||
}
|
||||
|
||||
type CreateClusterRequest struct {
|
||||
|
||||
// advanced param
|
||||
AdvancedParam []string `json:"advanced_param"`
|
||||
|
||||
// required, id of app to run in cluster
|
||||
AppId string `json:"app_id,omitempty"`
|
||||
|
||||
// required, conf a json string, include cpu, memory info of cluster
|
||||
Conf string `json:"conf,omitempty"`
|
||||
|
||||
// required, id of runtime
|
||||
RuntimeId string `json:"runtime_id,omitempty"`
|
||||
|
||||
// required, id of app version
|
||||
VersionId string `json:"version_id,omitempty"`
|
||||
|
||||
Username string `json:"-"`
|
||||
}
|
||||
|
||||
type Cluster struct {
|
||||
|
||||
// additional info
|
||||
AdditionalInfo string `json:"additional_info,omitempty"`
|
||||
|
||||
// id of app run in cluster
|
||||
AppId string `json:"app_id,omitempty"`
|
||||
|
||||
//// cluster common set
|
||||
//ClusterCommonSet OpenpitrixClusterClusterCommonSet `json:"cluster_common_set"`
|
||||
|
||||
// cluster id
|
||||
ClusterId string `json:"cluster_id,omitempty"`
|
||||
|
||||
// cluster type, frontgate or normal cluster
|
||||
ClusterType int64 `json:"cluster_type,omitempty"`
|
||||
|
||||
// the time when cluster create
|
||||
CreateTime *strfmt.DateTime `json:"create_time,omitempty"`
|
||||
|
||||
// cluster used to debug or not
|
||||
Debug bool `json:"debug,omitempty"`
|
||||
|
||||
// cluster description
|
||||
Description string `json:"description,omitempty"`
|
||||
|
||||
// endpoint of cluster
|
||||
Endpoints string `json:"endpoints,omitempty"`
|
||||
|
||||
// cluster env
|
||||
Env string `json:"env,omitempty"`
|
||||
|
||||
// frontgate id, a proxy for vpc to communicate
|
||||
FrontgateId string `json:"frontgate_id,omitempty"`
|
||||
|
||||
// global uuid
|
||||
GlobalUUID string `json:"global_uuid,omitempty"`
|
||||
|
||||
// metadata root access
|
||||
MetadataRootAccess bool `json:"metadata_root_access,omitempty"`
|
||||
|
||||
// cluster name
|
||||
Name string `json:"name,omitempty"`
|
||||
|
||||
// owner
|
||||
Owner string `json:"owner,omitempty"`
|
||||
|
||||
// cluster runtime id
|
||||
RuntimeId string `json:"runtime_id,omitempty"`
|
||||
|
||||
// cluster status eg.[active|used|enabled|disabled|deleted|stopped|ceased]
|
||||
Status string `json:"status,omitempty"`
|
||||
|
||||
// record status changed time
|
||||
StatusTime *strfmt.DateTime `json:"status_time,omitempty"`
|
||||
|
||||
// subnet id, cluster run in a subnet
|
||||
SubnetId string `json:"subnet_id,omitempty"`
|
||||
|
||||
// cluster transition status eg.[creating|deleting|upgrading|updating|rollbacking|stopping|starting|recovering|ceasing|resizing|scaling]
|
||||
TransitionStatus string `json:"transition_status,omitempty"`
|
||||
|
||||
// upgrade status, unused
|
||||
UpgradeStatus string `json:"upgrade_status,omitempty"`
|
||||
|
||||
// cluster upgraded time
|
||||
UpgradeTime *strfmt.DateTime `json:"upgrade_time,omitempty"`
|
||||
|
||||
// id of version of app run in cluster
|
||||
VersionId string `json:"version_id,omitempty"`
|
||||
|
||||
// vpc id, a vpc contain one more subnet
|
||||
VpcId string `json:"vpc_id,omitempty"`
|
||||
|
||||
// zone of cluster eg.[pek3a|pek3b]
|
||||
Zone string `json:"zone,omitempty"`
|
||||
}
|
||||
|
||||
type Runtime struct {
|
||||
// runtime id
|
||||
RuntimeId string `protobuf:"bytes,1,opt,name=runtime_id,json=runtimeId,proto3" json:"runtime_id,omitempty"`
|
||||
// runtime name,create by owner.
|
||||
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
|
||||
// runtime description
|
||||
Description string `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"`
|
||||
}
|
||||
|
||||
type ModifyClusterAttributesRequest struct {
|
||||
|
||||
// required, id of cluster to modify
|
||||
ClusterID string `json:"cluster_id,omitempty"`
|
||||
|
||||
// cluster description
|
||||
Description *string `json:"description,omitempty"`
|
||||
|
||||
// cluster name
|
||||
Name *string `json:"name,omitempty"`
|
||||
}
|
||||
@@ -121,12 +121,12 @@ func GetResource(namespace, resource, name string) (interface{}, error) {
|
||||
if searcher, ok := resources[resource]; ok {
|
||||
resource, err := searcher.get(namespace, name)
|
||||
if err != nil {
|
||||
klog.Errorln("get resource", namespace, resource, name, err)
|
||||
klog.Errorf("resource %s.%s.%s not found: %s", namespace, resource, name, err)
|
||||
return nil, err
|
||||
}
|
||||
return resource, nil
|
||||
}
|
||||
return nil, fmt.Errorf("resource %s not found", resource)
|
||||
return nil, fmt.Errorf("resource %s.%s.%s not found", namespace, resource, name)
|
||||
}
|
||||
|
||||
func ListResources(namespace, resource string, conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {
|
||||
@@ -136,19 +136,21 @@ func ListResources(namespace, resource string, conditions *params.Conditions, or
|
||||
|
||||
// none namespace resource
|
||||
if namespace != "" && sliceutil.HasString(clusterResources, resource) {
|
||||
klog.Errorln("resources not found", resource)
|
||||
return nil, fmt.Errorf("not found")
|
||||
err = fmt.Errorf("namespaced resource %s not found", resource)
|
||||
klog.Errorln(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if searcher, ok := resources[resource]; ok {
|
||||
result, err = searcher.search(namespace, conditions, orderBy, reverse)
|
||||
} else {
|
||||
klog.Errorln("resources not found", resource)
|
||||
return nil, fmt.Errorf("not found")
|
||||
err = fmt.Errorf("namespaced resource %s not found", resource)
|
||||
klog.Errorln(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
klog.Errorln("resources search", err)
|
||||
klog.Errorln(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
@@ -250,7 +250,7 @@ func (c *Config) stripEmptyOptions() {
|
||||
c.LdapOptions = nil
|
||||
}
|
||||
|
||||
if c.OpenPitrixOptions != nil && c.OpenPitrixOptions.APIServer == "" {
|
||||
if c.OpenPitrixOptions != nil && len(c.OpenPitrixOptions.Validate()) > 0 {
|
||||
c.OpenPitrixOptions = nil
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"io/ioutil"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/alerting"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/devops"
|
||||
esclient "kubesphere.io/kubesphere/pkg/simple/client/elasticsearch"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/elasticsearch"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/kubesphere"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/ldap"
|
||||
@@ -79,8 +79,12 @@ func newTestConfig() *Config {
|
||||
Bucket: "ssss",
|
||||
},
|
||||
OpenPitrixOptions: &openpitrix.OpenPitrixOptions{
|
||||
APIServer: "http://api-gateway.openpitrix-system.svc",
|
||||
Token: "ABCDEFGHIJKLMN",
|
||||
RuntimeManagerEndpoint: "openpitrix-hyperpitrix.openpitrix-system.svc:9103",
|
||||
ClusterManagerEndpoint: "openpitrix-hyperpitrix.openpitrix-system.svc:9104",
|
||||
RepoManagerEndpoint: "openpitrix-hyperpitrix.openpitrix-system.svc:9101",
|
||||
AppManagerEndpoint: "openpitrix-hyperpitrix.openpitrix-system.svc:9102",
|
||||
CategoryManagerEndpoint: "openpitrix-hyperpitrix.openpitrix-system.svc:9113",
|
||||
AttachmentManagerEndpoint: "openpitrix-hyperpitrix.openpitrix-system.svc:9122",
|
||||
},
|
||||
MonitoringOptions: &prometheus.PrometheusOptions{
|
||||
Endpoint: "http://prometheus.kubesphere-monitoring-system.svc",
|
||||
|
||||
@@ -18,8 +18,6 @@
|
||||
package errors
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"github.com/emicklei/go-restful"
|
||||
"net/http"
|
||||
)
|
||||
@@ -42,20 +40,6 @@ func New(message string) Error {
|
||||
return Error{Message: message}
|
||||
}
|
||||
|
||||
func Parse(data []byte) error {
|
||||
var j map[string]string
|
||||
err := json.Unmarshal(data, &j)
|
||||
if err != nil {
|
||||
return errors.New(string(data))
|
||||
} else if message := j["message"]; message != "" {
|
||||
return errors.New(message)
|
||||
} else if message := j["Error"]; message != "" {
|
||||
return errors.New(message)
|
||||
} else {
|
||||
return errors.New(string(data))
|
||||
}
|
||||
}
|
||||
|
||||
func ParseSvcErr(err error, resp *restful.Response) {
|
||||
if svcErr, ok := err.(restful.ServiceError); ok {
|
||||
resp.WriteServiceError(svcErr.Code, svcErr)
|
||||
|
||||
@@ -302,7 +302,14 @@ func (cs *ClientSet) S3() (*s2is3.S3Client, error) {
|
||||
func (cs *ClientSet) OpenPitrix() (*openpitrix.OpenPitrixClient, error) {
|
||||
var err error
|
||||
|
||||
if cs.csoptions.openPitrixOptions == nil || cs.csoptions.openPitrixOptions.APIServer == "" {
|
||||
if cs.csoptions.openPitrixOptions == nil ||
|
||||
cs.csoptions.openPitrixOptions.RepoManagerEndpoint == "" ||
|
||||
cs.csoptions.openPitrixOptions.RuntimeManagerEndpoint == "" ||
|
||||
cs.csoptions.openPitrixOptions.ClusterManagerEndpoint == "" ||
|
||||
cs.csoptions.openPitrixOptions.AppManagerEndpoint == "" ||
|
||||
cs.csoptions.openPitrixOptions.AttachmentManagerEndpoint == "" ||
|
||||
cs.csoptions.openPitrixOptions.RepoIndexerEndpoint == "" ||
|
||||
cs.csoptions.openPitrixOptions.CategoryManagerEndpoint == "" {
|
||||
return nil, ClientSetNotEnabledError{}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,258 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 The KubeSphere Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
package openpitrix
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"k8s.io/klog"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
Unknown = "-"
|
||||
DeploySuffix = "-Deployment"
|
||||
DaemonSuffix = "-DaemonSet"
|
||||
StateSuffix = "-StatefulSet"
|
||||
)
|
||||
|
||||
func (c *OpenPitrixClient) GetAppInfo(appId string) (string, string, string, error) {
|
||||
url := fmt.Sprintf("%s/v1/apps?app_id=%s", c.apiServer, appId)
|
||||
resp, err := c.makeHttpRequest("GET", url, "")
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return Unknown, Unknown, Unknown, err
|
||||
}
|
||||
|
||||
var apps appList
|
||||
err = json.Unmarshal(resp, &apps)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return Unknown, Unknown, Unknown, err
|
||||
}
|
||||
|
||||
if len(apps.Apps) == 0 {
|
||||
return Unknown, Unknown, Unknown, err
|
||||
}
|
||||
|
||||
return apps.Apps[0].ChartName, apps.Apps[0].RepoId, apps.Apps[0].AppId, nil
|
||||
}
|
||||
|
||||
func (c *OpenPitrixClient) GetCluster(clusterId string) (*Cluster, error) {
|
||||
url := fmt.Sprintf("%s/v1/clusters?cluster_id=%s", c.apiServer, clusterId)
|
||||
|
||||
resp, err := c.makeHttpRequest("GET", url, "")
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var clusterList ClusterList
|
||||
err = json.Unmarshal(resp, &clusterList)
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(clusterList.Clusters) == 0 {
|
||||
return nil, fmt.Errorf("NotFound, clusterId:%s", clusterId)
|
||||
}
|
||||
|
||||
return &clusterList.Clusters[0], nil
|
||||
}
|
||||
|
||||
func (c *OpenPitrixClient) ListClusters(runtimeId, searchWord, status string, limit, offset int) (*ClusterList, error) {
|
||||
|
||||
defaultStatus := "status=active&status=stopped&status=pending&status=ceased"
|
||||
|
||||
url := fmt.Sprintf("%s/v1/clusters?limit=%s&offset=%s", c.apiServer, strconv.Itoa(limit), strconv.Itoa(offset))
|
||||
|
||||
if searchWord != "" {
|
||||
url = fmt.Sprintf("%s&search_word=%s", url, searchWord)
|
||||
}
|
||||
|
||||
if status != "" {
|
||||
url = fmt.Sprintf("%s&status=%s", url, status)
|
||||
} else {
|
||||
url = fmt.Sprintf("%s&%s", url, defaultStatus)
|
||||
}
|
||||
|
||||
if len(runtimeId) > 0 {
|
||||
url = fmt.Sprintf("%s&runtime_id=%s", url, runtimeId)
|
||||
}
|
||||
|
||||
resp, err := c.makeHttpRequest("GET", url, "")
|
||||
if err != nil {
|
||||
klog.Errorf("request %s failed, reason: %s", url, err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var clusterList ClusterList
|
||||
err = json.Unmarshal(resp, &clusterList)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &clusterList, nil
|
||||
}
|
||||
|
||||
func (c *OpenPitrixClient) GetRepo(repoId string) (string, error) {
|
||||
url := fmt.Sprintf("%s/v1/repos?repo_id=%s", c.apiServer, repoId)
|
||||
resp, err := c.makeHttpRequest("GET", url, "")
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return Unknown, err
|
||||
}
|
||||
|
||||
var repos repoList
|
||||
err = json.Unmarshal(resp, &repos)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return Unknown, err
|
||||
}
|
||||
|
||||
if len(repos.Repos) == 0 {
|
||||
return Unknown, err
|
||||
}
|
||||
|
||||
return repos.Repos[0].Name, nil
|
||||
}
|
||||
|
||||
func (c *OpenPitrixClient) GetVersion(versionId string) (string, error) {
|
||||
versionUrl := fmt.Sprintf("%s/v1/app_versions?version_id=%s", c.apiServer, versionId)
|
||||
resp, err := c.makeHttpRequest("GET", versionUrl, "")
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return Unknown, err
|
||||
}
|
||||
|
||||
var versions VersionList
|
||||
err = json.Unmarshal(resp, &versions)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return Unknown, err
|
||||
}
|
||||
|
||||
if len(versions.Versions) == 0 {
|
||||
return Unknown, nil
|
||||
}
|
||||
return versions.Versions[0].Name, nil
|
||||
}
|
||||
|
||||
func (c *OpenPitrixClient) GetRuntime(runtimeId string) (string, error) {
|
||||
|
||||
versionUrl := fmt.Sprintf("%s/v1/runtimes?runtime_id=%s", c.apiServer, runtimeId)
|
||||
resp, err := c.makeHttpRequest("GET", versionUrl, "")
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return Unknown, err
|
||||
}
|
||||
|
||||
var runtimes runtimeList
|
||||
err = json.Unmarshal(resp, &runtimes)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return Unknown, err
|
||||
}
|
||||
|
||||
if len(runtimes.Runtimes) == 0 {
|
||||
return Unknown, nil
|
||||
}
|
||||
|
||||
return runtimes.Runtimes[0].Zone, nil
|
||||
}
|
||||
|
||||
func (c *OpenPitrixClient) CreateCluster(request CreateClusterRequest) error {
|
||||
|
||||
versionUrl := fmt.Sprintf("%s/v1/clusters/create", c.apiServer)
|
||||
|
||||
data, err := json.Marshal(request)
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return err
|
||||
}
|
||||
|
||||
data, err = c.makeHttpRequest("POST", versionUrl, string(data))
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *OpenPitrixClient) DeleteCluster(request DeleteClusterRequest) error {
|
||||
|
||||
versionUrl := fmt.Sprintf("%s/v1/clusters/delete", c.apiServer)
|
||||
|
||||
data, err := json.Marshal(request)
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return err
|
||||
}
|
||||
|
||||
data, err = c.makeHttpRequest("POST", versionUrl, string(data))
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *OpenPitrixClient) makeHttpRequest(method, url, data string) ([]byte, error) {
|
||||
var req *http.Request
|
||||
|
||||
var err error
|
||||
if method == "GET" {
|
||||
req, err = http.NewRequest(method, url, nil)
|
||||
} else {
|
||||
req, err = http.NewRequest(method, url, strings.NewReader(data))
|
||||
}
|
||||
|
||||
req.Header.Add("Authorization", c.token)
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Request to %s failed, method: %s,token: %s, reason: %s ", url, method, c.apiServer, err)
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode >= http.StatusBadRequest {
|
||||
err = fmt.Errorf(string(body))
|
||||
}
|
||||
return body, err
|
||||
}
|
||||
@@ -1,227 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 The KubeSphere Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
package openpitrix
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"k8s.io/klog"
|
||||
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func NewOpenPitrixClient(options *OpenPitrixOptions) (*OpenPitrixClient, error) {
|
||||
return &OpenPitrixClient{
|
||||
client: &http.Client{
|
||||
Timeout: time.Duration(3) * time.Second,
|
||||
},
|
||||
apiServer: options.APIServer,
|
||||
token: options.Token,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *OpenPitrixClient) CreateRuntime(runtime *RunTime) error {
|
||||
|
||||
data, err := json.Marshal(runtime)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(http.MethodPost, fmt.Sprintf("%s/v1/runtimes", c.apiServer), bytes.NewReader(data))
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.Header.Add("Content-Type", "application/json")
|
||||
req.Header.Add("Authorization", c.token)
|
||||
|
||||
resp, err := c.client.Do(req)
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
data, err = ioutil.ReadAll(resp.Body)
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return err
|
||||
}
|
||||
|
||||
if resp.StatusCode > http.StatusOK {
|
||||
err = Error{resp.StatusCode, string(data)}
|
||||
klog.Error(err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *OpenPitrixClient) deleteClusters(clusters []cluster) error {
|
||||
clusterId := make([]string, 0)
|
||||
|
||||
for _, cluster := range clusters {
|
||||
if cluster.Status != "deleted" && cluster.Status != "deleting" && !sliceutil.HasString(clusterId, cluster.ClusterId) {
|
||||
clusterId = append(clusterId, cluster.ClusterId)
|
||||
}
|
||||
}
|
||||
|
||||
if len(clusterId) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
deleteRequest := struct {
|
||||
ClusterId []string `json:"cluster_id"`
|
||||
}{
|
||||
ClusterId: clusterId,
|
||||
}
|
||||
data, _ := json.Marshal(deleteRequest)
|
||||
req, err := http.NewRequest(http.MethodPost, fmt.Sprintf("%s/v1/clusters/delete", c.apiServer), bytes.NewReader(data))
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.Header.Add("Authorization", c.token)
|
||||
|
||||
resp, err := c.client.Do(req)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return err
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
data, err = ioutil.ReadAll(resp.Body)
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return err
|
||||
}
|
||||
|
||||
if resp.StatusCode > http.StatusOK {
|
||||
err = Error{resp.StatusCode, string(data)}
|
||||
klog.Error(err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *OpenPitrixClient) listClusters(runtimeId string) ([]cluster, error) {
|
||||
limit := 200
|
||||
offset := 0
|
||||
clusters := make([]cluster, 0)
|
||||
for {
|
||||
req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%s/v1/clusters?runtime_id=%s&limit=%d&offset=%d", c.apiServer, runtimeId, limit, offset), nil)
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req.Header.Add("Authorization", c.token)
|
||||
|
||||
resp, err := c.client.Do(req)
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
data, err := ioutil.ReadAll(resp.Body)
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp.Body.Close()
|
||||
|
||||
if resp.StatusCode > http.StatusOK {
|
||||
err = Error{resp.StatusCode, string(data)}
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
listClusterResponse := struct {
|
||||
TotalCount int `json:"total_count"`
|
||||
ClusterSet []cluster `json:"cluster_set"`
|
||||
}{}
|
||||
err = json.Unmarshal(data, &listClusterResponse)
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
clusters = append(clusters, listClusterResponse.ClusterSet...)
|
||||
|
||||
if listClusterResponse.TotalCount <= limit+offset {
|
||||
break
|
||||
}
|
||||
|
||||
offset += limit
|
||||
}
|
||||
|
||||
return clusters, nil
|
||||
}
|
||||
|
||||
func (c *OpenPitrixClient) DeleteRuntime(runtimeId string) error {
|
||||
clusters, err := c.listClusters(runtimeId)
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return err
|
||||
}
|
||||
|
||||
err = c.deleteClusters(clusters)
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func IsNotFound(err error) bool {
|
||||
if e, ok := err.(Error); ok {
|
||||
if e.status == http.StatusNotFound {
|
||||
return true
|
||||
}
|
||||
if strings.Contains(e.message, "not exist") {
|
||||
return true
|
||||
}
|
||||
if strings.Contains(e.message, "not found") {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func IsDeleted(err error) bool {
|
||||
if e, ok := err.(Error); ok {
|
||||
if strings.Contains(e.message, "is [deleted]") {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
243
pkg/simple/client/openpitrix/openpitrixclient.go
Normal file
243
pkg/simple/client/openpitrix/openpitrixclient.go
Normal file
@@ -0,0 +1,243 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 The KubeSphere Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
*/
|
||||
package openpitrix
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"k8s.io/klog"
|
||||
"openpitrix.io/openpitrix/pkg/manager"
|
||||
"openpitrix.io/openpitrix/pkg/pb"
|
||||
"openpitrix.io/openpitrix/pkg/sender"
|
||||
"openpitrix.io/openpitrix/pkg/util/ctxutil"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
KubernetesProvider = "kubernetes"
|
||||
Unknown = "-"
|
||||
DeploySuffix = "-Deployment"
|
||||
DaemonSuffix = "-DaemonSet"
|
||||
StateSuffix = "-StatefulSet"
|
||||
SystemUsername = "system"
|
||||
SystemUserPath = ":system"
|
||||
)
|
||||
|
||||
type OpenPitrixClient struct {
|
||||
runtime pb.RuntimeManagerClient
|
||||
cluster pb.ClusterManagerClient
|
||||
app pb.AppManagerClient
|
||||
repo pb.RepoManagerClient
|
||||
category pb.CategoryManagerClient
|
||||
attachment pb.AttachmentManagerClient
|
||||
repoIndexer pb.RepoIndexerClient
|
||||
}
|
||||
|
||||
func parseToHostPort(endpoint string) (string, int, error) {
|
||||
args := strings.Split(endpoint, ":")
|
||||
if len(args) != 2 {
|
||||
return "", 0, fmt.Errorf("invalid server host: %s", endpoint)
|
||||
}
|
||||
host := args[0]
|
||||
port, err := strconv.Atoi(args[1])
|
||||
if err != nil {
|
||||
return "", 0, err
|
||||
}
|
||||
return host, port, nil
|
||||
}
|
||||
|
||||
func newRuntimeManagerClient(endpoint string) (pb.RuntimeManagerClient, error) {
|
||||
host, port, err := parseToHostPort(endpoint)
|
||||
conn, err := manager.NewClient(host, port)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return pb.NewRuntimeManagerClient(conn), nil
|
||||
}
|
||||
func newClusterManagerClient(endpoint string) (pb.ClusterManagerClient, error) {
|
||||
host, port, err := parseToHostPort(endpoint)
|
||||
conn, err := manager.NewClient(host, port)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return pb.NewClusterManagerClient(conn), nil
|
||||
}
|
||||
func newCategoryManagerClient(endpoint string) (pb.CategoryManagerClient, error) {
|
||||
host, port, err := parseToHostPort(endpoint)
|
||||
conn, err := manager.NewClient(host, port)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return pb.NewCategoryManagerClient(conn), nil
|
||||
}
|
||||
|
||||
func newAttachmentManagerClient(endpoint string) (pb.AttachmentManagerClient, error) {
|
||||
host, port, err := parseToHostPort(endpoint)
|
||||
conn, err := manager.NewClient(host, port)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return pb.NewAttachmentManagerClient(conn), nil
|
||||
}
|
||||
|
||||
func newRepoManagerClient(endpoint string) (pb.RepoManagerClient, error) {
|
||||
host, port, err := parseToHostPort(endpoint)
|
||||
conn, err := manager.NewClient(host, port)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return pb.NewRepoManagerClient(conn), nil
|
||||
}
|
||||
|
||||
func newRepoIndexer(endpoint string) (pb.RepoIndexerClient, error) {
|
||||
host, port, err := parseToHostPort(endpoint)
|
||||
conn, err := manager.NewClient(host, port)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return pb.NewRepoIndexerClient(conn), nil
|
||||
}
|
||||
|
||||
func newAppManagerClient(endpoint string) (pb.AppManagerClient, error) {
|
||||
host, port, err := parseToHostPort(endpoint)
|
||||
conn, err := manager.NewClient(host, port)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return pb.NewAppManagerClient(conn), nil
|
||||
}
|
||||
|
||||
func NewOpenPitrixClient(options *OpenPitrixOptions) (*OpenPitrixClient, error) {
|
||||
|
||||
runtimeMangerClient, err := newRuntimeManagerClient(options.RuntimeManagerEndpoint)
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
clusterManagerClient, err := newClusterManagerClient(options.ClusterManagerEndpoint)
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
repoManagerClient, err := newRepoManagerClient(options.RepoManagerEndpoint)
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
repoIndexerClient, err := newRepoIndexer(options.RepoIndexerEndpoint)
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
appManagerClient, err := newAppManagerClient(options.AppManagerEndpoint)
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
categoryManagerClient, err := newCategoryManagerClient(options.CategoryManagerEndpoint)
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
attachmentManagerClient, err := newAttachmentManagerClient(options.AttachmentManagerEndpoint)
|
||||
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
client := OpenPitrixClient{
|
||||
runtime: runtimeMangerClient,
|
||||
cluster: clusterManagerClient,
|
||||
repo: repoManagerClient,
|
||||
app: appManagerClient,
|
||||
category: categoryManagerClient,
|
||||
attachment: attachmentManagerClient,
|
||||
repoIndexer: repoIndexerClient,
|
||||
}
|
||||
|
||||
return &client, nil
|
||||
}
|
||||
func (c *OpenPitrixClient) Runtime() pb.RuntimeManagerClient {
|
||||
return c.runtime
|
||||
}
|
||||
func (c *OpenPitrixClient) App() pb.AppManagerClient {
|
||||
return c.app
|
||||
}
|
||||
func (c *OpenPitrixClient) Cluster() pb.ClusterManagerClient {
|
||||
return c.cluster
|
||||
}
|
||||
func (c *OpenPitrixClient) Category() pb.CategoryManagerClient {
|
||||
return c.category
|
||||
}
|
||||
|
||||
func (c *OpenPitrixClient) Repo() pb.RepoManagerClient {
|
||||
return c.repo
|
||||
}
|
||||
|
||||
func (c *OpenPitrixClient) RepoIndexer() pb.RepoIndexerClient {
|
||||
return c.repoIndexer
|
||||
}
|
||||
|
||||
func (c *OpenPitrixClient) Attachment() pb.AttachmentManagerClient {
|
||||
return c.attachment
|
||||
}
|
||||
|
||||
func SystemContext() context.Context {
|
||||
ctx := context.Background()
|
||||
ctx = ctxutil.ContextWithSender(ctx, sender.New(SystemUsername, SystemUserPath, ""))
|
||||
return ctx
|
||||
}
|
||||
func ContextWithUsername(username string) context.Context {
|
||||
ctx := context.Background()
|
||||
if username == "" {
|
||||
username = SystemUsername
|
||||
}
|
||||
ctx = ctxutil.ContextWithSender(ctx, sender.New(username, SystemUserPath, ""))
|
||||
return ctx
|
||||
}
|
||||
|
||||
func IsNotFound(err error) bool {
|
||||
if strings.Contains(err.Error(), "not exist") {
|
||||
return true
|
||||
}
|
||||
if strings.Contains(err.Error(), "not found") {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func IsDeleted(err error) bool {
|
||||
if strings.Contains(err.Error(), "is [deleted]") {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -7,29 +7,72 @@ import (
|
||||
)
|
||||
|
||||
type OpenPitrixOptions struct {
|
||||
APIServer string `json:"apiServer,omitempty" yaml:"apiServer"`
|
||||
Token string `json:"token,omitempty" yaml:"token"`
|
||||
RuntimeManagerEndpoint string `json:"runtimeManagerEndpoint,omitempty" yaml:"runtimeManagerEndpoint,omitempty"`
|
||||
ClusterManagerEndpoint string `json:"clusterManagerEndpoint,omitempty" yaml:"clusterManagerEndpoint,omitempty"`
|
||||
RepoManagerEndpoint string `json:"repoManagerEndpoint,omitempty" yaml:"repoManagerEndpoint,omitempty"`
|
||||
AppManagerEndpoint string `json:"appManagerEndpoint,omitempty" yaml:"appManagerEndpoint,omitempty"`
|
||||
CategoryManagerEndpoint string `json:"categoryManagerEndpoint,omitempty" yaml:"categoryManagerEndpoint,omitempty"`
|
||||
AttachmentManagerEndpoint string `json:"attachmentManagerEndpoint,omitempty" yaml:"attachmentManagerEndpoint,omitempty"`
|
||||
RepoIndexerEndpoint string `json:"repoIndexerEndpoint,omitempty" yaml:"repoIndexerEndpoint,omitempty"`
|
||||
}
|
||||
|
||||
func NewOpenPitrixOptions() *OpenPitrixOptions {
|
||||
return &OpenPitrixOptions{
|
||||
APIServer: "",
|
||||
Token: "",
|
||||
}
|
||||
return &OpenPitrixOptions{}
|
||||
}
|
||||
|
||||
func (s *OpenPitrixOptions) ApplyTo(options *OpenPitrixOptions) {
|
||||
if s.APIServer != "" {
|
||||
if options == nil {
|
||||
options = s
|
||||
return
|
||||
}
|
||||
if s.RuntimeManagerEndpoint != "" {
|
||||
reflectutils.Override(options, s)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *OpenPitrixOptions) Validate() []error {
|
||||
errs := []error{}
|
||||
var errs []error
|
||||
|
||||
if s.APIServer != "" {
|
||||
if s.Token == "" {
|
||||
errs = append(errs, fmt.Errorf("OpenPitrix access token cannot be empty"))
|
||||
if s.RuntimeManagerEndpoint != "" {
|
||||
_, _, err := parseToHostPort(s.RuntimeManagerEndpoint)
|
||||
if err != nil {
|
||||
errs = append(errs, fmt.Errorf("invalid host port:%s", s.RuntimeManagerEndpoint))
|
||||
}
|
||||
}
|
||||
if s.ClusterManagerEndpoint != "" {
|
||||
_, _, err := parseToHostPort(s.ClusterManagerEndpoint)
|
||||
if err != nil {
|
||||
errs = append(errs, fmt.Errorf("invalid host port:%s", s.ClusterManagerEndpoint))
|
||||
}
|
||||
}
|
||||
if s.RepoManagerEndpoint != "" {
|
||||
_, _, err := parseToHostPort(s.RepoManagerEndpoint)
|
||||
if err != nil {
|
||||
errs = append(errs, fmt.Errorf("invalid host port:%s", s.RepoManagerEndpoint))
|
||||
}
|
||||
}
|
||||
if s.RepoIndexerEndpoint != "" {
|
||||
_, _, err := parseToHostPort(s.RepoIndexerEndpoint)
|
||||
if err != nil {
|
||||
errs = append(errs, fmt.Errorf("invalid host port:%s", s.RepoIndexerEndpoint))
|
||||
}
|
||||
}
|
||||
if s.AppManagerEndpoint != "" {
|
||||
_, _, err := parseToHostPort(s.AppManagerEndpoint)
|
||||
if err != nil {
|
||||
errs = append(errs, fmt.Errorf("invalid host port:%s", s.AppManagerEndpoint))
|
||||
}
|
||||
}
|
||||
if s.CategoryManagerEndpoint != "" {
|
||||
_, _, err := parseToHostPort(s.CategoryManagerEndpoint)
|
||||
if err != nil {
|
||||
errs = append(errs, fmt.Errorf("invalid host port:%s", s.CategoryManagerEndpoint))
|
||||
}
|
||||
}
|
||||
if s.AttachmentManagerEndpoint != "" {
|
||||
_, _, err := parseToHostPort(s.CategoryManagerEndpoint)
|
||||
if err != nil {
|
||||
errs = append(errs, fmt.Errorf("invalid host port:%s", s.CategoryManagerEndpoint))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,9 +80,24 @@ func (s *OpenPitrixOptions) Validate() []error {
|
||||
}
|
||||
|
||||
func (s *OpenPitrixOptions) AddFlags(fs *pflag.FlagSet) {
|
||||
fs.StringVar(&s.APIServer, "openpitrix-apiserver", s.APIServer, ""+
|
||||
"OpenPitrix api gateway endpoint, if left blank, following options will be ignored.")
|
||||
fs.StringVar(&s.RuntimeManagerEndpoint, "openpitrix-runtime-manager-endpoint", s.RuntimeManagerEndpoint, ""+
|
||||
"OpenPitrix runtime manager endpoint")
|
||||
|
||||
fs.StringVar(&s.Token, "openpitrix-token", s.Token, ""+
|
||||
"OpenPitrix api access token.")
|
||||
fs.StringVar(&s.AppManagerEndpoint, "openpitrix-app-manager-endpoint", s.AppManagerEndpoint, ""+
|
||||
"OpenPitrix app manager endpoint")
|
||||
|
||||
fs.StringVar(&s.ClusterManagerEndpoint, "openpitrix-cluster-manager-endpoint", s.ClusterManagerEndpoint, ""+
|
||||
"OpenPitrix cluster manager endpoint")
|
||||
|
||||
fs.StringVar(&s.CategoryManagerEndpoint, "openpitrix-category-manager-endpoint", s.CategoryManagerEndpoint, ""+
|
||||
"OpenPitrix category manager endpoint")
|
||||
|
||||
fs.StringVar(&s.RepoManagerEndpoint, "openpitrix-repo-manager-endpoint", s.RepoManagerEndpoint, ""+
|
||||
"OpenPitrix repo manager endpoint")
|
||||
|
||||
fs.StringVar(&s.RepoIndexerEndpoint, "openpitrix-repo-indexer-endpoint", s.RepoIndexerEndpoint, ""+
|
||||
"OpenPitrix repo indexer endpoint")
|
||||
|
||||
fs.StringVar(&s.AttachmentManagerEndpoint, "openpitrix-attachment-manager-endpoint", s.AttachmentManagerEndpoint, ""+
|
||||
"OpenPitrix attachment manager endpoint")
|
||||
}
|
||||
|
||||
@@ -1,117 +0,0 @@
|
||||
package openpitrix
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Cluster struct {
|
||||
ClusterID string `json:"cluster_id"`
|
||||
Name string `json:"name"`
|
||||
AppID string `json:"app_id"`
|
||||
VersionID string `json:"version_id"`
|
||||
Status string `json:"status"`
|
||||
UpdateTime time.Time `json:"status_time"`
|
||||
CreateTime time.Time `json:"create_time"`
|
||||
RunTimeId string `json:"runtime_id"`
|
||||
Description string `json:"description"`
|
||||
ClusterRoleSets []ClusterRole `json:"cluster_role_set"`
|
||||
}
|
||||
|
||||
type ClusterRole struct {
|
||||
ClusterID string `json:"cluster_id"`
|
||||
Role string `json:"role"`
|
||||
}
|
||||
|
||||
type ClusterList struct {
|
||||
Total int `json:"total_count"`
|
||||
Clusters []Cluster `json:"cluster_set"`
|
||||
}
|
||||
|
||||
type VersionList struct {
|
||||
Total int `json:"total_count"`
|
||||
Versions []version `json:"app_version_set"`
|
||||
}
|
||||
|
||||
type version struct {
|
||||
Name string `json:"name"`
|
||||
VersionID string `json:"version_id"`
|
||||
}
|
||||
|
||||
type runtime struct {
|
||||
RuntimeID string `json:"runtime_id"`
|
||||
Zone string `json:"zone"`
|
||||
}
|
||||
|
||||
type runtimeList struct {
|
||||
Total int `json:"total_count"`
|
||||
Runtimes []runtime `json:"runtime_set"`
|
||||
}
|
||||
|
||||
type app struct {
|
||||
AppId string `json:"app_id"`
|
||||
Name string `json:"name"`
|
||||
ChartName string `json:"chart_name"`
|
||||
RepoId string `json:"repo_id"`
|
||||
}
|
||||
|
||||
type repo struct {
|
||||
RepoId string `json:"repo_id"`
|
||||
Name string `json:"name"`
|
||||
Url string `json:"url"`
|
||||
}
|
||||
|
||||
type appList struct {
|
||||
Total int `json:"total_count"`
|
||||
Apps []app `json:"app_set"`
|
||||
}
|
||||
|
||||
type repoList struct {
|
||||
Total int `json:"total_count"`
|
||||
Repos []repo `json:"repo_set"`
|
||||
}
|
||||
|
||||
type CreateClusterRequest struct {
|
||||
AppId string `json:"app_id" description:"ID of app to run in cluster, e.g. app-AA3A3y3zEgEM"`
|
||||
VersionId string `json:"version_id" description:"app version, e.g. appv-154gXYx5RKRp"`
|
||||
RuntimeId string `json:"runtime_id" description:"ID of runtime, e.g. runtime-wWwXL0LzWqEr"`
|
||||
Conf string `json:"conf" description:"conf a json string, include cpu, memory info of cluster"`
|
||||
}
|
||||
|
||||
type DeleteClusterRequest struct {
|
||||
ClusterId []string `json:"cluster_id" description:"cluster ID"`
|
||||
}
|
||||
|
||||
type RunTime struct {
|
||||
RuntimeId string `json:"runtime_id"`
|
||||
RuntimeUrl string `json:"runtime_url"`
|
||||
Name string `json:"name"`
|
||||
Provider string `json:"provider"`
|
||||
Zone string `json:"zone"`
|
||||
RuntimeCredential string `json:"runtime_credential"`
|
||||
}
|
||||
|
||||
type Interface interface {
|
||||
CreateRuntime(runtime *RunTime) error
|
||||
DeleteRuntime(runtimeId string) error
|
||||
}
|
||||
type cluster struct {
|
||||
Status string `json:"status"`
|
||||
ClusterId string `json:"cluster_id"`
|
||||
}
|
||||
|
||||
type Error struct {
|
||||
status int
|
||||
message string
|
||||
}
|
||||
|
||||
func (e Error) Error() string {
|
||||
return fmt.Sprintf("status: %d,message: %s", e.status, e.message)
|
||||
}
|
||||
|
||||
type OpenPitrixClient struct {
|
||||
client *http.Client
|
||||
apiServer string
|
||||
token string
|
||||
}
|
||||
@@ -34,10 +34,12 @@ import (
|
||||
_ "kubesphere.io/kubesphere/pkg/apis/iam/install"
|
||||
_ "kubesphere.io/kubesphere/pkg/apis/logging/install"
|
||||
_ "kubesphere.io/kubesphere/pkg/apis/monitoring/install"
|
||||
_ "kubesphere.io/kubesphere/pkg/apis/openpitrix/install"
|
||||
_ "kubesphere.io/kubesphere/pkg/apis/operations/install"
|
||||
_ "kubesphere.io/kubesphere/pkg/apis/resources/install"
|
||||
_ "kubesphere.io/kubesphere/pkg/apis/servicemesh/metrics/install"
|
||||
_ "kubesphere.io/kubesphere/pkg/apis/tenant/install"
|
||||
_ "kubesphere.io/kubesphere/pkg/apis/terminal/install"
|
||||
)
|
||||
|
||||
var output string
|
||||
|
||||
5
vendor/github.com/BurntSushi/toml/.gitignore
generated
vendored
Normal file
5
vendor/github.com/BurntSushi/toml/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
TAGS
|
||||
tags
|
||||
.*.swp
|
||||
tomlcheck/tomlcheck
|
||||
toml.test
|
||||
15
vendor/github.com/BurntSushi/toml/.travis.yml
generated
vendored
Normal file
15
vendor/github.com/BurntSushi/toml/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
language: go
|
||||
go:
|
||||
- 1.1
|
||||
- 1.2
|
||||
- 1.3
|
||||
- 1.4
|
||||
- 1.5
|
||||
- 1.6
|
||||
- tip
|
||||
install:
|
||||
- go install ./...
|
||||
- go get github.com/BurntSushi/toml-test
|
||||
script:
|
||||
- export PATH="$PATH:$HOME/gopath/bin"
|
||||
- make test
|
||||
3
vendor/github.com/BurntSushi/toml/COMPATIBLE
generated
vendored
Normal file
3
vendor/github.com/BurntSushi/toml/COMPATIBLE
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
Compatible with TOML version
|
||||
[v0.4.0](https://github.com/toml-lang/toml/blob/v0.4.0/versions/en/toml-v0.4.0.md)
|
||||
|
||||
21
vendor/github.com/BurntSushi/toml/COPYING
generated
vendored
Normal file
21
vendor/github.com/BurntSushi/toml/COPYING
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013 TOML authors
|
||||
|
||||
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.
|
||||
19
vendor/github.com/BurntSushi/toml/Makefile
generated
vendored
Normal file
19
vendor/github.com/BurntSushi/toml/Makefile
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
install:
|
||||
go install ./...
|
||||
|
||||
test: install
|
||||
go test -v
|
||||
toml-test toml-test-decoder
|
||||
toml-test -encoder toml-test-encoder
|
||||
|
||||
fmt:
|
||||
gofmt -w *.go */*.go
|
||||
colcheck *.go */*.go
|
||||
|
||||
tags:
|
||||
find ./ -name '*.go' -print0 | xargs -0 gotags > TAGS
|
||||
|
||||
push:
|
||||
git push origin master
|
||||
git push github master
|
||||
|
||||
218
vendor/github.com/BurntSushi/toml/README.md
generated
vendored
Normal file
218
vendor/github.com/BurntSushi/toml/README.md
generated
vendored
Normal file
@@ -0,0 +1,218 @@
|
||||
## TOML parser and encoder for Go with reflection
|
||||
|
||||
TOML stands for Tom's Obvious, Minimal Language. This Go package provides a
|
||||
reflection interface similar to Go's standard library `json` and `xml`
|
||||
packages. This package also supports the `encoding.TextUnmarshaler` and
|
||||
`encoding.TextMarshaler` interfaces so that you can define custom data
|
||||
representations. (There is an example of this below.)
|
||||
|
||||
Spec: https://github.com/toml-lang/toml
|
||||
|
||||
Compatible with TOML version
|
||||
[v0.4.0](https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.4.0.md)
|
||||
|
||||
Documentation: https://godoc.org/github.com/BurntSushi/toml
|
||||
|
||||
Installation:
|
||||
|
||||
```bash
|
||||
go get github.com/BurntSushi/toml
|
||||
```
|
||||
|
||||
Try the toml validator:
|
||||
|
||||
```bash
|
||||
go get github.com/BurntSushi/toml/cmd/tomlv
|
||||
tomlv some-toml-file.toml
|
||||
```
|
||||
|
||||
[](https://travis-ci.org/BurntSushi/toml) [](https://godoc.org/github.com/BurntSushi/toml)
|
||||
|
||||
### Testing
|
||||
|
||||
This package passes all tests in
|
||||
[toml-test](https://github.com/BurntSushi/toml-test) for both the decoder
|
||||
and the encoder.
|
||||
|
||||
### Examples
|
||||
|
||||
This package works similarly to how the Go standard library handles `XML`
|
||||
and `JSON`. Namely, data is loaded into Go values via reflection.
|
||||
|
||||
For the simplest example, consider some TOML file as just a list of keys
|
||||
and values:
|
||||
|
||||
```toml
|
||||
Age = 25
|
||||
Cats = [ "Cauchy", "Plato" ]
|
||||
Pi = 3.14
|
||||
Perfection = [ 6, 28, 496, 8128 ]
|
||||
DOB = 1987-07-05T05:45:00Z
|
||||
```
|
||||
|
||||
Which could be defined in Go as:
|
||||
|
||||
```go
|
||||
type Config struct {
|
||||
Age int
|
||||
Cats []string
|
||||
Pi float64
|
||||
Perfection []int
|
||||
DOB time.Time // requires `import time`
|
||||
}
|
||||
```
|
||||
|
||||
And then decoded with:
|
||||
|
||||
```go
|
||||
var conf Config
|
||||
if _, err := toml.Decode(tomlData, &conf); err != nil {
|
||||
// handle error
|
||||
}
|
||||
```
|
||||
|
||||
You can also use struct tags if your struct field name doesn't map to a TOML
|
||||
key value directly:
|
||||
|
||||
```toml
|
||||
some_key_NAME = "wat"
|
||||
```
|
||||
|
||||
```go
|
||||
type TOML struct {
|
||||
ObscureKey string `toml:"some_key_NAME"`
|
||||
}
|
||||
```
|
||||
|
||||
### Using the `encoding.TextUnmarshaler` interface
|
||||
|
||||
Here's an example that automatically parses duration strings into
|
||||
`time.Duration` values:
|
||||
|
||||
```toml
|
||||
[[song]]
|
||||
name = "Thunder Road"
|
||||
duration = "4m49s"
|
||||
|
||||
[[song]]
|
||||
name = "Stairway to Heaven"
|
||||
duration = "8m03s"
|
||||
```
|
||||
|
||||
Which can be decoded with:
|
||||
|
||||
```go
|
||||
type song struct {
|
||||
Name string
|
||||
Duration duration
|
||||
}
|
||||
type songs struct {
|
||||
Song []song
|
||||
}
|
||||
var favorites songs
|
||||
if _, err := toml.Decode(blob, &favorites); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
for _, s := range favorites.Song {
|
||||
fmt.Printf("%s (%s)\n", s.Name, s.Duration)
|
||||
}
|
||||
```
|
||||
|
||||
And you'll also need a `duration` type that satisfies the
|
||||
`encoding.TextUnmarshaler` interface:
|
||||
|
||||
```go
|
||||
type duration struct {
|
||||
time.Duration
|
||||
}
|
||||
|
||||
func (d *duration) UnmarshalText(text []byte) error {
|
||||
var err error
|
||||
d.Duration, err = time.ParseDuration(string(text))
|
||||
return err
|
||||
}
|
||||
```
|
||||
|
||||
### More complex usage
|
||||
|
||||
Here's an example of how to load the example from the official spec page:
|
||||
|
||||
```toml
|
||||
# This is a TOML document. Boom.
|
||||
|
||||
title = "TOML Example"
|
||||
|
||||
[owner]
|
||||
name = "Tom Preston-Werner"
|
||||
organization = "GitHub"
|
||||
bio = "GitHub Cofounder & CEO\nLikes tater tots and beer."
|
||||
dob = 1979-05-27T07:32:00Z # First class dates? Why not?
|
||||
|
||||
[database]
|
||||
server = "192.168.1.1"
|
||||
ports = [ 8001, 8001, 8002 ]
|
||||
connection_max = 5000
|
||||
enabled = true
|
||||
|
||||
[servers]
|
||||
|
||||
# You can indent as you please. Tabs or spaces. TOML don't care.
|
||||
[servers.alpha]
|
||||
ip = "10.0.0.1"
|
||||
dc = "eqdc10"
|
||||
|
||||
[servers.beta]
|
||||
ip = "10.0.0.2"
|
||||
dc = "eqdc10"
|
||||
|
||||
[clients]
|
||||
data = [ ["gamma", "delta"], [1, 2] ] # just an update to make sure parsers support it
|
||||
|
||||
# Line breaks are OK when inside arrays
|
||||
hosts = [
|
||||
"alpha",
|
||||
"omega"
|
||||
]
|
||||
```
|
||||
|
||||
And the corresponding Go types are:
|
||||
|
||||
```go
|
||||
type tomlConfig struct {
|
||||
Title string
|
||||
Owner ownerInfo
|
||||
DB database `toml:"database"`
|
||||
Servers map[string]server
|
||||
Clients clients
|
||||
}
|
||||
|
||||
type ownerInfo struct {
|
||||
Name string
|
||||
Org string `toml:"organization"`
|
||||
Bio string
|
||||
DOB time.Time
|
||||
}
|
||||
|
||||
type database struct {
|
||||
Server string
|
||||
Ports []int
|
||||
ConnMax int `toml:"connection_max"`
|
||||
Enabled bool
|
||||
}
|
||||
|
||||
type server struct {
|
||||
IP string
|
||||
DC string
|
||||
}
|
||||
|
||||
type clients struct {
|
||||
Data [][]interface{}
|
||||
Hosts []string
|
||||
}
|
||||
```
|
||||
|
||||
Note that a case insensitive match will be tried if an exact match can't be
|
||||
found.
|
||||
|
||||
A working example of the above can be found in `_examples/example.{go,toml}`.
|
||||
509
vendor/github.com/BurntSushi/toml/decode.go
generated
vendored
Normal file
509
vendor/github.com/BurntSushi/toml/decode.go
generated
vendored
Normal file
@@ -0,0 +1,509 @@
|
||||
package toml
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func e(format string, args ...interface{}) error {
|
||||
return fmt.Errorf("toml: "+format, args...)
|
||||
}
|
||||
|
||||
// Unmarshaler is the interface implemented by objects that can unmarshal a
|
||||
// TOML description of themselves.
|
||||
type Unmarshaler interface {
|
||||
UnmarshalTOML(interface{}) error
|
||||
}
|
||||
|
||||
// Unmarshal decodes the contents of `p` in TOML format into a pointer `v`.
|
||||
func Unmarshal(p []byte, v interface{}) error {
|
||||
_, err := Decode(string(p), v)
|
||||
return err
|
||||
}
|
||||
|
||||
// Primitive is a TOML value that hasn't been decoded into a Go value.
|
||||
// When using the various `Decode*` functions, the type `Primitive` may
|
||||
// be given to any value, and its decoding will be delayed.
|
||||
//
|
||||
// A `Primitive` value can be decoded using the `PrimitiveDecode` function.
|
||||
//
|
||||
// The underlying representation of a `Primitive` value is subject to change.
|
||||
// Do not rely on it.
|
||||
//
|
||||
// N.B. Primitive values are still parsed, so using them will only avoid
|
||||
// the overhead of reflection. They can be useful when you don't know the
|
||||
// exact type of TOML data until run time.
|
||||
type Primitive struct {
|
||||
undecoded interface{}
|
||||
context Key
|
||||
}
|
||||
|
||||
// DEPRECATED!
|
||||
//
|
||||
// Use MetaData.PrimitiveDecode instead.
|
||||
func PrimitiveDecode(primValue Primitive, v interface{}) error {
|
||||
md := MetaData{decoded: make(map[string]bool)}
|
||||
return md.unify(primValue.undecoded, rvalue(v))
|
||||
}
|
||||
|
||||
// PrimitiveDecode is just like the other `Decode*` functions, except it
|
||||
// decodes a TOML value that has already been parsed. Valid primitive values
|
||||
// can *only* be obtained from values filled by the decoder functions,
|
||||
// including this method. (i.e., `v` may contain more `Primitive`
|
||||
// values.)
|
||||
//
|
||||
// Meta data for primitive values is included in the meta data returned by
|
||||
// the `Decode*` functions with one exception: keys returned by the Undecoded
|
||||
// method will only reflect keys that were decoded. Namely, any keys hidden
|
||||
// behind a Primitive will be considered undecoded. Executing this method will
|
||||
// update the undecoded keys in the meta data. (See the example.)
|
||||
func (md *MetaData) PrimitiveDecode(primValue Primitive, v interface{}) error {
|
||||
md.context = primValue.context
|
||||
defer func() { md.context = nil }()
|
||||
return md.unify(primValue.undecoded, rvalue(v))
|
||||
}
|
||||
|
||||
// Decode will decode the contents of `data` in TOML format into a pointer
|
||||
// `v`.
|
||||
//
|
||||
// TOML hashes correspond to Go structs or maps. (Dealer's choice. They can be
|
||||
// used interchangeably.)
|
||||
//
|
||||
// TOML arrays of tables correspond to either a slice of structs or a slice
|
||||
// of maps.
|
||||
//
|
||||
// TOML datetimes correspond to Go `time.Time` values.
|
||||
//
|
||||
// All other TOML types (float, string, int, bool and array) correspond
|
||||
// to the obvious Go types.
|
||||
//
|
||||
// An exception to the above rules is if a type implements the
|
||||
// encoding.TextUnmarshaler interface. In this case, any primitive TOML value
|
||||
// (floats, strings, integers, booleans and datetimes) will be converted to
|
||||
// a byte string and given to the value's UnmarshalText method. See the
|
||||
// Unmarshaler example for a demonstration with time duration strings.
|
||||
//
|
||||
// Key mapping
|
||||
//
|
||||
// TOML keys can map to either keys in a Go map or field names in a Go
|
||||
// struct. The special `toml` struct tag may be used to map TOML keys to
|
||||
// struct fields that don't match the key name exactly. (See the example.)
|
||||
// A case insensitive match to struct names will be tried if an exact match
|
||||
// can't be found.
|
||||
//
|
||||
// The mapping between TOML values and Go values is loose. That is, there
|
||||
// may exist TOML values that cannot be placed into your representation, and
|
||||
// there may be parts of your representation that do not correspond to
|
||||
// TOML values. This loose mapping can be made stricter by using the IsDefined
|
||||
// and/or Undecoded methods on the MetaData returned.
|
||||
//
|
||||
// This decoder will not handle cyclic types. If a cyclic type is passed,
|
||||
// `Decode` will not terminate.
|
||||
func Decode(data string, v interface{}) (MetaData, error) {
|
||||
rv := reflect.ValueOf(v)
|
||||
if rv.Kind() != reflect.Ptr {
|
||||
return MetaData{}, e("Decode of non-pointer %s", reflect.TypeOf(v))
|
||||
}
|
||||
if rv.IsNil() {
|
||||
return MetaData{}, e("Decode of nil %s", reflect.TypeOf(v))
|
||||
}
|
||||
p, err := parse(data)
|
||||
if err != nil {
|
||||
return MetaData{}, err
|
||||
}
|
||||
md := MetaData{
|
||||
p.mapping, p.types, p.ordered,
|
||||
make(map[string]bool, len(p.ordered)), nil,
|
||||
}
|
||||
return md, md.unify(p.mapping, indirect(rv))
|
||||
}
|
||||
|
||||
// DecodeFile is just like Decode, except it will automatically read the
|
||||
// contents of the file at `fpath` and decode it for you.
|
||||
func DecodeFile(fpath string, v interface{}) (MetaData, error) {
|
||||
bs, err := ioutil.ReadFile(fpath)
|
||||
if err != nil {
|
||||
return MetaData{}, err
|
||||
}
|
||||
return Decode(string(bs), v)
|
||||
}
|
||||
|
||||
// DecodeReader is just like Decode, except it will consume all bytes
|
||||
// from the reader and decode it for you.
|
||||
func DecodeReader(r io.Reader, v interface{}) (MetaData, error) {
|
||||
bs, err := ioutil.ReadAll(r)
|
||||
if err != nil {
|
||||
return MetaData{}, err
|
||||
}
|
||||
return Decode(string(bs), v)
|
||||
}
|
||||
|
||||
// unify performs a sort of type unification based on the structure of `rv`,
|
||||
// which is the client representation.
|
||||
//
|
||||
// Any type mismatch produces an error. Finding a type that we don't know
|
||||
// how to handle produces an unsupported type error.
|
||||
func (md *MetaData) unify(data interface{}, rv reflect.Value) error {
|
||||
|
||||
// Special case. Look for a `Primitive` value.
|
||||
if rv.Type() == reflect.TypeOf((*Primitive)(nil)).Elem() {
|
||||
// Save the undecoded data and the key context into the primitive
|
||||
// value.
|
||||
context := make(Key, len(md.context))
|
||||
copy(context, md.context)
|
||||
rv.Set(reflect.ValueOf(Primitive{
|
||||
undecoded: data,
|
||||
context: context,
|
||||
}))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Special case. Unmarshaler Interface support.
|
||||
if rv.CanAddr() {
|
||||
if v, ok := rv.Addr().Interface().(Unmarshaler); ok {
|
||||
return v.UnmarshalTOML(data)
|
||||
}
|
||||
}
|
||||
|
||||
// Special case. Handle time.Time values specifically.
|
||||
// TODO: Remove this code when we decide to drop support for Go 1.1.
|
||||
// This isn't necessary in Go 1.2 because time.Time satisfies the encoding
|
||||
// interfaces.
|
||||
if rv.Type().AssignableTo(rvalue(time.Time{}).Type()) {
|
||||
return md.unifyDatetime(data, rv)
|
||||
}
|
||||
|
||||
// Special case. Look for a value satisfying the TextUnmarshaler interface.
|
||||
if v, ok := rv.Interface().(TextUnmarshaler); ok {
|
||||
return md.unifyText(data, v)
|
||||
}
|
||||
// BUG(burntsushi)
|
||||
// The behavior here is incorrect whenever a Go type satisfies the
|
||||
// encoding.TextUnmarshaler interface but also corresponds to a TOML
|
||||
// hash or array. In particular, the unmarshaler should only be applied
|
||||
// to primitive TOML values. But at this point, it will be applied to
|
||||
// all kinds of values and produce an incorrect error whenever those values
|
||||
// are hashes or arrays (including arrays of tables).
|
||||
|
||||
k := rv.Kind()
|
||||
|
||||
// laziness
|
||||
if k >= reflect.Int && k <= reflect.Uint64 {
|
||||
return md.unifyInt(data, rv)
|
||||
}
|
||||
switch k {
|
||||
case reflect.Ptr:
|
||||
elem := reflect.New(rv.Type().Elem())
|
||||
err := md.unify(data, reflect.Indirect(elem))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rv.Set(elem)
|
||||
return nil
|
||||
case reflect.Struct:
|
||||
return md.unifyStruct(data, rv)
|
||||
case reflect.Map:
|
||||
return md.unifyMap(data, rv)
|
||||
case reflect.Array:
|
||||
return md.unifyArray(data, rv)
|
||||
case reflect.Slice:
|
||||
return md.unifySlice(data, rv)
|
||||
case reflect.String:
|
||||
return md.unifyString(data, rv)
|
||||
case reflect.Bool:
|
||||
return md.unifyBool(data, rv)
|
||||
case reflect.Interface:
|
||||
// we only support empty interfaces.
|
||||
if rv.NumMethod() > 0 {
|
||||
return e("unsupported type %s", rv.Type())
|
||||
}
|
||||
return md.unifyAnything(data, rv)
|
||||
case reflect.Float32:
|
||||
fallthrough
|
||||
case reflect.Float64:
|
||||
return md.unifyFloat64(data, rv)
|
||||
}
|
||||
return e("unsupported type %s", rv.Kind())
|
||||
}
|
||||
|
||||
func (md *MetaData) unifyStruct(mapping interface{}, rv reflect.Value) error {
|
||||
tmap, ok := mapping.(map[string]interface{})
|
||||
if !ok {
|
||||
if mapping == nil {
|
||||
return nil
|
||||
}
|
||||
return e("type mismatch for %s: expected table but found %T",
|
||||
rv.Type().String(), mapping)
|
||||
}
|
||||
|
||||
for key, datum := range tmap {
|
||||
var f *field
|
||||
fields := cachedTypeFields(rv.Type())
|
||||
for i := range fields {
|
||||
ff := &fields[i]
|
||||
if ff.name == key {
|
||||
f = ff
|
||||
break
|
||||
}
|
||||
if f == nil && strings.EqualFold(ff.name, key) {
|
||||
f = ff
|
||||
}
|
||||
}
|
||||
if f != nil {
|
||||
subv := rv
|
||||
for _, i := range f.index {
|
||||
subv = indirect(subv.Field(i))
|
||||
}
|
||||
if isUnifiable(subv) {
|
||||
md.decoded[md.context.add(key).String()] = true
|
||||
md.context = append(md.context, key)
|
||||
if err := md.unify(datum, subv); err != nil {
|
||||
return err
|
||||
}
|
||||
md.context = md.context[0 : len(md.context)-1]
|
||||
} else if f.name != "" {
|
||||
// Bad user! No soup for you!
|
||||
return e("cannot write unexported field %s.%s",
|
||||
rv.Type().String(), f.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (md *MetaData) unifyMap(mapping interface{}, rv reflect.Value) error {
|
||||
tmap, ok := mapping.(map[string]interface{})
|
||||
if !ok {
|
||||
if tmap == nil {
|
||||
return nil
|
||||
}
|
||||
return badtype("map", mapping)
|
||||
}
|
||||
if rv.IsNil() {
|
||||
rv.Set(reflect.MakeMap(rv.Type()))
|
||||
}
|
||||
for k, v := range tmap {
|
||||
md.decoded[md.context.add(k).String()] = true
|
||||
md.context = append(md.context, k)
|
||||
|
||||
rvkey := indirect(reflect.New(rv.Type().Key()))
|
||||
rvval := reflect.Indirect(reflect.New(rv.Type().Elem()))
|
||||
if err := md.unify(v, rvval); err != nil {
|
||||
return err
|
||||
}
|
||||
md.context = md.context[0 : len(md.context)-1]
|
||||
|
||||
rvkey.SetString(k)
|
||||
rv.SetMapIndex(rvkey, rvval)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (md *MetaData) unifyArray(data interface{}, rv reflect.Value) error {
|
||||
datav := reflect.ValueOf(data)
|
||||
if datav.Kind() != reflect.Slice {
|
||||
if !datav.IsValid() {
|
||||
return nil
|
||||
}
|
||||
return badtype("slice", data)
|
||||
}
|
||||
sliceLen := datav.Len()
|
||||
if sliceLen != rv.Len() {
|
||||
return e("expected array length %d; got TOML array of length %d",
|
||||
rv.Len(), sliceLen)
|
||||
}
|
||||
return md.unifySliceArray(datav, rv)
|
||||
}
|
||||
|
||||
func (md *MetaData) unifySlice(data interface{}, rv reflect.Value) error {
|
||||
datav := reflect.ValueOf(data)
|
||||
if datav.Kind() != reflect.Slice {
|
||||
if !datav.IsValid() {
|
||||
return nil
|
||||
}
|
||||
return badtype("slice", data)
|
||||
}
|
||||
n := datav.Len()
|
||||
if rv.IsNil() || rv.Cap() < n {
|
||||
rv.Set(reflect.MakeSlice(rv.Type(), n, n))
|
||||
}
|
||||
rv.SetLen(n)
|
||||
return md.unifySliceArray(datav, rv)
|
||||
}
|
||||
|
||||
func (md *MetaData) unifySliceArray(data, rv reflect.Value) error {
|
||||
sliceLen := data.Len()
|
||||
for i := 0; i < sliceLen; i++ {
|
||||
v := data.Index(i).Interface()
|
||||
sliceval := indirect(rv.Index(i))
|
||||
if err := md.unify(v, sliceval); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (md *MetaData) unifyDatetime(data interface{}, rv reflect.Value) error {
|
||||
if _, ok := data.(time.Time); ok {
|
||||
rv.Set(reflect.ValueOf(data))
|
||||
return nil
|
||||
}
|
||||
return badtype("time.Time", data)
|
||||
}
|
||||
|
||||
func (md *MetaData) unifyString(data interface{}, rv reflect.Value) error {
|
||||
if s, ok := data.(string); ok {
|
||||
rv.SetString(s)
|
||||
return nil
|
||||
}
|
||||
return badtype("string", data)
|
||||
}
|
||||
|
||||
func (md *MetaData) unifyFloat64(data interface{}, rv reflect.Value) error {
|
||||
if num, ok := data.(float64); ok {
|
||||
switch rv.Kind() {
|
||||
case reflect.Float32:
|
||||
fallthrough
|
||||
case reflect.Float64:
|
||||
rv.SetFloat(num)
|
||||
default:
|
||||
panic("bug")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return badtype("float", data)
|
||||
}
|
||||
|
||||
func (md *MetaData) unifyInt(data interface{}, rv reflect.Value) error {
|
||||
if num, ok := data.(int64); ok {
|
||||
if rv.Kind() >= reflect.Int && rv.Kind() <= reflect.Int64 {
|
||||
switch rv.Kind() {
|
||||
case reflect.Int, reflect.Int64:
|
||||
// No bounds checking necessary.
|
||||
case reflect.Int8:
|
||||
if num < math.MinInt8 || num > math.MaxInt8 {
|
||||
return e("value %d is out of range for int8", num)
|
||||
}
|
||||
case reflect.Int16:
|
||||
if num < math.MinInt16 || num > math.MaxInt16 {
|
||||
return e("value %d is out of range for int16", num)
|
||||
}
|
||||
case reflect.Int32:
|
||||
if num < math.MinInt32 || num > math.MaxInt32 {
|
||||
return e("value %d is out of range for int32", num)
|
||||
}
|
||||
}
|
||||
rv.SetInt(num)
|
||||
} else if rv.Kind() >= reflect.Uint && rv.Kind() <= reflect.Uint64 {
|
||||
unum := uint64(num)
|
||||
switch rv.Kind() {
|
||||
case reflect.Uint, reflect.Uint64:
|
||||
// No bounds checking necessary.
|
||||
case reflect.Uint8:
|
||||
if num < 0 || unum > math.MaxUint8 {
|
||||
return e("value %d is out of range for uint8", num)
|
||||
}
|
||||
case reflect.Uint16:
|
||||
if num < 0 || unum > math.MaxUint16 {
|
||||
return e("value %d is out of range for uint16", num)
|
||||
}
|
||||
case reflect.Uint32:
|
||||
if num < 0 || unum > math.MaxUint32 {
|
||||
return e("value %d is out of range for uint32", num)
|
||||
}
|
||||
}
|
||||
rv.SetUint(unum)
|
||||
} else {
|
||||
panic("unreachable")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return badtype("integer", data)
|
||||
}
|
||||
|
||||
func (md *MetaData) unifyBool(data interface{}, rv reflect.Value) error {
|
||||
if b, ok := data.(bool); ok {
|
||||
rv.SetBool(b)
|
||||
return nil
|
||||
}
|
||||
return badtype("boolean", data)
|
||||
}
|
||||
|
||||
func (md *MetaData) unifyAnything(data interface{}, rv reflect.Value) error {
|
||||
rv.Set(reflect.ValueOf(data))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (md *MetaData) unifyText(data interface{}, v TextUnmarshaler) error {
|
||||
var s string
|
||||
switch sdata := data.(type) {
|
||||
case TextMarshaler:
|
||||
text, err := sdata.MarshalText()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s = string(text)
|
||||
case fmt.Stringer:
|
||||
s = sdata.String()
|
||||
case string:
|
||||
s = sdata
|
||||
case bool:
|
||||
s = fmt.Sprintf("%v", sdata)
|
||||
case int64:
|
||||
s = fmt.Sprintf("%d", sdata)
|
||||
case float64:
|
||||
s = fmt.Sprintf("%f", sdata)
|
||||
default:
|
||||
return badtype("primitive (string-like)", data)
|
||||
}
|
||||
if err := v.UnmarshalText([]byte(s)); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// rvalue returns a reflect.Value of `v`. All pointers are resolved.
|
||||
func rvalue(v interface{}) reflect.Value {
|
||||
return indirect(reflect.ValueOf(v))
|
||||
}
|
||||
|
||||
// indirect returns the value pointed to by a pointer.
|
||||
// Pointers are followed until the value is not a pointer.
|
||||
// New values are allocated for each nil pointer.
|
||||
//
|
||||
// An exception to this rule is if the value satisfies an interface of
|
||||
// interest to us (like encoding.TextUnmarshaler).
|
||||
func indirect(v reflect.Value) reflect.Value {
|
||||
if v.Kind() != reflect.Ptr {
|
||||
if v.CanSet() {
|
||||
pv := v.Addr()
|
||||
if _, ok := pv.Interface().(TextUnmarshaler); ok {
|
||||
return pv
|
||||
}
|
||||
}
|
||||
return v
|
||||
}
|
||||
if v.IsNil() {
|
||||
v.Set(reflect.New(v.Type().Elem()))
|
||||
}
|
||||
return indirect(reflect.Indirect(v))
|
||||
}
|
||||
|
||||
func isUnifiable(rv reflect.Value) bool {
|
||||
if rv.CanSet() {
|
||||
return true
|
||||
}
|
||||
if _, ok := rv.Interface().(TextUnmarshaler); ok {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func badtype(expected string, data interface{}) error {
|
||||
return e("cannot load TOML value of type %T into a Go %s", data, expected)
|
||||
}
|
||||
121
vendor/github.com/BurntSushi/toml/decode_meta.go
generated
vendored
Normal file
121
vendor/github.com/BurntSushi/toml/decode_meta.go
generated
vendored
Normal file
@@ -0,0 +1,121 @@
|
||||
package toml
|
||||
|
||||
import "strings"
|
||||
|
||||
// MetaData allows access to meta information about TOML data that may not
|
||||
// be inferrable via reflection. In particular, whether a key has been defined
|
||||
// and the TOML type of a key.
|
||||
type MetaData struct {
|
||||
mapping map[string]interface{}
|
||||
types map[string]tomlType
|
||||
keys []Key
|
||||
decoded map[string]bool
|
||||
context Key // Used only during decoding.
|
||||
}
|
||||
|
||||
// IsDefined returns true if the key given exists in the TOML data. The key
|
||||
// should be specified hierarchially. e.g.,
|
||||
//
|
||||
// // access the TOML key 'a.b.c'
|
||||
// IsDefined("a", "b", "c")
|
||||
//
|
||||
// IsDefined will return false if an empty key given. Keys are case sensitive.
|
||||
func (md *MetaData) IsDefined(key ...string) bool {
|
||||
if len(key) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
var hash map[string]interface{}
|
||||
var ok bool
|
||||
var hashOrVal interface{} = md.mapping
|
||||
for _, k := range key {
|
||||
if hash, ok = hashOrVal.(map[string]interface{}); !ok {
|
||||
return false
|
||||
}
|
||||
if hashOrVal, ok = hash[k]; !ok {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Type returns a string representation of the type of the key specified.
|
||||
//
|
||||
// Type will return the empty string if given an empty key or a key that
|
||||
// does not exist. Keys are case sensitive.
|
||||
func (md *MetaData) Type(key ...string) string {
|
||||
fullkey := strings.Join(key, ".")
|
||||
if typ, ok := md.types[fullkey]; ok {
|
||||
return typ.typeString()
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// Key is the type of any TOML key, including key groups. Use (MetaData).Keys
|
||||
// to get values of this type.
|
||||
type Key []string
|
||||
|
||||
func (k Key) String() string {
|
||||
return strings.Join(k, ".")
|
||||
}
|
||||
|
||||
func (k Key) maybeQuotedAll() string {
|
||||
var ss []string
|
||||
for i := range k {
|
||||
ss = append(ss, k.maybeQuoted(i))
|
||||
}
|
||||
return strings.Join(ss, ".")
|
||||
}
|
||||
|
||||
func (k Key) maybeQuoted(i int) string {
|
||||
quote := false
|
||||
for _, c := range k[i] {
|
||||
if !isBareKeyChar(c) {
|
||||
quote = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if quote {
|
||||
return "\"" + strings.Replace(k[i], "\"", "\\\"", -1) + "\""
|
||||
}
|
||||
return k[i]
|
||||
}
|
||||
|
||||
func (k Key) add(piece string) Key {
|
||||
newKey := make(Key, len(k)+1)
|
||||
copy(newKey, k)
|
||||
newKey[len(k)] = piece
|
||||
return newKey
|
||||
}
|
||||
|
||||
// Keys returns a slice of every key in the TOML data, including key groups.
|
||||
// Each key is itself a slice, where the first element is the top of the
|
||||
// hierarchy and the last is the most specific.
|
||||
//
|
||||
// The list will have the same order as the keys appeared in the TOML data.
|
||||
//
|
||||
// All keys returned are non-empty.
|
||||
func (md *MetaData) Keys() []Key {
|
||||
return md.keys
|
||||
}
|
||||
|
||||
// Undecoded returns all keys that have not been decoded in the order in which
|
||||
// they appear in the original TOML document.
|
||||
//
|
||||
// This includes keys that haven't been decoded because of a Primitive value.
|
||||
// Once the Primitive value is decoded, the keys will be considered decoded.
|
||||
//
|
||||
// Also note that decoding into an empty interface will result in no decoding,
|
||||
// and so no keys will be considered decoded.
|
||||
//
|
||||
// In this sense, the Undecoded keys correspond to keys in the TOML document
|
||||
// that do not have a concrete type in your representation.
|
||||
func (md *MetaData) Undecoded() []Key {
|
||||
undecoded := make([]Key, 0, len(md.keys))
|
||||
for _, key := range md.keys {
|
||||
if !md.decoded[key.String()] {
|
||||
undecoded = append(undecoded, key)
|
||||
}
|
||||
}
|
||||
return undecoded
|
||||
}
|
||||
27
vendor/github.com/BurntSushi/toml/doc.go
generated
vendored
Normal file
27
vendor/github.com/BurntSushi/toml/doc.go
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
Package toml provides facilities for decoding and encoding TOML configuration
|
||||
files via reflection. There is also support for delaying decoding with
|
||||
the Primitive type, and querying the set of keys in a TOML document with the
|
||||
MetaData type.
|
||||
|
||||
The specification implemented: https://github.com/toml-lang/toml
|
||||
|
||||
The sub-command github.com/BurntSushi/toml/cmd/tomlv can be used to verify
|
||||
whether a file is a valid TOML document. It can also be used to print the
|
||||
type of each key in a TOML document.
|
||||
|
||||
Testing
|
||||
|
||||
There are two important types of tests used for this package. The first is
|
||||
contained inside '*_test.go' files and uses the standard Go unit testing
|
||||
framework. These tests are primarily devoted to holistically testing the
|
||||
decoder and encoder.
|
||||
|
||||
The second type of testing is used to verify the implementation's adherence
|
||||
to the TOML specification. These tests have been factored into their own
|
||||
project: https://github.com/BurntSushi/toml-test
|
||||
|
||||
The reason the tests are in a separate project is so that they can be used by
|
||||
any implementation of TOML. Namely, it is language agnostic.
|
||||
*/
|
||||
package toml
|
||||
568
vendor/github.com/BurntSushi/toml/encode.go
generated
vendored
Normal file
568
vendor/github.com/BurntSushi/toml/encode.go
generated
vendored
Normal file
@@ -0,0 +1,568 @@
|
||||
package toml
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type tomlEncodeError struct{ error }
|
||||
|
||||
var (
|
||||
errArrayMixedElementTypes = errors.New(
|
||||
"toml: cannot encode array with mixed element types")
|
||||
errArrayNilElement = errors.New(
|
||||
"toml: cannot encode array with nil element")
|
||||
errNonString = errors.New(
|
||||
"toml: cannot encode a map with non-string key type")
|
||||
errAnonNonStruct = errors.New(
|
||||
"toml: cannot encode an anonymous field that is not a struct")
|
||||
errArrayNoTable = errors.New(
|
||||
"toml: TOML array element cannot contain a table")
|
||||
errNoKey = errors.New(
|
||||
"toml: top-level values must be Go maps or structs")
|
||||
errAnything = errors.New("") // used in testing
|
||||
)
|
||||
|
||||
var quotedReplacer = strings.NewReplacer(
|
||||
"\t", "\\t",
|
||||
"\n", "\\n",
|
||||
"\r", "\\r",
|
||||
"\"", "\\\"",
|
||||
"\\", "\\\\",
|
||||
)
|
||||
|
||||
// Encoder controls the encoding of Go values to a TOML document to some
|
||||
// io.Writer.
|
||||
//
|
||||
// The indentation level can be controlled with the Indent field.
|
||||
type Encoder struct {
|
||||
// A single indentation level. By default it is two spaces.
|
||||
Indent string
|
||||
|
||||
// hasWritten is whether we have written any output to w yet.
|
||||
hasWritten bool
|
||||
w *bufio.Writer
|
||||
}
|
||||
|
||||
// NewEncoder returns a TOML encoder that encodes Go values to the io.Writer
|
||||
// given. By default, a single indentation level is 2 spaces.
|
||||
func NewEncoder(w io.Writer) *Encoder {
|
||||
return &Encoder{
|
||||
w: bufio.NewWriter(w),
|
||||
Indent: " ",
|
||||
}
|
||||
}
|
||||
|
||||
// Encode writes a TOML representation of the Go value to the underlying
|
||||
// io.Writer. If the value given cannot be encoded to a valid TOML document,
|
||||
// then an error is returned.
|
||||
//
|
||||
// The mapping between Go values and TOML values should be precisely the same
|
||||
// as for the Decode* functions. Similarly, the TextMarshaler interface is
|
||||
// supported by encoding the resulting bytes as strings. (If you want to write
|
||||
// arbitrary binary data then you will need to use something like base64 since
|
||||
// TOML does not have any binary types.)
|
||||
//
|
||||
// When encoding TOML hashes (i.e., Go maps or structs), keys without any
|
||||
// sub-hashes are encoded first.
|
||||
//
|
||||
// If a Go map is encoded, then its keys are sorted alphabetically for
|
||||
// deterministic output. More control over this behavior may be provided if
|
||||
// there is demand for it.
|
||||
//
|
||||
// Encoding Go values without a corresponding TOML representation---like map
|
||||
// types with non-string keys---will cause an error to be returned. Similarly
|
||||
// for mixed arrays/slices, arrays/slices with nil elements, embedded
|
||||
// non-struct types and nested slices containing maps or structs.
|
||||
// (e.g., [][]map[string]string is not allowed but []map[string]string is OK
|
||||
// and so is []map[string][]string.)
|
||||
func (enc *Encoder) Encode(v interface{}) error {
|
||||
rv := eindirect(reflect.ValueOf(v))
|
||||
if err := enc.safeEncode(Key([]string{}), rv); err != nil {
|
||||
return err
|
||||
}
|
||||
return enc.w.Flush()
|
||||
}
|
||||
|
||||
func (enc *Encoder) safeEncode(key Key, rv reflect.Value) (err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
if terr, ok := r.(tomlEncodeError); ok {
|
||||
err = terr.error
|
||||
return
|
||||
}
|
||||
panic(r)
|
||||
}
|
||||
}()
|
||||
enc.encode(key, rv)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (enc *Encoder) encode(key Key, rv reflect.Value) {
|
||||
// Special case. Time needs to be in ISO8601 format.
|
||||
// Special case. If we can marshal the type to text, then we used that.
|
||||
// Basically, this prevents the encoder for handling these types as
|
||||
// generic structs (or whatever the underlying type of a TextMarshaler is).
|
||||
switch rv.Interface().(type) {
|
||||
case time.Time, TextMarshaler:
|
||||
enc.keyEqElement(key, rv)
|
||||
return
|
||||
}
|
||||
|
||||
k := rv.Kind()
|
||||
switch k {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32,
|
||||
reflect.Int64,
|
||||
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32,
|
||||
reflect.Uint64,
|
||||
reflect.Float32, reflect.Float64, reflect.String, reflect.Bool:
|
||||
enc.keyEqElement(key, rv)
|
||||
case reflect.Array, reflect.Slice:
|
||||
if typeEqual(tomlArrayHash, tomlTypeOfGo(rv)) {
|
||||
enc.eArrayOfTables(key, rv)
|
||||
} else {
|
||||
enc.keyEqElement(key, rv)
|
||||
}
|
||||
case reflect.Interface:
|
||||
if rv.IsNil() {
|
||||
return
|
||||
}
|
||||
enc.encode(key, rv.Elem())
|
||||
case reflect.Map:
|
||||
if rv.IsNil() {
|
||||
return
|
||||
}
|
||||
enc.eTable(key, rv)
|
||||
case reflect.Ptr:
|
||||
if rv.IsNil() {
|
||||
return
|
||||
}
|
||||
enc.encode(key, rv.Elem())
|
||||
case reflect.Struct:
|
||||
enc.eTable(key, rv)
|
||||
default:
|
||||
panic(e("unsupported type for key '%s': %s", key, k))
|
||||
}
|
||||
}
|
||||
|
||||
// eElement encodes any value that can be an array element (primitives and
|
||||
// arrays).
|
||||
func (enc *Encoder) eElement(rv reflect.Value) {
|
||||
switch v := rv.Interface().(type) {
|
||||
case time.Time:
|
||||
// Special case time.Time as a primitive. Has to come before
|
||||
// TextMarshaler below because time.Time implements
|
||||
// encoding.TextMarshaler, but we need to always use UTC.
|
||||
enc.wf(v.UTC().Format("2006-01-02T15:04:05Z"))
|
||||
return
|
||||
case TextMarshaler:
|
||||
// Special case. Use text marshaler if it's available for this value.
|
||||
if s, err := v.MarshalText(); err != nil {
|
||||
encPanic(err)
|
||||
} else {
|
||||
enc.writeQuoted(string(s))
|
||||
}
|
||||
return
|
||||
}
|
||||
switch rv.Kind() {
|
||||
case reflect.Bool:
|
||||
enc.wf(strconv.FormatBool(rv.Bool()))
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32,
|
||||
reflect.Int64:
|
||||
enc.wf(strconv.FormatInt(rv.Int(), 10))
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16,
|
||||
reflect.Uint32, reflect.Uint64:
|
||||
enc.wf(strconv.FormatUint(rv.Uint(), 10))
|
||||
case reflect.Float32:
|
||||
enc.wf(floatAddDecimal(strconv.FormatFloat(rv.Float(), 'f', -1, 32)))
|
||||
case reflect.Float64:
|
||||
enc.wf(floatAddDecimal(strconv.FormatFloat(rv.Float(), 'f', -1, 64)))
|
||||
case reflect.Array, reflect.Slice:
|
||||
enc.eArrayOrSliceElement(rv)
|
||||
case reflect.Interface:
|
||||
enc.eElement(rv.Elem())
|
||||
case reflect.String:
|
||||
enc.writeQuoted(rv.String())
|
||||
default:
|
||||
panic(e("unexpected primitive type: %s", rv.Kind()))
|
||||
}
|
||||
}
|
||||
|
||||
// By the TOML spec, all floats must have a decimal with at least one
|
||||
// number on either side.
|
||||
func floatAddDecimal(fstr string) string {
|
||||
if !strings.Contains(fstr, ".") {
|
||||
return fstr + ".0"
|
||||
}
|
||||
return fstr
|
||||
}
|
||||
|
||||
func (enc *Encoder) writeQuoted(s string) {
|
||||
enc.wf("\"%s\"", quotedReplacer.Replace(s))
|
||||
}
|
||||
|
||||
func (enc *Encoder) eArrayOrSliceElement(rv reflect.Value) {
|
||||
length := rv.Len()
|
||||
enc.wf("[")
|
||||
for i := 0; i < length; i++ {
|
||||
elem := rv.Index(i)
|
||||
enc.eElement(elem)
|
||||
if i != length-1 {
|
||||
enc.wf(", ")
|
||||
}
|
||||
}
|
||||
enc.wf("]")
|
||||
}
|
||||
|
||||
func (enc *Encoder) eArrayOfTables(key Key, rv reflect.Value) {
|
||||
if len(key) == 0 {
|
||||
encPanic(errNoKey)
|
||||
}
|
||||
for i := 0; i < rv.Len(); i++ {
|
||||
trv := rv.Index(i)
|
||||
if isNil(trv) {
|
||||
continue
|
||||
}
|
||||
panicIfInvalidKey(key)
|
||||
enc.newline()
|
||||
enc.wf("%s[[%s]]", enc.indentStr(key), key.maybeQuotedAll())
|
||||
enc.newline()
|
||||
enc.eMapOrStruct(key, trv)
|
||||
}
|
||||
}
|
||||
|
||||
func (enc *Encoder) eTable(key Key, rv reflect.Value) {
|
||||
panicIfInvalidKey(key)
|
||||
if len(key) == 1 {
|
||||
// Output an extra newline between top-level tables.
|
||||
// (The newline isn't written if nothing else has been written though.)
|
||||
enc.newline()
|
||||
}
|
||||
if len(key) > 0 {
|
||||
enc.wf("%s[%s]", enc.indentStr(key), key.maybeQuotedAll())
|
||||
enc.newline()
|
||||
}
|
||||
enc.eMapOrStruct(key, rv)
|
||||
}
|
||||
|
||||
func (enc *Encoder) eMapOrStruct(key Key, rv reflect.Value) {
|
||||
switch rv := eindirect(rv); rv.Kind() {
|
||||
case reflect.Map:
|
||||
enc.eMap(key, rv)
|
||||
case reflect.Struct:
|
||||
enc.eStruct(key, rv)
|
||||
default:
|
||||
panic("eTable: unhandled reflect.Value Kind: " + rv.Kind().String())
|
||||
}
|
||||
}
|
||||
|
||||
func (enc *Encoder) eMap(key Key, rv reflect.Value) {
|
||||
rt := rv.Type()
|
||||
if rt.Key().Kind() != reflect.String {
|
||||
encPanic(errNonString)
|
||||
}
|
||||
|
||||
// Sort keys so that we have deterministic output. And write keys directly
|
||||
// underneath this key first, before writing sub-structs or sub-maps.
|
||||
var mapKeysDirect, mapKeysSub []string
|
||||
for _, mapKey := range rv.MapKeys() {
|
||||
k := mapKey.String()
|
||||
if typeIsHash(tomlTypeOfGo(rv.MapIndex(mapKey))) {
|
||||
mapKeysSub = append(mapKeysSub, k)
|
||||
} else {
|
||||
mapKeysDirect = append(mapKeysDirect, k)
|
||||
}
|
||||
}
|
||||
|
||||
var writeMapKeys = func(mapKeys []string) {
|
||||
sort.Strings(mapKeys)
|
||||
for _, mapKey := range mapKeys {
|
||||
mrv := rv.MapIndex(reflect.ValueOf(mapKey))
|
||||
if isNil(mrv) {
|
||||
// Don't write anything for nil fields.
|
||||
continue
|
||||
}
|
||||
enc.encode(key.add(mapKey), mrv)
|
||||
}
|
||||
}
|
||||
writeMapKeys(mapKeysDirect)
|
||||
writeMapKeys(mapKeysSub)
|
||||
}
|
||||
|
||||
func (enc *Encoder) eStruct(key Key, rv reflect.Value) {
|
||||
// Write keys for fields directly under this key first, because if we write
|
||||
// a field that creates a new table, then all keys under it will be in that
|
||||
// table (not the one we're writing here).
|
||||
rt := rv.Type()
|
||||
var fieldsDirect, fieldsSub [][]int
|
||||
var addFields func(rt reflect.Type, rv reflect.Value, start []int)
|
||||
addFields = func(rt reflect.Type, rv reflect.Value, start []int) {
|
||||
for i := 0; i < rt.NumField(); i++ {
|
||||
f := rt.Field(i)
|
||||
// skip unexported fields
|
||||
if f.PkgPath != "" && !f.Anonymous {
|
||||
continue
|
||||
}
|
||||
frv := rv.Field(i)
|
||||
if f.Anonymous {
|
||||
t := f.Type
|
||||
switch t.Kind() {
|
||||
case reflect.Struct:
|
||||
// Treat anonymous struct fields with
|
||||
// tag names as though they are not
|
||||
// anonymous, like encoding/json does.
|
||||
if getOptions(f.Tag).name == "" {
|
||||
addFields(t, frv, f.Index)
|
||||
continue
|
||||
}
|
||||
case reflect.Ptr:
|
||||
if t.Elem().Kind() == reflect.Struct &&
|
||||
getOptions(f.Tag).name == "" {
|
||||
if !frv.IsNil() {
|
||||
addFields(t.Elem(), frv.Elem(), f.Index)
|
||||
}
|
||||
continue
|
||||
}
|
||||
// Fall through to the normal field encoding logic below
|
||||
// for non-struct anonymous fields.
|
||||
}
|
||||
}
|
||||
|
||||
if typeIsHash(tomlTypeOfGo(frv)) {
|
||||
fieldsSub = append(fieldsSub, append(start, f.Index...))
|
||||
} else {
|
||||
fieldsDirect = append(fieldsDirect, append(start, f.Index...))
|
||||
}
|
||||
}
|
||||
}
|
||||
addFields(rt, rv, nil)
|
||||
|
||||
var writeFields = func(fields [][]int) {
|
||||
for _, fieldIndex := range fields {
|
||||
sft := rt.FieldByIndex(fieldIndex)
|
||||
sf := rv.FieldByIndex(fieldIndex)
|
||||
if isNil(sf) {
|
||||
// Don't write anything for nil fields.
|
||||
continue
|
||||
}
|
||||
|
||||
opts := getOptions(sft.Tag)
|
||||
if opts.skip {
|
||||
continue
|
||||
}
|
||||
keyName := sft.Name
|
||||
if opts.name != "" {
|
||||
keyName = opts.name
|
||||
}
|
||||
if opts.omitempty && isEmpty(sf) {
|
||||
continue
|
||||
}
|
||||
if opts.omitzero && isZero(sf) {
|
||||
continue
|
||||
}
|
||||
|
||||
enc.encode(key.add(keyName), sf)
|
||||
}
|
||||
}
|
||||
writeFields(fieldsDirect)
|
||||
writeFields(fieldsSub)
|
||||
}
|
||||
|
||||
// tomlTypeName returns the TOML type name of the Go value's type. It is
|
||||
// used to determine whether the types of array elements are mixed (which is
|
||||
// forbidden). If the Go value is nil, then it is illegal for it to be an array
|
||||
// element, and valueIsNil is returned as true.
|
||||
|
||||
// Returns the TOML type of a Go value. The type may be `nil`, which means
|
||||
// no concrete TOML type could be found.
|
||||
func tomlTypeOfGo(rv reflect.Value) tomlType {
|
||||
if isNil(rv) || !rv.IsValid() {
|
||||
return nil
|
||||
}
|
||||
switch rv.Kind() {
|
||||
case reflect.Bool:
|
||||
return tomlBool
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32,
|
||||
reflect.Int64,
|
||||
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32,
|
||||
reflect.Uint64:
|
||||
return tomlInteger
|
||||
case reflect.Float32, reflect.Float64:
|
||||
return tomlFloat
|
||||
case reflect.Array, reflect.Slice:
|
||||
if typeEqual(tomlHash, tomlArrayType(rv)) {
|
||||
return tomlArrayHash
|
||||
}
|
||||
return tomlArray
|
||||
case reflect.Ptr, reflect.Interface:
|
||||
return tomlTypeOfGo(rv.Elem())
|
||||
case reflect.String:
|
||||
return tomlString
|
||||
case reflect.Map:
|
||||
return tomlHash
|
||||
case reflect.Struct:
|
||||
switch rv.Interface().(type) {
|
||||
case time.Time:
|
||||
return tomlDatetime
|
||||
case TextMarshaler:
|
||||
return tomlString
|
||||
default:
|
||||
return tomlHash
|
||||
}
|
||||
default:
|
||||
panic("unexpected reflect.Kind: " + rv.Kind().String())
|
||||
}
|
||||
}
|
||||
|
||||
// tomlArrayType returns the element type of a TOML array. The type returned
|
||||
// may be nil if it cannot be determined (e.g., a nil slice or a zero length
|
||||
// slize). This function may also panic if it finds a type that cannot be
|
||||
// expressed in TOML (such as nil elements, heterogeneous arrays or directly
|
||||
// nested arrays of tables).
|
||||
func tomlArrayType(rv reflect.Value) tomlType {
|
||||
if isNil(rv) || !rv.IsValid() || rv.Len() == 0 {
|
||||
return nil
|
||||
}
|
||||
firstType := tomlTypeOfGo(rv.Index(0))
|
||||
if firstType == nil {
|
||||
encPanic(errArrayNilElement)
|
||||
}
|
||||
|
||||
rvlen := rv.Len()
|
||||
for i := 1; i < rvlen; i++ {
|
||||
elem := rv.Index(i)
|
||||
switch elemType := tomlTypeOfGo(elem); {
|
||||
case elemType == nil:
|
||||
encPanic(errArrayNilElement)
|
||||
case !typeEqual(firstType, elemType):
|
||||
encPanic(errArrayMixedElementTypes)
|
||||
}
|
||||
}
|
||||
// If we have a nested array, then we must make sure that the nested
|
||||
// array contains ONLY primitives.
|
||||
// This checks arbitrarily nested arrays.
|
||||
if typeEqual(firstType, tomlArray) || typeEqual(firstType, tomlArrayHash) {
|
||||
nest := tomlArrayType(eindirect(rv.Index(0)))
|
||||
if typeEqual(nest, tomlHash) || typeEqual(nest, tomlArrayHash) {
|
||||
encPanic(errArrayNoTable)
|
||||
}
|
||||
}
|
||||
return firstType
|
||||
}
|
||||
|
||||
type tagOptions struct {
|
||||
skip bool // "-"
|
||||
name string
|
||||
omitempty bool
|
||||
omitzero bool
|
||||
}
|
||||
|
||||
func getOptions(tag reflect.StructTag) tagOptions {
|
||||
t := tag.Get("toml")
|
||||
if t == "-" {
|
||||
return tagOptions{skip: true}
|
||||
}
|
||||
var opts tagOptions
|
||||
parts := strings.Split(t, ",")
|
||||
opts.name = parts[0]
|
||||
for _, s := range parts[1:] {
|
||||
switch s {
|
||||
case "omitempty":
|
||||
opts.omitempty = true
|
||||
case "omitzero":
|
||||
opts.omitzero = true
|
||||
}
|
||||
}
|
||||
return opts
|
||||
}
|
||||
|
||||
func isZero(rv reflect.Value) bool {
|
||||
switch rv.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
return rv.Int() == 0
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
return rv.Uint() == 0
|
||||
case reflect.Float32, reflect.Float64:
|
||||
return rv.Float() == 0.0
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func isEmpty(rv reflect.Value) bool {
|
||||
switch rv.Kind() {
|
||||
case reflect.Array, reflect.Slice, reflect.Map, reflect.String:
|
||||
return rv.Len() == 0
|
||||
case reflect.Bool:
|
||||
return !rv.Bool()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (enc *Encoder) newline() {
|
||||
if enc.hasWritten {
|
||||
enc.wf("\n")
|
||||
}
|
||||
}
|
||||
|
||||
func (enc *Encoder) keyEqElement(key Key, val reflect.Value) {
|
||||
if len(key) == 0 {
|
||||
encPanic(errNoKey)
|
||||
}
|
||||
panicIfInvalidKey(key)
|
||||
enc.wf("%s%s = ", enc.indentStr(key), key.maybeQuoted(len(key)-1))
|
||||
enc.eElement(val)
|
||||
enc.newline()
|
||||
}
|
||||
|
||||
func (enc *Encoder) wf(format string, v ...interface{}) {
|
||||
if _, err := fmt.Fprintf(enc.w, format, v...); err != nil {
|
||||
encPanic(err)
|
||||
}
|
||||
enc.hasWritten = true
|
||||
}
|
||||
|
||||
func (enc *Encoder) indentStr(key Key) string {
|
||||
return strings.Repeat(enc.Indent, len(key)-1)
|
||||
}
|
||||
|
||||
func encPanic(err error) {
|
||||
panic(tomlEncodeError{err})
|
||||
}
|
||||
|
||||
func eindirect(v reflect.Value) reflect.Value {
|
||||
switch v.Kind() {
|
||||
case reflect.Ptr, reflect.Interface:
|
||||
return eindirect(v.Elem())
|
||||
default:
|
||||
return v
|
||||
}
|
||||
}
|
||||
|
||||
func isNil(rv reflect.Value) bool {
|
||||
switch rv.Kind() {
|
||||
case reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
|
||||
return rv.IsNil()
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func panicIfInvalidKey(key Key) {
|
||||
for _, k := range key {
|
||||
if len(k) == 0 {
|
||||
encPanic(e("Key '%s' is not a valid table name. Key names "+
|
||||
"cannot be empty.", key.maybeQuotedAll()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func isValidKeyName(s string) bool {
|
||||
return len(s) != 0
|
||||
}
|
||||
19
vendor/github.com/BurntSushi/toml/encoding_types.go
generated
vendored
Normal file
19
vendor/github.com/BurntSushi/toml/encoding_types.go
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
// +build go1.2
|
||||
|
||||
package toml
|
||||
|
||||
// In order to support Go 1.1, we define our own TextMarshaler and
|
||||
// TextUnmarshaler types. For Go 1.2+, we just alias them with the
|
||||
// standard library interfaces.
|
||||
|
||||
import (
|
||||
"encoding"
|
||||
)
|
||||
|
||||
// TextMarshaler is a synonym for encoding.TextMarshaler. It is defined here
|
||||
// so that Go 1.1 can be supported.
|
||||
type TextMarshaler encoding.TextMarshaler
|
||||
|
||||
// TextUnmarshaler is a synonym for encoding.TextUnmarshaler. It is defined
|
||||
// here so that Go 1.1 can be supported.
|
||||
type TextUnmarshaler encoding.TextUnmarshaler
|
||||
18
vendor/github.com/BurntSushi/toml/encoding_types_1.1.go
generated
vendored
Normal file
18
vendor/github.com/BurntSushi/toml/encoding_types_1.1.go
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
// +build !go1.2
|
||||
|
||||
package toml
|
||||
|
||||
// These interfaces were introduced in Go 1.2, so we add them manually when
|
||||
// compiling for Go 1.1.
|
||||
|
||||
// TextMarshaler is a synonym for encoding.TextMarshaler. It is defined here
|
||||
// so that Go 1.1 can be supported.
|
||||
type TextMarshaler interface {
|
||||
MarshalText() (text []byte, err error)
|
||||
}
|
||||
|
||||
// TextUnmarshaler is a synonym for encoding.TextUnmarshaler. It is defined
|
||||
// here so that Go 1.1 can be supported.
|
||||
type TextUnmarshaler interface {
|
||||
UnmarshalText(text []byte) error
|
||||
}
|
||||
953
vendor/github.com/BurntSushi/toml/lex.go
generated
vendored
Normal file
953
vendor/github.com/BurntSushi/toml/lex.go
generated
vendored
Normal file
@@ -0,0 +1,953 @@
|
||||
package toml
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
type itemType int
|
||||
|
||||
const (
|
||||
itemError itemType = iota
|
||||
itemNIL // used in the parser to indicate no type
|
||||
itemEOF
|
||||
itemText
|
||||
itemString
|
||||
itemRawString
|
||||
itemMultilineString
|
||||
itemRawMultilineString
|
||||
itemBool
|
||||
itemInteger
|
||||
itemFloat
|
||||
itemDatetime
|
||||
itemArray // the start of an array
|
||||
itemArrayEnd
|
||||
itemTableStart
|
||||
itemTableEnd
|
||||
itemArrayTableStart
|
||||
itemArrayTableEnd
|
||||
itemKeyStart
|
||||
itemCommentStart
|
||||
itemInlineTableStart
|
||||
itemInlineTableEnd
|
||||
)
|
||||
|
||||
const (
|
||||
eof = 0
|
||||
comma = ','
|
||||
tableStart = '['
|
||||
tableEnd = ']'
|
||||
arrayTableStart = '['
|
||||
arrayTableEnd = ']'
|
||||
tableSep = '.'
|
||||
keySep = '='
|
||||
arrayStart = '['
|
||||
arrayEnd = ']'
|
||||
commentStart = '#'
|
||||
stringStart = '"'
|
||||
stringEnd = '"'
|
||||
rawStringStart = '\''
|
||||
rawStringEnd = '\''
|
||||
inlineTableStart = '{'
|
||||
inlineTableEnd = '}'
|
||||
)
|
||||
|
||||
type stateFn func(lx *lexer) stateFn
|
||||
|
||||
type lexer struct {
|
||||
input string
|
||||
start int
|
||||
pos int
|
||||
line int
|
||||
state stateFn
|
||||
items chan item
|
||||
|
||||
// Allow for backing up up to three runes.
|
||||
// This is necessary because TOML contains 3-rune tokens (""" and ''').
|
||||
prevWidths [3]int
|
||||
nprev int // how many of prevWidths are in use
|
||||
// If we emit an eof, we can still back up, but it is not OK to call
|
||||
// next again.
|
||||
atEOF bool
|
||||
|
||||
// A stack of state functions used to maintain context.
|
||||
// The idea is to reuse parts of the state machine in various places.
|
||||
// For example, values can appear at the top level or within arbitrarily
|
||||
// nested arrays. The last state on the stack is used after a value has
|
||||
// been lexed. Similarly for comments.
|
||||
stack []stateFn
|
||||
}
|
||||
|
||||
type item struct {
|
||||
typ itemType
|
||||
val string
|
||||
line int
|
||||
}
|
||||
|
||||
func (lx *lexer) nextItem() item {
|
||||
for {
|
||||
select {
|
||||
case item := <-lx.items:
|
||||
return item
|
||||
default:
|
||||
lx.state = lx.state(lx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func lex(input string) *lexer {
|
||||
lx := &lexer{
|
||||
input: input,
|
||||
state: lexTop,
|
||||
line: 1,
|
||||
items: make(chan item, 10),
|
||||
stack: make([]stateFn, 0, 10),
|
||||
}
|
||||
return lx
|
||||
}
|
||||
|
||||
func (lx *lexer) push(state stateFn) {
|
||||
lx.stack = append(lx.stack, state)
|
||||
}
|
||||
|
||||
func (lx *lexer) pop() stateFn {
|
||||
if len(lx.stack) == 0 {
|
||||
return lx.errorf("BUG in lexer: no states to pop")
|
||||
}
|
||||
last := lx.stack[len(lx.stack)-1]
|
||||
lx.stack = lx.stack[0 : len(lx.stack)-1]
|
||||
return last
|
||||
}
|
||||
|
||||
func (lx *lexer) current() string {
|
||||
return lx.input[lx.start:lx.pos]
|
||||
}
|
||||
|
||||
func (lx *lexer) emit(typ itemType) {
|
||||
lx.items <- item{typ, lx.current(), lx.line}
|
||||
lx.start = lx.pos
|
||||
}
|
||||
|
||||
func (lx *lexer) emitTrim(typ itemType) {
|
||||
lx.items <- item{typ, strings.TrimSpace(lx.current()), lx.line}
|
||||
lx.start = lx.pos
|
||||
}
|
||||
|
||||
func (lx *lexer) next() (r rune) {
|
||||
if lx.atEOF {
|
||||
panic("next called after EOF")
|
||||
}
|
||||
if lx.pos >= len(lx.input) {
|
||||
lx.atEOF = true
|
||||
return eof
|
||||
}
|
||||
|
||||
if lx.input[lx.pos] == '\n' {
|
||||
lx.line++
|
||||
}
|
||||
lx.prevWidths[2] = lx.prevWidths[1]
|
||||
lx.prevWidths[1] = lx.prevWidths[0]
|
||||
if lx.nprev < 3 {
|
||||
lx.nprev++
|
||||
}
|
||||
r, w := utf8.DecodeRuneInString(lx.input[lx.pos:])
|
||||
lx.prevWidths[0] = w
|
||||
lx.pos += w
|
||||
return r
|
||||
}
|
||||
|
||||
// ignore skips over the pending input before this point.
|
||||
func (lx *lexer) ignore() {
|
||||
lx.start = lx.pos
|
||||
}
|
||||
|
||||
// backup steps back one rune. Can be called only twice between calls to next.
|
||||
func (lx *lexer) backup() {
|
||||
if lx.atEOF {
|
||||
lx.atEOF = false
|
||||
return
|
||||
}
|
||||
if lx.nprev < 1 {
|
||||
panic("backed up too far")
|
||||
}
|
||||
w := lx.prevWidths[0]
|
||||
lx.prevWidths[0] = lx.prevWidths[1]
|
||||
lx.prevWidths[1] = lx.prevWidths[2]
|
||||
lx.nprev--
|
||||
lx.pos -= w
|
||||
if lx.pos < len(lx.input) && lx.input[lx.pos] == '\n' {
|
||||
lx.line--
|
||||
}
|
||||
}
|
||||
|
||||
// accept consumes the next rune if it's equal to `valid`.
|
||||
func (lx *lexer) accept(valid rune) bool {
|
||||
if lx.next() == valid {
|
||||
return true
|
||||
}
|
||||
lx.backup()
|
||||
return false
|
||||
}
|
||||
|
||||
// peek returns but does not consume the next rune in the input.
|
||||
func (lx *lexer) peek() rune {
|
||||
r := lx.next()
|
||||
lx.backup()
|
||||
return r
|
||||
}
|
||||
|
||||
// skip ignores all input that matches the given predicate.
|
||||
func (lx *lexer) skip(pred func(rune) bool) {
|
||||
for {
|
||||
r := lx.next()
|
||||
if pred(r) {
|
||||
continue
|
||||
}
|
||||
lx.backup()
|
||||
lx.ignore()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// errorf stops all lexing by emitting an error and returning `nil`.
|
||||
// Note that any value that is a character is escaped if it's a special
|
||||
// character (newlines, tabs, etc.).
|
||||
func (lx *lexer) errorf(format string, values ...interface{}) stateFn {
|
||||
lx.items <- item{
|
||||
itemError,
|
||||
fmt.Sprintf(format, values...),
|
||||
lx.line,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// lexTop consumes elements at the top level of TOML data.
|
||||
func lexTop(lx *lexer) stateFn {
|
||||
r := lx.next()
|
||||
if isWhitespace(r) || isNL(r) {
|
||||
return lexSkip(lx, lexTop)
|
||||
}
|
||||
switch r {
|
||||
case commentStart:
|
||||
lx.push(lexTop)
|
||||
return lexCommentStart
|
||||
case tableStart:
|
||||
return lexTableStart
|
||||
case eof:
|
||||
if lx.pos > lx.start {
|
||||
return lx.errorf("unexpected EOF")
|
||||
}
|
||||
lx.emit(itemEOF)
|
||||
return nil
|
||||
}
|
||||
|
||||
// At this point, the only valid item can be a key, so we back up
|
||||
// and let the key lexer do the rest.
|
||||
lx.backup()
|
||||
lx.push(lexTopEnd)
|
||||
return lexKeyStart
|
||||
}
|
||||
|
||||
// lexTopEnd is entered whenever a top-level item has been consumed. (A value
|
||||
// or a table.) It must see only whitespace, and will turn back to lexTop
|
||||
// upon a newline. If it sees EOF, it will quit the lexer successfully.
|
||||
func lexTopEnd(lx *lexer) stateFn {
|
||||
r := lx.next()
|
||||
switch {
|
||||
case r == commentStart:
|
||||
// a comment will read to a newline for us.
|
||||
lx.push(lexTop)
|
||||
return lexCommentStart
|
||||
case isWhitespace(r):
|
||||
return lexTopEnd
|
||||
case isNL(r):
|
||||
lx.ignore()
|
||||
return lexTop
|
||||
case r == eof:
|
||||
lx.emit(itemEOF)
|
||||
return nil
|
||||
}
|
||||
return lx.errorf("expected a top-level item to end with a newline, "+
|
||||
"comment, or EOF, but got %q instead", r)
|
||||
}
|
||||
|
||||
// lexTable lexes the beginning of a table. Namely, it makes sure that
|
||||
// it starts with a character other than '.' and ']'.
|
||||
// It assumes that '[' has already been consumed.
|
||||
// It also handles the case that this is an item in an array of tables.
|
||||
// e.g., '[[name]]'.
|
||||
func lexTableStart(lx *lexer) stateFn {
|
||||
if lx.peek() == arrayTableStart {
|
||||
lx.next()
|
||||
lx.emit(itemArrayTableStart)
|
||||
lx.push(lexArrayTableEnd)
|
||||
} else {
|
||||
lx.emit(itemTableStart)
|
||||
lx.push(lexTableEnd)
|
||||
}
|
||||
return lexTableNameStart
|
||||
}
|
||||
|
||||
func lexTableEnd(lx *lexer) stateFn {
|
||||
lx.emit(itemTableEnd)
|
||||
return lexTopEnd
|
||||
}
|
||||
|
||||
func lexArrayTableEnd(lx *lexer) stateFn {
|
||||
if r := lx.next(); r != arrayTableEnd {
|
||||
return lx.errorf("expected end of table array name delimiter %q, "+
|
||||
"but got %q instead", arrayTableEnd, r)
|
||||
}
|
||||
lx.emit(itemArrayTableEnd)
|
||||
return lexTopEnd
|
||||
}
|
||||
|
||||
func lexTableNameStart(lx *lexer) stateFn {
|
||||
lx.skip(isWhitespace)
|
||||
switch r := lx.peek(); {
|
||||
case r == tableEnd || r == eof:
|
||||
return lx.errorf("unexpected end of table name " +
|
||||
"(table names cannot be empty)")
|
||||
case r == tableSep:
|
||||
return lx.errorf("unexpected table separator " +
|
||||
"(table names cannot be empty)")
|
||||
case r == stringStart || r == rawStringStart:
|
||||
lx.ignore()
|
||||
lx.push(lexTableNameEnd)
|
||||
return lexValue // reuse string lexing
|
||||
default:
|
||||
return lexBareTableName
|
||||
}
|
||||
}
|
||||
|
||||
// lexBareTableName lexes the name of a table. It assumes that at least one
|
||||
// valid character for the table has already been read.
|
||||
func lexBareTableName(lx *lexer) stateFn {
|
||||
r := lx.next()
|
||||
if isBareKeyChar(r) {
|
||||
return lexBareTableName
|
||||
}
|
||||
lx.backup()
|
||||
lx.emit(itemText)
|
||||
return lexTableNameEnd
|
||||
}
|
||||
|
||||
// lexTableNameEnd reads the end of a piece of a table name, optionally
|
||||
// consuming whitespace.
|
||||
func lexTableNameEnd(lx *lexer) stateFn {
|
||||
lx.skip(isWhitespace)
|
||||
switch r := lx.next(); {
|
||||
case isWhitespace(r):
|
||||
return lexTableNameEnd
|
||||
case r == tableSep:
|
||||
lx.ignore()
|
||||
return lexTableNameStart
|
||||
case r == tableEnd:
|
||||
return lx.pop()
|
||||
default:
|
||||
return lx.errorf("expected '.' or ']' to end table name, "+
|
||||
"but got %q instead", r)
|
||||
}
|
||||
}
|
||||
|
||||
// lexKeyStart consumes a key name up until the first non-whitespace character.
|
||||
// lexKeyStart will ignore whitespace.
|
||||
func lexKeyStart(lx *lexer) stateFn {
|
||||
r := lx.peek()
|
||||
switch {
|
||||
case r == keySep:
|
||||
return lx.errorf("unexpected key separator %q", keySep)
|
||||
case isWhitespace(r) || isNL(r):
|
||||
lx.next()
|
||||
return lexSkip(lx, lexKeyStart)
|
||||
case r == stringStart || r == rawStringStart:
|
||||
lx.ignore()
|
||||
lx.emit(itemKeyStart)
|
||||
lx.push(lexKeyEnd)
|
||||
return lexValue // reuse string lexing
|
||||
default:
|
||||
lx.ignore()
|
||||
lx.emit(itemKeyStart)
|
||||
return lexBareKey
|
||||
}
|
||||
}
|
||||
|
||||
// lexBareKey consumes the text of a bare key. Assumes that the first character
|
||||
// (which is not whitespace) has not yet been consumed.
|
||||
func lexBareKey(lx *lexer) stateFn {
|
||||
switch r := lx.next(); {
|
||||
case isBareKeyChar(r):
|
||||
return lexBareKey
|
||||
case isWhitespace(r):
|
||||
lx.backup()
|
||||
lx.emit(itemText)
|
||||
return lexKeyEnd
|
||||
case r == keySep:
|
||||
lx.backup()
|
||||
lx.emit(itemText)
|
||||
return lexKeyEnd
|
||||
default:
|
||||
return lx.errorf("bare keys cannot contain %q", r)
|
||||
}
|
||||
}
|
||||
|
||||
// lexKeyEnd consumes the end of a key and trims whitespace (up to the key
|
||||
// separator).
|
||||
func lexKeyEnd(lx *lexer) stateFn {
|
||||
switch r := lx.next(); {
|
||||
case r == keySep:
|
||||
return lexSkip(lx, lexValue)
|
||||
case isWhitespace(r):
|
||||
return lexSkip(lx, lexKeyEnd)
|
||||
default:
|
||||
return lx.errorf("expected key separator %q, but got %q instead",
|
||||
keySep, r)
|
||||
}
|
||||
}
|
||||
|
||||
// lexValue starts the consumption of a value anywhere a value is expected.
|
||||
// lexValue will ignore whitespace.
|
||||
// After a value is lexed, the last state on the next is popped and returned.
|
||||
func lexValue(lx *lexer) stateFn {
|
||||
// We allow whitespace to precede a value, but NOT newlines.
|
||||
// In array syntax, the array states are responsible for ignoring newlines.
|
||||
r := lx.next()
|
||||
switch {
|
||||
case isWhitespace(r):
|
||||
return lexSkip(lx, lexValue)
|
||||
case isDigit(r):
|
||||
lx.backup() // avoid an extra state and use the same as above
|
||||
return lexNumberOrDateStart
|
||||
}
|
||||
switch r {
|
||||
case arrayStart:
|
||||
lx.ignore()
|
||||
lx.emit(itemArray)
|
||||
return lexArrayValue
|
||||
case inlineTableStart:
|
||||
lx.ignore()
|
||||
lx.emit(itemInlineTableStart)
|
||||
return lexInlineTableValue
|
||||
case stringStart:
|
||||
if lx.accept(stringStart) {
|
||||
if lx.accept(stringStart) {
|
||||
lx.ignore() // Ignore """
|
||||
return lexMultilineString
|
||||
}
|
||||
lx.backup()
|
||||
}
|
||||
lx.ignore() // ignore the '"'
|
||||
return lexString
|
||||
case rawStringStart:
|
||||
if lx.accept(rawStringStart) {
|
||||
if lx.accept(rawStringStart) {
|
||||
lx.ignore() // Ignore """
|
||||
return lexMultilineRawString
|
||||
}
|
||||
lx.backup()
|
||||
}
|
||||
lx.ignore() // ignore the "'"
|
||||
return lexRawString
|
||||
case '+', '-':
|
||||
return lexNumberStart
|
||||
case '.': // special error case, be kind to users
|
||||
return lx.errorf("floats must start with a digit, not '.'")
|
||||
}
|
||||
if unicode.IsLetter(r) {
|
||||
// Be permissive here; lexBool will give a nice error if the
|
||||
// user wrote something like
|
||||
// x = foo
|
||||
// (i.e. not 'true' or 'false' but is something else word-like.)
|
||||
lx.backup()
|
||||
return lexBool
|
||||
}
|
||||
return lx.errorf("expected value but found %q instead", r)
|
||||
}
|
||||
|
||||
// lexArrayValue consumes one value in an array. It assumes that '[' or ','
|
||||
// have already been consumed. All whitespace and newlines are ignored.
|
||||
func lexArrayValue(lx *lexer) stateFn {
|
||||
r := lx.next()
|
||||
switch {
|
||||
case isWhitespace(r) || isNL(r):
|
||||
return lexSkip(lx, lexArrayValue)
|
||||
case r == commentStart:
|
||||
lx.push(lexArrayValue)
|
||||
return lexCommentStart
|
||||
case r == comma:
|
||||
return lx.errorf("unexpected comma")
|
||||
case r == arrayEnd:
|
||||
// NOTE(caleb): The spec isn't clear about whether you can have
|
||||
// a trailing comma or not, so we'll allow it.
|
||||
return lexArrayEnd
|
||||
}
|
||||
|
||||
lx.backup()
|
||||
lx.push(lexArrayValueEnd)
|
||||
return lexValue
|
||||
}
|
||||
|
||||
// lexArrayValueEnd consumes everything between the end of an array value and
|
||||
// the next value (or the end of the array): it ignores whitespace and newlines
|
||||
// and expects either a ',' or a ']'.
|
||||
func lexArrayValueEnd(lx *lexer) stateFn {
|
||||
r := lx.next()
|
||||
switch {
|
||||
case isWhitespace(r) || isNL(r):
|
||||
return lexSkip(lx, lexArrayValueEnd)
|
||||
case r == commentStart:
|
||||
lx.push(lexArrayValueEnd)
|
||||
return lexCommentStart
|
||||
case r == comma:
|
||||
lx.ignore()
|
||||
return lexArrayValue // move on to the next value
|
||||
case r == arrayEnd:
|
||||
return lexArrayEnd
|
||||
}
|
||||
return lx.errorf(
|
||||
"expected a comma or array terminator %q, but got %q instead",
|
||||
arrayEnd, r,
|
||||
)
|
||||
}
|
||||
|
||||
// lexArrayEnd finishes the lexing of an array.
|
||||
// It assumes that a ']' has just been consumed.
|
||||
func lexArrayEnd(lx *lexer) stateFn {
|
||||
lx.ignore()
|
||||
lx.emit(itemArrayEnd)
|
||||
return lx.pop()
|
||||
}
|
||||
|
||||
// lexInlineTableValue consumes one key/value pair in an inline table.
|
||||
// It assumes that '{' or ',' have already been consumed. Whitespace is ignored.
|
||||
func lexInlineTableValue(lx *lexer) stateFn {
|
||||
r := lx.next()
|
||||
switch {
|
||||
case isWhitespace(r):
|
||||
return lexSkip(lx, lexInlineTableValue)
|
||||
case isNL(r):
|
||||
return lx.errorf("newlines not allowed within inline tables")
|
||||
case r == commentStart:
|
||||
lx.push(lexInlineTableValue)
|
||||
return lexCommentStart
|
||||
case r == comma:
|
||||
return lx.errorf("unexpected comma")
|
||||
case r == inlineTableEnd:
|
||||
return lexInlineTableEnd
|
||||
}
|
||||
lx.backup()
|
||||
lx.push(lexInlineTableValueEnd)
|
||||
return lexKeyStart
|
||||
}
|
||||
|
||||
// lexInlineTableValueEnd consumes everything between the end of an inline table
|
||||
// key/value pair and the next pair (or the end of the table):
|
||||
// it ignores whitespace and expects either a ',' or a '}'.
|
||||
func lexInlineTableValueEnd(lx *lexer) stateFn {
|
||||
r := lx.next()
|
||||
switch {
|
||||
case isWhitespace(r):
|
||||
return lexSkip(lx, lexInlineTableValueEnd)
|
||||
case isNL(r):
|
||||
return lx.errorf("newlines not allowed within inline tables")
|
||||
case r == commentStart:
|
||||
lx.push(lexInlineTableValueEnd)
|
||||
return lexCommentStart
|
||||
case r == comma:
|
||||
lx.ignore()
|
||||
return lexInlineTableValue
|
||||
case r == inlineTableEnd:
|
||||
return lexInlineTableEnd
|
||||
}
|
||||
return lx.errorf("expected a comma or an inline table terminator %q, "+
|
||||
"but got %q instead", inlineTableEnd, r)
|
||||
}
|
||||
|
||||
// lexInlineTableEnd finishes the lexing of an inline table.
|
||||
// It assumes that a '}' has just been consumed.
|
||||
func lexInlineTableEnd(lx *lexer) stateFn {
|
||||
lx.ignore()
|
||||
lx.emit(itemInlineTableEnd)
|
||||
return lx.pop()
|
||||
}
|
||||
|
||||
// lexString consumes the inner contents of a string. It assumes that the
|
||||
// beginning '"' has already been consumed and ignored.
|
||||
func lexString(lx *lexer) stateFn {
|
||||
r := lx.next()
|
||||
switch {
|
||||
case r == eof:
|
||||
return lx.errorf("unexpected EOF")
|
||||
case isNL(r):
|
||||
return lx.errorf("strings cannot contain newlines")
|
||||
case r == '\\':
|
||||
lx.push(lexString)
|
||||
return lexStringEscape
|
||||
case r == stringEnd:
|
||||
lx.backup()
|
||||
lx.emit(itemString)
|
||||
lx.next()
|
||||
lx.ignore()
|
||||
return lx.pop()
|
||||
}
|
||||
return lexString
|
||||
}
|
||||
|
||||
// lexMultilineString consumes the inner contents of a string. It assumes that
|
||||
// the beginning '"""' has already been consumed and ignored.
|
||||
func lexMultilineString(lx *lexer) stateFn {
|
||||
switch lx.next() {
|
||||
case eof:
|
||||
return lx.errorf("unexpected EOF")
|
||||
case '\\':
|
||||
return lexMultilineStringEscape
|
||||
case stringEnd:
|
||||
if lx.accept(stringEnd) {
|
||||
if lx.accept(stringEnd) {
|
||||
lx.backup()
|
||||
lx.backup()
|
||||
lx.backup()
|
||||
lx.emit(itemMultilineString)
|
||||
lx.next()
|
||||
lx.next()
|
||||
lx.next()
|
||||
lx.ignore()
|
||||
return lx.pop()
|
||||
}
|
||||
lx.backup()
|
||||
}
|
||||
}
|
||||
return lexMultilineString
|
||||
}
|
||||
|
||||
// lexRawString consumes a raw string. Nothing can be escaped in such a string.
|
||||
// It assumes that the beginning "'" has already been consumed and ignored.
|
||||
func lexRawString(lx *lexer) stateFn {
|
||||
r := lx.next()
|
||||
switch {
|
||||
case r == eof:
|
||||
return lx.errorf("unexpected EOF")
|
||||
case isNL(r):
|
||||
return lx.errorf("strings cannot contain newlines")
|
||||
case r == rawStringEnd:
|
||||
lx.backup()
|
||||
lx.emit(itemRawString)
|
||||
lx.next()
|
||||
lx.ignore()
|
||||
return lx.pop()
|
||||
}
|
||||
return lexRawString
|
||||
}
|
||||
|
||||
// lexMultilineRawString consumes a raw string. Nothing can be escaped in such
|
||||
// a string. It assumes that the beginning "'''" has already been consumed and
|
||||
// ignored.
|
||||
func lexMultilineRawString(lx *lexer) stateFn {
|
||||
switch lx.next() {
|
||||
case eof:
|
||||
return lx.errorf("unexpected EOF")
|
||||
case rawStringEnd:
|
||||
if lx.accept(rawStringEnd) {
|
||||
if lx.accept(rawStringEnd) {
|
||||
lx.backup()
|
||||
lx.backup()
|
||||
lx.backup()
|
||||
lx.emit(itemRawMultilineString)
|
||||
lx.next()
|
||||
lx.next()
|
||||
lx.next()
|
||||
lx.ignore()
|
||||
return lx.pop()
|
||||
}
|
||||
lx.backup()
|
||||
}
|
||||
}
|
||||
return lexMultilineRawString
|
||||
}
|
||||
|
||||
// lexMultilineStringEscape consumes an escaped character. It assumes that the
|
||||
// preceding '\\' has already been consumed.
|
||||
func lexMultilineStringEscape(lx *lexer) stateFn {
|
||||
// Handle the special case first:
|
||||
if isNL(lx.next()) {
|
||||
return lexMultilineString
|
||||
}
|
||||
lx.backup()
|
||||
lx.push(lexMultilineString)
|
||||
return lexStringEscape(lx)
|
||||
}
|
||||
|
||||
func lexStringEscape(lx *lexer) stateFn {
|
||||
r := lx.next()
|
||||
switch r {
|
||||
case 'b':
|
||||
fallthrough
|
||||
case 't':
|
||||
fallthrough
|
||||
case 'n':
|
||||
fallthrough
|
||||
case 'f':
|
||||
fallthrough
|
||||
case 'r':
|
||||
fallthrough
|
||||
case '"':
|
||||
fallthrough
|
||||
case '\\':
|
||||
return lx.pop()
|
||||
case 'u':
|
||||
return lexShortUnicodeEscape
|
||||
case 'U':
|
||||
return lexLongUnicodeEscape
|
||||
}
|
||||
return lx.errorf("invalid escape character %q; only the following "+
|
||||
"escape characters are allowed: "+
|
||||
`\b, \t, \n, \f, \r, \", \\, \uXXXX, and \UXXXXXXXX`, r)
|
||||
}
|
||||
|
||||
func lexShortUnicodeEscape(lx *lexer) stateFn {
|
||||
var r rune
|
||||
for i := 0; i < 4; i++ {
|
||||
r = lx.next()
|
||||
if !isHexadecimal(r) {
|
||||
return lx.errorf(`expected four hexadecimal digits after '\u', `+
|
||||
"but got %q instead", lx.current())
|
||||
}
|
||||
}
|
||||
return lx.pop()
|
||||
}
|
||||
|
||||
func lexLongUnicodeEscape(lx *lexer) stateFn {
|
||||
var r rune
|
||||
for i := 0; i < 8; i++ {
|
||||
r = lx.next()
|
||||
if !isHexadecimal(r) {
|
||||
return lx.errorf(`expected eight hexadecimal digits after '\U', `+
|
||||
"but got %q instead", lx.current())
|
||||
}
|
||||
}
|
||||
return lx.pop()
|
||||
}
|
||||
|
||||
// lexNumberOrDateStart consumes either an integer, a float, or datetime.
|
||||
func lexNumberOrDateStart(lx *lexer) stateFn {
|
||||
r := lx.next()
|
||||
if isDigit(r) {
|
||||
return lexNumberOrDate
|
||||
}
|
||||
switch r {
|
||||
case '_':
|
||||
return lexNumber
|
||||
case 'e', 'E':
|
||||
return lexFloat
|
||||
case '.':
|
||||
return lx.errorf("floats must start with a digit, not '.'")
|
||||
}
|
||||
return lx.errorf("expected a digit but got %q", r)
|
||||
}
|
||||
|
||||
// lexNumberOrDate consumes either an integer, float or datetime.
|
||||
func lexNumberOrDate(lx *lexer) stateFn {
|
||||
r := lx.next()
|
||||
if isDigit(r) {
|
||||
return lexNumberOrDate
|
||||
}
|
||||
switch r {
|
||||
case '-':
|
||||
return lexDatetime
|
||||
case '_':
|
||||
return lexNumber
|
||||
case '.', 'e', 'E':
|
||||
return lexFloat
|
||||
}
|
||||
|
||||
lx.backup()
|
||||
lx.emit(itemInteger)
|
||||
return lx.pop()
|
||||
}
|
||||
|
||||
// lexDatetime consumes a Datetime, to a first approximation.
|
||||
// The parser validates that it matches one of the accepted formats.
|
||||
func lexDatetime(lx *lexer) stateFn {
|
||||
r := lx.next()
|
||||
if isDigit(r) {
|
||||
return lexDatetime
|
||||
}
|
||||
switch r {
|
||||
case '-', 'T', ':', '.', 'Z', '+':
|
||||
return lexDatetime
|
||||
}
|
||||
|
||||
lx.backup()
|
||||
lx.emit(itemDatetime)
|
||||
return lx.pop()
|
||||
}
|
||||
|
||||
// lexNumberStart consumes either an integer or a float. It assumes that a sign
|
||||
// has already been read, but that *no* digits have been consumed.
|
||||
// lexNumberStart will move to the appropriate integer or float states.
|
||||
func lexNumberStart(lx *lexer) stateFn {
|
||||
// We MUST see a digit. Even floats have to start with a digit.
|
||||
r := lx.next()
|
||||
if !isDigit(r) {
|
||||
if r == '.' {
|
||||
return lx.errorf("floats must start with a digit, not '.'")
|
||||
}
|
||||
return lx.errorf("expected a digit but got %q", r)
|
||||
}
|
||||
return lexNumber
|
||||
}
|
||||
|
||||
// lexNumber consumes an integer or a float after seeing the first digit.
|
||||
func lexNumber(lx *lexer) stateFn {
|
||||
r := lx.next()
|
||||
if isDigit(r) {
|
||||
return lexNumber
|
||||
}
|
||||
switch r {
|
||||
case '_':
|
||||
return lexNumber
|
||||
case '.', 'e', 'E':
|
||||
return lexFloat
|
||||
}
|
||||
|
||||
lx.backup()
|
||||
lx.emit(itemInteger)
|
||||
return lx.pop()
|
||||
}
|
||||
|
||||
// lexFloat consumes the elements of a float. It allows any sequence of
|
||||
// float-like characters, so floats emitted by the lexer are only a first
|
||||
// approximation and must be validated by the parser.
|
||||
func lexFloat(lx *lexer) stateFn {
|
||||
r := lx.next()
|
||||
if isDigit(r) {
|
||||
return lexFloat
|
||||
}
|
||||
switch r {
|
||||
case '_', '.', '-', '+', 'e', 'E':
|
||||
return lexFloat
|
||||
}
|
||||
|
||||
lx.backup()
|
||||
lx.emit(itemFloat)
|
||||
return lx.pop()
|
||||
}
|
||||
|
||||
// lexBool consumes a bool string: 'true' or 'false.
|
||||
func lexBool(lx *lexer) stateFn {
|
||||
var rs []rune
|
||||
for {
|
||||
r := lx.next()
|
||||
if !unicode.IsLetter(r) {
|
||||
lx.backup()
|
||||
break
|
||||
}
|
||||
rs = append(rs, r)
|
||||
}
|
||||
s := string(rs)
|
||||
switch s {
|
||||
case "true", "false":
|
||||
lx.emit(itemBool)
|
||||
return lx.pop()
|
||||
}
|
||||
return lx.errorf("expected value but found %q instead", s)
|
||||
}
|
||||
|
||||
// lexCommentStart begins the lexing of a comment. It will emit
|
||||
// itemCommentStart and consume no characters, passing control to lexComment.
|
||||
func lexCommentStart(lx *lexer) stateFn {
|
||||
lx.ignore()
|
||||
lx.emit(itemCommentStart)
|
||||
return lexComment
|
||||
}
|
||||
|
||||
// lexComment lexes an entire comment. It assumes that '#' has been consumed.
|
||||
// It will consume *up to* the first newline character, and pass control
|
||||
// back to the last state on the stack.
|
||||
func lexComment(lx *lexer) stateFn {
|
||||
r := lx.peek()
|
||||
if isNL(r) || r == eof {
|
||||
lx.emit(itemText)
|
||||
return lx.pop()
|
||||
}
|
||||
lx.next()
|
||||
return lexComment
|
||||
}
|
||||
|
||||
// lexSkip ignores all slurped input and moves on to the next state.
|
||||
func lexSkip(lx *lexer, nextState stateFn) stateFn {
|
||||
return func(lx *lexer) stateFn {
|
||||
lx.ignore()
|
||||
return nextState
|
||||
}
|
||||
}
|
||||
|
||||
// isWhitespace returns true if `r` is a whitespace character according
|
||||
// to the spec.
|
||||
func isWhitespace(r rune) bool {
|
||||
return r == '\t' || r == ' '
|
||||
}
|
||||
|
||||
func isNL(r rune) bool {
|
||||
return r == '\n' || r == '\r'
|
||||
}
|
||||
|
||||
func isDigit(r rune) bool {
|
||||
return r >= '0' && r <= '9'
|
||||
}
|
||||
|
||||
func isHexadecimal(r rune) bool {
|
||||
return (r >= '0' && r <= '9') ||
|
||||
(r >= 'a' && r <= 'f') ||
|
||||
(r >= 'A' && r <= 'F')
|
||||
}
|
||||
|
||||
func isBareKeyChar(r rune) bool {
|
||||
return (r >= 'A' && r <= 'Z') ||
|
||||
(r >= 'a' && r <= 'z') ||
|
||||
(r >= '0' && r <= '9') ||
|
||||
r == '_' ||
|
||||
r == '-'
|
||||
}
|
||||
|
||||
func (itype itemType) String() string {
|
||||
switch itype {
|
||||
case itemError:
|
||||
return "Error"
|
||||
case itemNIL:
|
||||
return "NIL"
|
||||
case itemEOF:
|
||||
return "EOF"
|
||||
case itemText:
|
||||
return "Text"
|
||||
case itemString, itemRawString, itemMultilineString, itemRawMultilineString:
|
||||
return "String"
|
||||
case itemBool:
|
||||
return "Bool"
|
||||
case itemInteger:
|
||||
return "Integer"
|
||||
case itemFloat:
|
||||
return "Float"
|
||||
case itemDatetime:
|
||||
return "DateTime"
|
||||
case itemTableStart:
|
||||
return "TableStart"
|
||||
case itemTableEnd:
|
||||
return "TableEnd"
|
||||
case itemKeyStart:
|
||||
return "KeyStart"
|
||||
case itemArray:
|
||||
return "Array"
|
||||
case itemArrayEnd:
|
||||
return "ArrayEnd"
|
||||
case itemCommentStart:
|
||||
return "CommentStart"
|
||||
}
|
||||
panic(fmt.Sprintf("BUG: Unknown type '%d'.", int(itype)))
|
||||
}
|
||||
|
||||
func (item item) String() string {
|
||||
return fmt.Sprintf("(%s, %s)", item.typ.String(), item.val)
|
||||
}
|
||||
592
vendor/github.com/BurntSushi/toml/parse.go
generated
vendored
Normal file
592
vendor/github.com/BurntSushi/toml/parse.go
generated
vendored
Normal file
@@ -0,0 +1,592 @@
|
||||
package toml
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
type parser struct {
|
||||
mapping map[string]interface{}
|
||||
types map[string]tomlType
|
||||
lx *lexer
|
||||
|
||||
// A list of keys in the order that they appear in the TOML data.
|
||||
ordered []Key
|
||||
|
||||
// the full key for the current hash in scope
|
||||
context Key
|
||||
|
||||
// the base key name for everything except hashes
|
||||
currentKey string
|
||||
|
||||
// rough approximation of line number
|
||||
approxLine int
|
||||
|
||||
// A map of 'key.group.names' to whether they were created implicitly.
|
||||
implicits map[string]bool
|
||||
}
|
||||
|
||||
type parseError string
|
||||
|
||||
func (pe parseError) Error() string {
|
||||
return string(pe)
|
||||
}
|
||||
|
||||
func parse(data string) (p *parser, err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
var ok bool
|
||||
if err, ok = r.(parseError); ok {
|
||||
return
|
||||
}
|
||||
panic(r)
|
||||
}
|
||||
}()
|
||||
|
||||
p = &parser{
|
||||
mapping: make(map[string]interface{}),
|
||||
types: make(map[string]tomlType),
|
||||
lx: lex(data),
|
||||
ordered: make([]Key, 0),
|
||||
implicits: make(map[string]bool),
|
||||
}
|
||||
for {
|
||||
item := p.next()
|
||||
if item.typ == itemEOF {
|
||||
break
|
||||
}
|
||||
p.topLevel(item)
|
||||
}
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
||||
func (p *parser) panicf(format string, v ...interface{}) {
|
||||
msg := fmt.Sprintf("Near line %d (last key parsed '%s'): %s",
|
||||
p.approxLine, p.current(), fmt.Sprintf(format, v...))
|
||||
panic(parseError(msg))
|
||||
}
|
||||
|
||||
func (p *parser) next() item {
|
||||
it := p.lx.nextItem()
|
||||
if it.typ == itemError {
|
||||
p.panicf("%s", it.val)
|
||||
}
|
||||
return it
|
||||
}
|
||||
|
||||
func (p *parser) bug(format string, v ...interface{}) {
|
||||
panic(fmt.Sprintf("BUG: "+format+"\n\n", v...))
|
||||
}
|
||||
|
||||
func (p *parser) expect(typ itemType) item {
|
||||
it := p.next()
|
||||
p.assertEqual(typ, it.typ)
|
||||
return it
|
||||
}
|
||||
|
||||
func (p *parser) assertEqual(expected, got itemType) {
|
||||
if expected != got {
|
||||
p.bug("Expected '%s' but got '%s'.", expected, got)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *parser) topLevel(item item) {
|
||||
switch item.typ {
|
||||
case itemCommentStart:
|
||||
p.approxLine = item.line
|
||||
p.expect(itemText)
|
||||
case itemTableStart:
|
||||
kg := p.next()
|
||||
p.approxLine = kg.line
|
||||
|
||||
var key Key
|
||||
for ; kg.typ != itemTableEnd && kg.typ != itemEOF; kg = p.next() {
|
||||
key = append(key, p.keyString(kg))
|
||||
}
|
||||
p.assertEqual(itemTableEnd, kg.typ)
|
||||
|
||||
p.establishContext(key, false)
|
||||
p.setType("", tomlHash)
|
||||
p.ordered = append(p.ordered, key)
|
||||
case itemArrayTableStart:
|
||||
kg := p.next()
|
||||
p.approxLine = kg.line
|
||||
|
||||
var key Key
|
||||
for ; kg.typ != itemArrayTableEnd && kg.typ != itemEOF; kg = p.next() {
|
||||
key = append(key, p.keyString(kg))
|
||||
}
|
||||
p.assertEqual(itemArrayTableEnd, kg.typ)
|
||||
|
||||
p.establishContext(key, true)
|
||||
p.setType("", tomlArrayHash)
|
||||
p.ordered = append(p.ordered, key)
|
||||
case itemKeyStart:
|
||||
kname := p.next()
|
||||
p.approxLine = kname.line
|
||||
p.currentKey = p.keyString(kname)
|
||||
|
||||
val, typ := p.value(p.next())
|
||||
p.setValue(p.currentKey, val)
|
||||
p.setType(p.currentKey, typ)
|
||||
p.ordered = append(p.ordered, p.context.add(p.currentKey))
|
||||
p.currentKey = ""
|
||||
default:
|
||||
p.bug("Unexpected type at top level: %s", item.typ)
|
||||
}
|
||||
}
|
||||
|
||||
// Gets a string for a key (or part of a key in a table name).
|
||||
func (p *parser) keyString(it item) string {
|
||||
switch it.typ {
|
||||
case itemText:
|
||||
return it.val
|
||||
case itemString, itemMultilineString,
|
||||
itemRawString, itemRawMultilineString:
|
||||
s, _ := p.value(it)
|
||||
return s.(string)
|
||||
default:
|
||||
p.bug("Unexpected key type: %s", it.typ)
|
||||
panic("unreachable")
|
||||
}
|
||||
}
|
||||
|
||||
// value translates an expected value from the lexer into a Go value wrapped
|
||||
// as an empty interface.
|
||||
func (p *parser) value(it item) (interface{}, tomlType) {
|
||||
switch it.typ {
|
||||
case itemString:
|
||||
return p.replaceEscapes(it.val), p.typeOfPrimitive(it)
|
||||
case itemMultilineString:
|
||||
trimmed := stripFirstNewline(stripEscapedWhitespace(it.val))
|
||||
return p.replaceEscapes(trimmed), p.typeOfPrimitive(it)
|
||||
case itemRawString:
|
||||
return it.val, p.typeOfPrimitive(it)
|
||||
case itemRawMultilineString:
|
||||
return stripFirstNewline(it.val), p.typeOfPrimitive(it)
|
||||
case itemBool:
|
||||
switch it.val {
|
||||
case "true":
|
||||
return true, p.typeOfPrimitive(it)
|
||||
case "false":
|
||||
return false, p.typeOfPrimitive(it)
|
||||
}
|
||||
p.bug("Expected boolean value, but got '%s'.", it.val)
|
||||
case itemInteger:
|
||||
if !numUnderscoresOK(it.val) {
|
||||
p.panicf("Invalid integer %q: underscores must be surrounded by digits",
|
||||
it.val)
|
||||
}
|
||||
val := strings.Replace(it.val, "_", "", -1)
|
||||
num, err := strconv.ParseInt(val, 10, 64)
|
||||
if err != nil {
|
||||
// Distinguish integer values. Normally, it'd be a bug if the lexer
|
||||
// provides an invalid integer, but it's possible that the number is
|
||||
// out of range of valid values (which the lexer cannot determine).
|
||||
// So mark the former as a bug but the latter as a legitimate user
|
||||
// error.
|
||||
if e, ok := err.(*strconv.NumError); ok &&
|
||||
e.Err == strconv.ErrRange {
|
||||
|
||||
p.panicf("Integer '%s' is out of the range of 64-bit "+
|
||||
"signed integers.", it.val)
|
||||
} else {
|
||||
p.bug("Expected integer value, but got '%s'.", it.val)
|
||||
}
|
||||
}
|
||||
return num, p.typeOfPrimitive(it)
|
||||
case itemFloat:
|
||||
parts := strings.FieldsFunc(it.val, func(r rune) bool {
|
||||
switch r {
|
||||
case '.', 'e', 'E':
|
||||
return true
|
||||
}
|
||||
return false
|
||||
})
|
||||
for _, part := range parts {
|
||||
if !numUnderscoresOK(part) {
|
||||
p.panicf("Invalid float %q: underscores must be "+
|
||||
"surrounded by digits", it.val)
|
||||
}
|
||||
}
|
||||
if !numPeriodsOK(it.val) {
|
||||
// As a special case, numbers like '123.' or '1.e2',
|
||||
// which are valid as far as Go/strconv are concerned,
|
||||
// must be rejected because TOML says that a fractional
|
||||
// part consists of '.' followed by 1+ digits.
|
||||
p.panicf("Invalid float %q: '.' must be followed "+
|
||||
"by one or more digits", it.val)
|
||||
}
|
||||
val := strings.Replace(it.val, "_", "", -1)
|
||||
num, err := strconv.ParseFloat(val, 64)
|
||||
if err != nil {
|
||||
if e, ok := err.(*strconv.NumError); ok &&
|
||||
e.Err == strconv.ErrRange {
|
||||
|
||||
p.panicf("Float '%s' is out of the range of 64-bit "+
|
||||
"IEEE-754 floating-point numbers.", it.val)
|
||||
} else {
|
||||
p.panicf("Invalid float value: %q", it.val)
|
||||
}
|
||||
}
|
||||
return num, p.typeOfPrimitive(it)
|
||||
case itemDatetime:
|
||||
var t time.Time
|
||||
var ok bool
|
||||
var err error
|
||||
for _, format := range []string{
|
||||
"2006-01-02T15:04:05Z07:00",
|
||||
"2006-01-02T15:04:05",
|
||||
"2006-01-02",
|
||||
} {
|
||||
t, err = time.ParseInLocation(format, it.val, time.Local)
|
||||
if err == nil {
|
||||
ok = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !ok {
|
||||
p.panicf("Invalid TOML Datetime: %q.", it.val)
|
||||
}
|
||||
return t, p.typeOfPrimitive(it)
|
||||
case itemArray:
|
||||
array := make([]interface{}, 0)
|
||||
types := make([]tomlType, 0)
|
||||
|
||||
for it = p.next(); it.typ != itemArrayEnd; it = p.next() {
|
||||
if it.typ == itemCommentStart {
|
||||
p.expect(itemText)
|
||||
continue
|
||||
}
|
||||
|
||||
val, typ := p.value(it)
|
||||
array = append(array, val)
|
||||
types = append(types, typ)
|
||||
}
|
||||
return array, p.typeOfArray(types)
|
||||
case itemInlineTableStart:
|
||||
var (
|
||||
hash = make(map[string]interface{})
|
||||
outerContext = p.context
|
||||
outerKey = p.currentKey
|
||||
)
|
||||
|
||||
p.context = append(p.context, p.currentKey)
|
||||
p.currentKey = ""
|
||||
for it := p.next(); it.typ != itemInlineTableEnd; it = p.next() {
|
||||
if it.typ != itemKeyStart {
|
||||
p.bug("Expected key start but instead found %q, around line %d",
|
||||
it.val, p.approxLine)
|
||||
}
|
||||
if it.typ == itemCommentStart {
|
||||
p.expect(itemText)
|
||||
continue
|
||||
}
|
||||
|
||||
// retrieve key
|
||||
k := p.next()
|
||||
p.approxLine = k.line
|
||||
kname := p.keyString(k)
|
||||
|
||||
// retrieve value
|
||||
p.currentKey = kname
|
||||
val, typ := p.value(p.next())
|
||||
// make sure we keep metadata up to date
|
||||
p.setType(kname, typ)
|
||||
p.ordered = append(p.ordered, p.context.add(p.currentKey))
|
||||
hash[kname] = val
|
||||
}
|
||||
p.context = outerContext
|
||||
p.currentKey = outerKey
|
||||
return hash, tomlHash
|
||||
}
|
||||
p.bug("Unexpected value type: %s", it.typ)
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
// numUnderscoresOK checks whether each underscore in s is surrounded by
|
||||
// characters that are not underscores.
|
||||
func numUnderscoresOK(s string) bool {
|
||||
accept := false
|
||||
for _, r := range s {
|
||||
if r == '_' {
|
||||
if !accept {
|
||||
return false
|
||||
}
|
||||
accept = false
|
||||
continue
|
||||
}
|
||||
accept = true
|
||||
}
|
||||
return accept
|
||||
}
|
||||
|
||||
// numPeriodsOK checks whether every period in s is followed by a digit.
|
||||
func numPeriodsOK(s string) bool {
|
||||
period := false
|
||||
for _, r := range s {
|
||||
if period && !isDigit(r) {
|
||||
return false
|
||||
}
|
||||
period = r == '.'
|
||||
}
|
||||
return !period
|
||||
}
|
||||
|
||||
// establishContext sets the current context of the parser,
|
||||
// where the context is either a hash or an array of hashes. Which one is
|
||||
// set depends on the value of the `array` parameter.
|
||||
//
|
||||
// Establishing the context also makes sure that the key isn't a duplicate, and
|
||||
// will create implicit hashes automatically.
|
||||
func (p *parser) establishContext(key Key, array bool) {
|
||||
var ok bool
|
||||
|
||||
// Always start at the top level and drill down for our context.
|
||||
hashContext := p.mapping
|
||||
keyContext := make(Key, 0)
|
||||
|
||||
// We only need implicit hashes for key[0:-1]
|
||||
for _, k := range key[0 : len(key)-1] {
|
||||
_, ok = hashContext[k]
|
||||
keyContext = append(keyContext, k)
|
||||
|
||||
// No key? Make an implicit hash and move on.
|
||||
if !ok {
|
||||
p.addImplicit(keyContext)
|
||||
hashContext[k] = make(map[string]interface{})
|
||||
}
|
||||
|
||||
// If the hash context is actually an array of tables, then set
|
||||
// the hash context to the last element in that array.
|
||||
//
|
||||
// Otherwise, it better be a table, since this MUST be a key group (by
|
||||
// virtue of it not being the last element in a key).
|
||||
switch t := hashContext[k].(type) {
|
||||
case []map[string]interface{}:
|
||||
hashContext = t[len(t)-1]
|
||||
case map[string]interface{}:
|
||||
hashContext = t
|
||||
default:
|
||||
p.panicf("Key '%s' was already created as a hash.", keyContext)
|
||||
}
|
||||
}
|
||||
|
||||
p.context = keyContext
|
||||
if array {
|
||||
// If this is the first element for this array, then allocate a new
|
||||
// list of tables for it.
|
||||
k := key[len(key)-1]
|
||||
if _, ok := hashContext[k]; !ok {
|
||||
hashContext[k] = make([]map[string]interface{}, 0, 5)
|
||||
}
|
||||
|
||||
// Add a new table. But make sure the key hasn't already been used
|
||||
// for something else.
|
||||
if hash, ok := hashContext[k].([]map[string]interface{}); ok {
|
||||
hashContext[k] = append(hash, make(map[string]interface{}))
|
||||
} else {
|
||||
p.panicf("Key '%s' was already created and cannot be used as "+
|
||||
"an array.", keyContext)
|
||||
}
|
||||
} else {
|
||||
p.setValue(key[len(key)-1], make(map[string]interface{}))
|
||||
}
|
||||
p.context = append(p.context, key[len(key)-1])
|
||||
}
|
||||
|
||||
// setValue sets the given key to the given value in the current context.
|
||||
// It will make sure that the key hasn't already been defined, account for
|
||||
// implicit key groups.
|
||||
func (p *parser) setValue(key string, value interface{}) {
|
||||
var tmpHash interface{}
|
||||
var ok bool
|
||||
|
||||
hash := p.mapping
|
||||
keyContext := make(Key, 0)
|
||||
for _, k := range p.context {
|
||||
keyContext = append(keyContext, k)
|
||||
if tmpHash, ok = hash[k]; !ok {
|
||||
p.bug("Context for key '%s' has not been established.", keyContext)
|
||||
}
|
||||
switch t := tmpHash.(type) {
|
||||
case []map[string]interface{}:
|
||||
// The context is a table of hashes. Pick the most recent table
|
||||
// defined as the current hash.
|
||||
hash = t[len(t)-1]
|
||||
case map[string]interface{}:
|
||||
hash = t
|
||||
default:
|
||||
p.bug("Expected hash to have type 'map[string]interface{}', but "+
|
||||
"it has '%T' instead.", tmpHash)
|
||||
}
|
||||
}
|
||||
keyContext = append(keyContext, key)
|
||||
|
||||
if _, ok := hash[key]; ok {
|
||||
// Typically, if the given key has already been set, then we have
|
||||
// to raise an error since duplicate keys are disallowed. However,
|
||||
// it's possible that a key was previously defined implicitly. In this
|
||||
// case, it is allowed to be redefined concretely. (See the
|
||||
// `tests/valid/implicit-and-explicit-after.toml` test in `toml-test`.)
|
||||
//
|
||||
// But we have to make sure to stop marking it as an implicit. (So that
|
||||
// another redefinition provokes an error.)
|
||||
//
|
||||
// Note that since it has already been defined (as a hash), we don't
|
||||
// want to overwrite it. So our business is done.
|
||||
if p.isImplicit(keyContext) {
|
||||
p.removeImplicit(keyContext)
|
||||
return
|
||||
}
|
||||
|
||||
// Otherwise, we have a concrete key trying to override a previous
|
||||
// key, which is *always* wrong.
|
||||
p.panicf("Key '%s' has already been defined.", keyContext)
|
||||
}
|
||||
hash[key] = value
|
||||
}
|
||||
|
||||
// setType sets the type of a particular value at a given key.
|
||||
// It should be called immediately AFTER setValue.
|
||||
//
|
||||
// Note that if `key` is empty, then the type given will be applied to the
|
||||
// current context (which is either a table or an array of tables).
|
||||
func (p *parser) setType(key string, typ tomlType) {
|
||||
keyContext := make(Key, 0, len(p.context)+1)
|
||||
for _, k := range p.context {
|
||||
keyContext = append(keyContext, k)
|
||||
}
|
||||
if len(key) > 0 { // allow type setting for hashes
|
||||
keyContext = append(keyContext, key)
|
||||
}
|
||||
p.types[keyContext.String()] = typ
|
||||
}
|
||||
|
||||
// addImplicit sets the given Key as having been created implicitly.
|
||||
func (p *parser) addImplicit(key Key) {
|
||||
p.implicits[key.String()] = true
|
||||
}
|
||||
|
||||
// removeImplicit stops tagging the given key as having been implicitly
|
||||
// created.
|
||||
func (p *parser) removeImplicit(key Key) {
|
||||
p.implicits[key.String()] = false
|
||||
}
|
||||
|
||||
// isImplicit returns true if the key group pointed to by the key was created
|
||||
// implicitly.
|
||||
func (p *parser) isImplicit(key Key) bool {
|
||||
return p.implicits[key.String()]
|
||||
}
|
||||
|
||||
// current returns the full key name of the current context.
|
||||
func (p *parser) current() string {
|
||||
if len(p.currentKey) == 0 {
|
||||
return p.context.String()
|
||||
}
|
||||
if len(p.context) == 0 {
|
||||
return p.currentKey
|
||||
}
|
||||
return fmt.Sprintf("%s.%s", p.context, p.currentKey)
|
||||
}
|
||||
|
||||
func stripFirstNewline(s string) string {
|
||||
if len(s) == 0 || s[0] != '\n' {
|
||||
return s
|
||||
}
|
||||
return s[1:]
|
||||
}
|
||||
|
||||
func stripEscapedWhitespace(s string) string {
|
||||
esc := strings.Split(s, "\\\n")
|
||||
if len(esc) > 1 {
|
||||
for i := 1; i < len(esc); i++ {
|
||||
esc[i] = strings.TrimLeftFunc(esc[i], unicode.IsSpace)
|
||||
}
|
||||
}
|
||||
return strings.Join(esc, "")
|
||||
}
|
||||
|
||||
func (p *parser) replaceEscapes(str string) string {
|
||||
var replaced []rune
|
||||
s := []byte(str)
|
||||
r := 0
|
||||
for r < len(s) {
|
||||
if s[r] != '\\' {
|
||||
c, size := utf8.DecodeRune(s[r:])
|
||||
r += size
|
||||
replaced = append(replaced, c)
|
||||
continue
|
||||
}
|
||||
r += 1
|
||||
if r >= len(s) {
|
||||
p.bug("Escape sequence at end of string.")
|
||||
return ""
|
||||
}
|
||||
switch s[r] {
|
||||
default:
|
||||
p.bug("Expected valid escape code after \\, but got %q.", s[r])
|
||||
return ""
|
||||
case 'b':
|
||||
replaced = append(replaced, rune(0x0008))
|
||||
r += 1
|
||||
case 't':
|
||||
replaced = append(replaced, rune(0x0009))
|
||||
r += 1
|
||||
case 'n':
|
||||
replaced = append(replaced, rune(0x000A))
|
||||
r += 1
|
||||
case 'f':
|
||||
replaced = append(replaced, rune(0x000C))
|
||||
r += 1
|
||||
case 'r':
|
||||
replaced = append(replaced, rune(0x000D))
|
||||
r += 1
|
||||
case '"':
|
||||
replaced = append(replaced, rune(0x0022))
|
||||
r += 1
|
||||
case '\\':
|
||||
replaced = append(replaced, rune(0x005C))
|
||||
r += 1
|
||||
case 'u':
|
||||
// At this point, we know we have a Unicode escape of the form
|
||||
// `uXXXX` at [r, r+5). (Because the lexer guarantees this
|
||||
// for us.)
|
||||
escaped := p.asciiEscapeToUnicode(s[r+1 : r+5])
|
||||
replaced = append(replaced, escaped)
|
||||
r += 5
|
||||
case 'U':
|
||||
// At this point, we know we have a Unicode escape of the form
|
||||
// `uXXXX` at [r, r+9). (Because the lexer guarantees this
|
||||
// for us.)
|
||||
escaped := p.asciiEscapeToUnicode(s[r+1 : r+9])
|
||||
replaced = append(replaced, escaped)
|
||||
r += 9
|
||||
}
|
||||
}
|
||||
return string(replaced)
|
||||
}
|
||||
|
||||
func (p *parser) asciiEscapeToUnicode(bs []byte) rune {
|
||||
s := string(bs)
|
||||
hex, err := strconv.ParseUint(strings.ToLower(s), 16, 32)
|
||||
if err != nil {
|
||||
p.bug("Could not parse '%s' as a hexadecimal number, but the "+
|
||||
"lexer claims it's OK: %s", s, err)
|
||||
}
|
||||
if !utf8.ValidRune(rune(hex)) {
|
||||
p.panicf("Escaped character '\\u%s' is not valid UTF-8.", s)
|
||||
}
|
||||
return rune(hex)
|
||||
}
|
||||
|
||||
func isStringType(ty itemType) bool {
|
||||
return ty == itemString || ty == itemMultilineString ||
|
||||
ty == itemRawString || ty == itemRawMultilineString
|
||||
}
|
||||
1
vendor/github.com/BurntSushi/toml/session.vim
generated
vendored
Normal file
1
vendor/github.com/BurntSushi/toml/session.vim
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
au BufWritePost *.go silent!make tags > /dev/null 2>&1
|
||||
91
vendor/github.com/BurntSushi/toml/type_check.go
generated
vendored
Normal file
91
vendor/github.com/BurntSushi/toml/type_check.go
generated
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
package toml
|
||||
|
||||
// tomlType represents any Go type that corresponds to a TOML type.
|
||||
// While the first draft of the TOML spec has a simplistic type system that
|
||||
// probably doesn't need this level of sophistication, we seem to be militating
|
||||
// toward adding real composite types.
|
||||
type tomlType interface {
|
||||
typeString() string
|
||||
}
|
||||
|
||||
// typeEqual accepts any two types and returns true if they are equal.
|
||||
func typeEqual(t1, t2 tomlType) bool {
|
||||
if t1 == nil || t2 == nil {
|
||||
return false
|
||||
}
|
||||
return t1.typeString() == t2.typeString()
|
||||
}
|
||||
|
||||
func typeIsHash(t tomlType) bool {
|
||||
return typeEqual(t, tomlHash) || typeEqual(t, tomlArrayHash)
|
||||
}
|
||||
|
||||
type tomlBaseType string
|
||||
|
||||
func (btype tomlBaseType) typeString() string {
|
||||
return string(btype)
|
||||
}
|
||||
|
||||
func (btype tomlBaseType) String() string {
|
||||
return btype.typeString()
|
||||
}
|
||||
|
||||
var (
|
||||
tomlInteger tomlBaseType = "Integer"
|
||||
tomlFloat tomlBaseType = "Float"
|
||||
tomlDatetime tomlBaseType = "Datetime"
|
||||
tomlString tomlBaseType = "String"
|
||||
tomlBool tomlBaseType = "Bool"
|
||||
tomlArray tomlBaseType = "Array"
|
||||
tomlHash tomlBaseType = "Hash"
|
||||
tomlArrayHash tomlBaseType = "ArrayHash"
|
||||
)
|
||||
|
||||
// typeOfPrimitive returns a tomlType of any primitive value in TOML.
|
||||
// Primitive values are: Integer, Float, Datetime, String and Bool.
|
||||
//
|
||||
// Passing a lexer item other than the following will cause a BUG message
|
||||
// to occur: itemString, itemBool, itemInteger, itemFloat, itemDatetime.
|
||||
func (p *parser) typeOfPrimitive(lexItem item) tomlType {
|
||||
switch lexItem.typ {
|
||||
case itemInteger:
|
||||
return tomlInteger
|
||||
case itemFloat:
|
||||
return tomlFloat
|
||||
case itemDatetime:
|
||||
return tomlDatetime
|
||||
case itemString:
|
||||
return tomlString
|
||||
case itemMultilineString:
|
||||
return tomlString
|
||||
case itemRawString:
|
||||
return tomlString
|
||||
case itemRawMultilineString:
|
||||
return tomlString
|
||||
case itemBool:
|
||||
return tomlBool
|
||||
}
|
||||
p.bug("Cannot infer primitive type of lex item '%s'.", lexItem)
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
// typeOfArray returns a tomlType for an array given a list of types of its
|
||||
// values.
|
||||
//
|
||||
// In the current spec, if an array is homogeneous, then its type is always
|
||||
// "Array". If the array is not homogeneous, an error is generated.
|
||||
func (p *parser) typeOfArray(types []tomlType) tomlType {
|
||||
// Empty arrays are cool.
|
||||
if len(types) == 0 {
|
||||
return tomlArray
|
||||
}
|
||||
|
||||
theType := types[0]
|
||||
for _, t := range types[1:] {
|
||||
if !typeEqual(theType, t) {
|
||||
p.panicf("Array contains values of type '%s' and '%s', but "+
|
||||
"arrays must be homogeneous.", theType, t)
|
||||
}
|
||||
}
|
||||
return tomlArray
|
||||
}
|
||||
242
vendor/github.com/BurntSushi/toml/type_fields.go
generated
vendored
Normal file
242
vendor/github.com/BurntSushi/toml/type_fields.go
generated
vendored
Normal file
@@ -0,0 +1,242 @@
|
||||
package toml
|
||||
|
||||
// Struct field handling is adapted from code in encoding/json:
|
||||
//
|
||||
// Copyright 2010 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the Go distribution.
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"sort"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// A field represents a single field found in a struct.
|
||||
type field struct {
|
||||
name string // the name of the field (`toml` tag included)
|
||||
tag bool // whether field has a `toml` tag
|
||||
index []int // represents the depth of an anonymous field
|
||||
typ reflect.Type // the type of the field
|
||||
}
|
||||
|
||||
// byName sorts field by name, breaking ties with depth,
|
||||
// then breaking ties with "name came from toml tag", then
|
||||
// breaking ties with index sequence.
|
||||
type byName []field
|
||||
|
||||
func (x byName) Len() int { return len(x) }
|
||||
|
||||
func (x byName) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
|
||||
|
||||
func (x byName) Less(i, j int) bool {
|
||||
if x[i].name != x[j].name {
|
||||
return x[i].name < x[j].name
|
||||
}
|
||||
if len(x[i].index) != len(x[j].index) {
|
||||
return len(x[i].index) < len(x[j].index)
|
||||
}
|
||||
if x[i].tag != x[j].tag {
|
||||
return x[i].tag
|
||||
}
|
||||
return byIndex(x).Less(i, j)
|
||||
}
|
||||
|
||||
// byIndex sorts field by index sequence.
|
||||
type byIndex []field
|
||||
|
||||
func (x byIndex) Len() int { return len(x) }
|
||||
|
||||
func (x byIndex) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
|
||||
|
||||
func (x byIndex) Less(i, j int) bool {
|
||||
for k, xik := range x[i].index {
|
||||
if k >= len(x[j].index) {
|
||||
return false
|
||||
}
|
||||
if xik != x[j].index[k] {
|
||||
return xik < x[j].index[k]
|
||||
}
|
||||
}
|
||||
return len(x[i].index) < len(x[j].index)
|
||||
}
|
||||
|
||||
// typeFields returns a list of fields that TOML should recognize for the given
|
||||
// type. The algorithm is breadth-first search over the set of structs to
|
||||
// include - the top struct and then any reachable anonymous structs.
|
||||
func typeFields(t reflect.Type) []field {
|
||||
// Anonymous fields to explore at the current level and the next.
|
||||
current := []field{}
|
||||
next := []field{{typ: t}}
|
||||
|
||||
// Count of queued names for current level and the next.
|
||||
count := map[reflect.Type]int{}
|
||||
nextCount := map[reflect.Type]int{}
|
||||
|
||||
// Types already visited at an earlier level.
|
||||
visited := map[reflect.Type]bool{}
|
||||
|
||||
// Fields found.
|
||||
var fields []field
|
||||
|
||||
for len(next) > 0 {
|
||||
current, next = next, current[:0]
|
||||
count, nextCount = nextCount, map[reflect.Type]int{}
|
||||
|
||||
for _, f := range current {
|
||||
if visited[f.typ] {
|
||||
continue
|
||||
}
|
||||
visited[f.typ] = true
|
||||
|
||||
// Scan f.typ for fields to include.
|
||||
for i := 0; i < f.typ.NumField(); i++ {
|
||||
sf := f.typ.Field(i)
|
||||
if sf.PkgPath != "" && !sf.Anonymous { // unexported
|
||||
continue
|
||||
}
|
||||
opts := getOptions(sf.Tag)
|
||||
if opts.skip {
|
||||
continue
|
||||
}
|
||||
index := make([]int, len(f.index)+1)
|
||||
copy(index, f.index)
|
||||
index[len(f.index)] = i
|
||||
|
||||
ft := sf.Type
|
||||
if ft.Name() == "" && ft.Kind() == reflect.Ptr {
|
||||
// Follow pointer.
|
||||
ft = ft.Elem()
|
||||
}
|
||||
|
||||
// Record found field and index sequence.
|
||||
if opts.name != "" || !sf.Anonymous || ft.Kind() != reflect.Struct {
|
||||
tagged := opts.name != ""
|
||||
name := opts.name
|
||||
if name == "" {
|
||||
name = sf.Name
|
||||
}
|
||||
fields = append(fields, field{name, tagged, index, ft})
|
||||
if count[f.typ] > 1 {
|
||||
// If there were multiple instances, add a second,
|
||||
// so that the annihilation code will see a duplicate.
|
||||
// It only cares about the distinction between 1 or 2,
|
||||
// so don't bother generating any more copies.
|
||||
fields = append(fields, fields[len(fields)-1])
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// Record new anonymous struct to explore in next round.
|
||||
nextCount[ft]++
|
||||
if nextCount[ft] == 1 {
|
||||
f := field{name: ft.Name(), index: index, typ: ft}
|
||||
next = append(next, f)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sort.Sort(byName(fields))
|
||||
|
||||
// Delete all fields that are hidden by the Go rules for embedded fields,
|
||||
// except that fields with TOML tags are promoted.
|
||||
|
||||
// The fields are sorted in primary order of name, secondary order
|
||||
// of field index length. Loop over names; for each name, delete
|
||||
// hidden fields by choosing the one dominant field that survives.
|
||||
out := fields[:0]
|
||||
for advance, i := 0, 0; i < len(fields); i += advance {
|
||||
// One iteration per name.
|
||||
// Find the sequence of fields with the name of this first field.
|
||||
fi := fields[i]
|
||||
name := fi.name
|
||||
for advance = 1; i+advance < len(fields); advance++ {
|
||||
fj := fields[i+advance]
|
||||
if fj.name != name {
|
||||
break
|
||||
}
|
||||
}
|
||||
if advance == 1 { // Only one field with this name
|
||||
out = append(out, fi)
|
||||
continue
|
||||
}
|
||||
dominant, ok := dominantField(fields[i : i+advance])
|
||||
if ok {
|
||||
out = append(out, dominant)
|
||||
}
|
||||
}
|
||||
|
||||
fields = out
|
||||
sort.Sort(byIndex(fields))
|
||||
|
||||
return fields
|
||||
}
|
||||
|
||||
// dominantField looks through the fields, all of which are known to
|
||||
// have the same name, to find the single field that dominates the
|
||||
// others using Go's embedding rules, modified by the presence of
|
||||
// TOML tags. If there are multiple top-level fields, the boolean
|
||||
// will be false: This condition is an error in Go and we skip all
|
||||
// the fields.
|
||||
func dominantField(fields []field) (field, bool) {
|
||||
// The fields are sorted in increasing index-length order. The winner
|
||||
// must therefore be one with the shortest index length. Drop all
|
||||
// longer entries, which is easy: just truncate the slice.
|
||||
length := len(fields[0].index)
|
||||
tagged := -1 // Index of first tagged field.
|
||||
for i, f := range fields {
|
||||
if len(f.index) > length {
|
||||
fields = fields[:i]
|
||||
break
|
||||
}
|
||||
if f.tag {
|
||||
if tagged >= 0 {
|
||||
// Multiple tagged fields at the same level: conflict.
|
||||
// Return no field.
|
||||
return field{}, false
|
||||
}
|
||||
tagged = i
|
||||
}
|
||||
}
|
||||
if tagged >= 0 {
|
||||
return fields[tagged], true
|
||||
}
|
||||
// All remaining fields have the same length. If there's more than one,
|
||||
// we have a conflict (two fields named "X" at the same level) and we
|
||||
// return no field.
|
||||
if len(fields) > 1 {
|
||||
return field{}, false
|
||||
}
|
||||
return fields[0], true
|
||||
}
|
||||
|
||||
var fieldCache struct {
|
||||
sync.RWMutex
|
||||
m map[reflect.Type][]field
|
||||
}
|
||||
|
||||
// cachedTypeFields is like typeFields but uses a cache to avoid repeated work.
|
||||
func cachedTypeFields(t reflect.Type) []field {
|
||||
fieldCache.RLock()
|
||||
f := fieldCache.m[t]
|
||||
fieldCache.RUnlock()
|
||||
if f != nil {
|
||||
return f
|
||||
}
|
||||
|
||||
// Compute fields without lock.
|
||||
// Might duplicate effort but won't hold other computations back.
|
||||
f = typeFields(t)
|
||||
if f == nil {
|
||||
f = []field{}
|
||||
}
|
||||
|
||||
fieldCache.Lock()
|
||||
if fieldCache.m == nil {
|
||||
fieldCache.m = map[reflect.Type][]field{}
|
||||
}
|
||||
fieldCache.m[t] = f
|
||||
fieldCache.Unlock()
|
||||
return f
|
||||
}
|
||||
3
vendor/github.com/fatih/camelcase/.travis.yml
generated
vendored
Normal file
3
vendor/github.com/fatih/camelcase/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
language: go
|
||||
go: 1.x
|
||||
|
||||
20
vendor/github.com/fatih/camelcase/LICENSE.md
generated
vendored
Normal file
20
vendor/github.com/fatih/camelcase/LICENSE.md
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Fatih Arslan
|
||||
|
||||
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.
|
||||
58
vendor/github.com/fatih/camelcase/README.md
generated
vendored
Normal file
58
vendor/github.com/fatih/camelcase/README.md
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
# CamelCase [](http://godoc.org/github.com/fatih/camelcase) [](https://travis-ci.org/fatih/camelcase)
|
||||
|
||||
CamelCase is a Golang (Go) package to split the words of a camelcase type
|
||||
string into a slice of words. It can be used to convert a camelcase word (lower
|
||||
or upper case) into any type of word.
|
||||
|
||||
## Splitting rules:
|
||||
|
||||
1. If string is not valid UTF-8, return it without splitting as
|
||||
single item array.
|
||||
2. Assign all unicode characters into one of 4 sets: lower case
|
||||
letters, upper case letters, numbers, and all other characters.
|
||||
3. Iterate through characters of string, introducing splits
|
||||
between adjacent characters that belong to different sets.
|
||||
4. Iterate through array of split strings, and if a given string
|
||||
is upper case:
|
||||
* if subsequent string is lower case:
|
||||
* move last character of upper case string to beginning of
|
||||
lower case string
|
||||
|
||||
## Install
|
||||
|
||||
```bash
|
||||
go get github.com/fatih/camelcase
|
||||
```
|
||||
|
||||
## Usage and examples
|
||||
|
||||
```go
|
||||
splitted := camelcase.Split("GolangPackage")
|
||||
|
||||
fmt.Println(splitted[0], splitted[1]) // prints: "Golang", "Package"
|
||||
```
|
||||
|
||||
Both lower camel case and upper camel case are supported. For more info please
|
||||
check: [http://en.wikipedia.org/wiki/CamelCase](http://en.wikipedia.org/wiki/CamelCase)
|
||||
|
||||
Below are some example cases:
|
||||
|
||||
```
|
||||
"" => []
|
||||
"lowercase" => ["lowercase"]
|
||||
"Class" => ["Class"]
|
||||
"MyClass" => ["My", "Class"]
|
||||
"MyC" => ["My", "C"]
|
||||
"HTML" => ["HTML"]
|
||||
"PDFLoader" => ["PDF", "Loader"]
|
||||
"AString" => ["A", "String"]
|
||||
"SimpleXMLParser" => ["Simple", "XML", "Parser"]
|
||||
"vimRPCPlugin" => ["vim", "RPC", "Plugin"]
|
||||
"GL11Version" => ["GL", "11", "Version"]
|
||||
"99Bottles" => ["99", "Bottles"]
|
||||
"May5" => ["May", "5"]
|
||||
"BFG9000" => ["BFG", "9000"]
|
||||
"BöseÜberraschung" => ["Böse", "Überraschung"]
|
||||
"Two spaces" => ["Two", " ", "spaces"]
|
||||
"BadUTF8\xe2\xe2\xa1" => ["BadUTF8\xe2\xe2\xa1"]
|
||||
```
|
||||
90
vendor/github.com/fatih/camelcase/camelcase.go
generated
vendored
Normal file
90
vendor/github.com/fatih/camelcase/camelcase.go
generated
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
// Package camelcase is a micro package to split the words of a camelcase type
|
||||
// string into a slice of words.
|
||||
package camelcase
|
||||
|
||||
import (
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// Split splits the camelcase word and returns a list of words. It also
|
||||
// supports digits. Both lower camel case and upper camel case are supported.
|
||||
// For more info please check: http://en.wikipedia.org/wiki/CamelCase
|
||||
//
|
||||
// Examples
|
||||
//
|
||||
// "" => [""]
|
||||
// "lowercase" => ["lowercase"]
|
||||
// "Class" => ["Class"]
|
||||
// "MyClass" => ["My", "Class"]
|
||||
// "MyC" => ["My", "C"]
|
||||
// "HTML" => ["HTML"]
|
||||
// "PDFLoader" => ["PDF", "Loader"]
|
||||
// "AString" => ["A", "String"]
|
||||
// "SimpleXMLParser" => ["Simple", "XML", "Parser"]
|
||||
// "vimRPCPlugin" => ["vim", "RPC", "Plugin"]
|
||||
// "GL11Version" => ["GL", "11", "Version"]
|
||||
// "99Bottles" => ["99", "Bottles"]
|
||||
// "May5" => ["May", "5"]
|
||||
// "BFG9000" => ["BFG", "9000"]
|
||||
// "BöseÜberraschung" => ["Böse", "Überraschung"]
|
||||
// "Two spaces" => ["Two", " ", "spaces"]
|
||||
// "BadUTF8\xe2\xe2\xa1" => ["BadUTF8\xe2\xe2\xa1"]
|
||||
//
|
||||
// Splitting rules
|
||||
//
|
||||
// 1) If string is not valid UTF-8, return it without splitting as
|
||||
// single item array.
|
||||
// 2) Assign all unicode characters into one of 4 sets: lower case
|
||||
// letters, upper case letters, numbers, and all other characters.
|
||||
// 3) Iterate through characters of string, introducing splits
|
||||
// between adjacent characters that belong to different sets.
|
||||
// 4) Iterate through array of split strings, and if a given string
|
||||
// is upper case:
|
||||
// if subsequent string is lower case:
|
||||
// move last character of upper case string to beginning of
|
||||
// lower case string
|
||||
func Split(src string) (entries []string) {
|
||||
// don't split invalid utf8
|
||||
if !utf8.ValidString(src) {
|
||||
return []string{src}
|
||||
}
|
||||
entries = []string{}
|
||||
var runes [][]rune
|
||||
lastClass := 0
|
||||
class := 0
|
||||
// split into fields based on class of unicode character
|
||||
for _, r := range src {
|
||||
switch true {
|
||||
case unicode.IsLower(r):
|
||||
class = 1
|
||||
case unicode.IsUpper(r):
|
||||
class = 2
|
||||
case unicode.IsDigit(r):
|
||||
class = 3
|
||||
default:
|
||||
class = 4
|
||||
}
|
||||
if class == lastClass {
|
||||
runes[len(runes)-1] = append(runes[len(runes)-1], r)
|
||||
} else {
|
||||
runes = append(runes, []rune{r})
|
||||
}
|
||||
lastClass = class
|
||||
}
|
||||
// handle upper case -> lower case sequences, e.g.
|
||||
// "PDFL", "oader" -> "PDF", "Loader"
|
||||
for i := 0; i < len(runes)-1; i++ {
|
||||
if unicode.IsUpper(runes[i][0]) && unicode.IsLower(runes[i+1][0]) {
|
||||
runes[i+1] = append([]rune{runes[i][len(runes[i])-1]}, runes[i+1]...)
|
||||
runes[i] = runes[i][:len(runes[i])-1]
|
||||
}
|
||||
}
|
||||
// construct []string from results
|
||||
for _, s := range runes {
|
||||
if len(s) > 0 {
|
||||
entries = append(entries, string(s))
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
25
vendor/github.com/globalsign/mgo/LICENSE
generated
vendored
Normal file
25
vendor/github.com/globalsign/mgo/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
mgo - MongoDB driver for Go
|
||||
|
||||
Copyright (c) 2010-2013 - Gustavo Niemeyer <gustavo@niemeyer.net>
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
25
vendor/github.com/globalsign/mgo/bson/LICENSE
generated
vendored
Normal file
25
vendor/github.com/globalsign/mgo/bson/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
BSON library for Go
|
||||
|
||||
Copyright (c) 2010-2012 - Gustavo Niemeyer <gustavo@niemeyer.net>
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
12
vendor/github.com/globalsign/mgo/bson/README.md
generated
vendored
Normal file
12
vendor/github.com/globalsign/mgo/bson/README.md
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
[](https://godoc.org/github.com/globalsign/mgo/bson)
|
||||
|
||||
An Implementation of BSON for Go
|
||||
--------------------------------
|
||||
|
||||
Package bson is an implementation of the [BSON specification](http://bsonspec.org) for Go.
|
||||
|
||||
While the BSON package implements the BSON spec as faithfully as possible, there
|
||||
is some MongoDB specific behaviour (such as map keys `$in`, `$all`, etc) in the
|
||||
`bson` package. The priority is for backwards compatibility for the `mgo`
|
||||
driver, though fixes for obviously buggy behaviour is welcome (and features, etc
|
||||
behind feature flags).
|
||||
836
vendor/github.com/globalsign/mgo/bson/bson.go
generated
vendored
Normal file
836
vendor/github.com/globalsign/mgo/bson/bson.go
generated
vendored
Normal file
@@ -0,0 +1,836 @@
|
||||
// BSON library for Go
|
||||
//
|
||||
// Copyright (c) 2010-2012 - Gustavo Niemeyer <gustavo@niemeyer.net>
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Package bson is an implementation of the BSON specification for Go:
|
||||
//
|
||||
// http://bsonspec.org
|
||||
//
|
||||
// It was created as part of the mgo MongoDB driver for Go, but is standalone
|
||||
// and may be used on its own without the driver.
|
||||
package bson
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/md5"
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"os"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
//go:generate go run bson_corpus_spec_test_generator.go
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// The public API.
|
||||
|
||||
// Element types constants from BSON specification.
|
||||
const (
|
||||
ElementFloat64 byte = 0x01
|
||||
ElementString byte = 0x02
|
||||
ElementDocument byte = 0x03
|
||||
ElementArray byte = 0x04
|
||||
ElementBinary byte = 0x05
|
||||
Element06 byte = 0x06
|
||||
ElementObjectId byte = 0x07
|
||||
ElementBool byte = 0x08
|
||||
ElementDatetime byte = 0x09
|
||||
ElementNil byte = 0x0A
|
||||
ElementRegEx byte = 0x0B
|
||||
ElementDBPointer byte = 0x0C
|
||||
ElementJavaScriptWithoutScope byte = 0x0D
|
||||
ElementSymbol byte = 0x0E
|
||||
ElementJavaScriptWithScope byte = 0x0F
|
||||
ElementInt32 byte = 0x10
|
||||
ElementTimestamp byte = 0x11
|
||||
ElementInt64 byte = 0x12
|
||||
ElementDecimal128 byte = 0x13
|
||||
ElementMinKey byte = 0xFF
|
||||
ElementMaxKey byte = 0x7F
|
||||
|
||||
BinaryGeneric byte = 0x00
|
||||
BinaryFunction byte = 0x01
|
||||
BinaryBinaryOld byte = 0x02
|
||||
BinaryUUIDOld byte = 0x03
|
||||
BinaryUUID byte = 0x04
|
||||
BinaryMD5 byte = 0x05
|
||||
BinaryUserDefined byte = 0x80
|
||||
)
|
||||
|
||||
// Getter interface: a value implementing the bson.Getter interface will have its GetBSON
|
||||
// method called when the given value has to be marshalled, and the result
|
||||
// of this method will be marshaled in place of the actual object.
|
||||
//
|
||||
// If GetBSON returns return a non-nil error, the marshalling procedure
|
||||
// will stop and error out with the provided value.
|
||||
type Getter interface {
|
||||
GetBSON() (interface{}, error)
|
||||
}
|
||||
|
||||
// Setter interface: a value implementing the bson.Setter interface will receive the BSON
|
||||
// value via the SetBSON method during unmarshaling, and the object
|
||||
// itself will not be changed as usual.
|
||||
//
|
||||
// If setting the value works, the method should return nil or alternatively
|
||||
// bson.ErrSetZero to set the respective field to its zero value (nil for
|
||||
// pointer types). If SetBSON returns a value of type bson.TypeError, the
|
||||
// BSON value will be omitted from a map or slice being decoded and the
|
||||
// unmarshalling will continue. If it returns any other non-nil error, the
|
||||
// unmarshalling procedure will stop and error out with the provided value.
|
||||
//
|
||||
// This interface is generally useful in pointer receivers, since the method
|
||||
// will want to change the receiver. A type field that implements the Setter
|
||||
// interface doesn't have to be a pointer, though.
|
||||
//
|
||||
// Unlike the usual behavior, unmarshalling onto a value that implements a
|
||||
// Setter interface will NOT reset the value to its zero state. This allows
|
||||
// the value to decide by itself how to be unmarshalled.
|
||||
//
|
||||
// For example:
|
||||
//
|
||||
// type MyString string
|
||||
//
|
||||
// func (s *MyString) SetBSON(raw bson.Raw) error {
|
||||
// return raw.Unmarshal(s)
|
||||
// }
|
||||
//
|
||||
type Setter interface {
|
||||
SetBSON(raw Raw) error
|
||||
}
|
||||
|
||||
// ErrSetZero may be returned from a SetBSON method to have the value set to
|
||||
// its respective zero value. When used in pointer values, this will set the
|
||||
// field to nil rather than to the pre-allocated value.
|
||||
var ErrSetZero = errors.New("set to zero")
|
||||
|
||||
// M is a convenient alias for a map[string]interface{} map, useful for
|
||||
// dealing with BSON in a native way. For instance:
|
||||
//
|
||||
// bson.M{"a": 1, "b": true}
|
||||
//
|
||||
// There's no special handling for this type in addition to what's done anyway
|
||||
// for an equivalent map type. Elements in the map will be dumped in an
|
||||
// undefined ordered. See also the bson.D type for an ordered alternative.
|
||||
type M map[string]interface{}
|
||||
|
||||
// D represents a BSON document containing ordered elements. For example:
|
||||
//
|
||||
// bson.D{{"a", 1}, {"b", true}}
|
||||
//
|
||||
// In some situations, such as when creating indexes for MongoDB, the order in
|
||||
// which the elements are defined is important. If the order is not important,
|
||||
// using a map is generally more comfortable. See bson.M and bson.RawD.
|
||||
type D []DocElem
|
||||
|
||||
// DocElem is an element of the bson.D document representation.
|
||||
type DocElem struct {
|
||||
Name string
|
||||
Value interface{}
|
||||
}
|
||||
|
||||
// Map returns a map out of the ordered element name/value pairs in d.
|
||||
func (d D) Map() (m M) {
|
||||
m = make(M, len(d))
|
||||
for _, item := range d {
|
||||
m[item.Name] = item.Value
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// The Raw type represents raw unprocessed BSON documents and elements.
|
||||
// Kind is the kind of element as defined per the BSON specification, and
|
||||
// Data is the raw unprocessed data for the respective element.
|
||||
// Using this type it is possible to unmarshal or marshal values partially.
|
||||
//
|
||||
// Relevant documentation:
|
||||
//
|
||||
// http://bsonspec.org/#/specification
|
||||
//
|
||||
type Raw struct {
|
||||
Kind byte
|
||||
Data []byte
|
||||
}
|
||||
|
||||
// RawD represents a BSON document containing raw unprocessed elements.
|
||||
// This low-level representation may be useful when lazily processing
|
||||
// documents of uncertain content, or when manipulating the raw content
|
||||
// documents in general.
|
||||
type RawD []RawDocElem
|
||||
|
||||
// RawDocElem elements of RawD type.
|
||||
type RawDocElem struct {
|
||||
Name string
|
||||
Value Raw
|
||||
}
|
||||
|
||||
// ObjectId is a unique ID identifying a BSON value. It must be exactly 12 bytes
|
||||
// long. MongoDB objects by default have such a property set in their "_id"
|
||||
// property.
|
||||
//
|
||||
// http://www.mongodb.org/display/DOCS/Object+Ids
|
||||
type ObjectId string
|
||||
|
||||
// ObjectIdHex returns an ObjectId from the provided hex representation.
|
||||
// Calling this function with an invalid hex representation will
|
||||
// cause a runtime panic. See the IsObjectIdHex function.
|
||||
func ObjectIdHex(s string) ObjectId {
|
||||
d, err := hex.DecodeString(s)
|
||||
if err != nil || len(d) != 12 {
|
||||
panic(fmt.Sprintf("invalid input to ObjectIdHex: %q", s))
|
||||
}
|
||||
return ObjectId(d)
|
||||
}
|
||||
|
||||
// IsObjectIdHex returns whether s is a valid hex representation of
|
||||
// an ObjectId. See the ObjectIdHex function.
|
||||
func IsObjectIdHex(s string) bool {
|
||||
if len(s) != 24 {
|
||||
return false
|
||||
}
|
||||
_, err := hex.DecodeString(s)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// objectIdCounter is atomically incremented when generating a new ObjectId
|
||||
// using NewObjectId() function. It's used as a counter part of an id.
|
||||
var objectIdCounter = readRandomUint32()
|
||||
|
||||
// readRandomUint32 returns a random objectIdCounter.
|
||||
func readRandomUint32() uint32 {
|
||||
var b [4]byte
|
||||
_, err := io.ReadFull(rand.Reader, b[:])
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("cannot read random object id: %v", err))
|
||||
}
|
||||
return uint32((uint32(b[0]) << 0) | (uint32(b[1]) << 8) | (uint32(b[2]) << 16) | (uint32(b[3]) << 24))
|
||||
}
|
||||
|
||||
// machineId stores machine id generated once and used in subsequent calls
|
||||
// to NewObjectId function.
|
||||
var machineId = readMachineId()
|
||||
var processId = os.Getpid()
|
||||
|
||||
// readMachineId generates and returns a machine id.
|
||||
// If this function fails to get the hostname it will cause a runtime error.
|
||||
func readMachineId() []byte {
|
||||
var sum [3]byte
|
||||
id := sum[:]
|
||||
hostname, err1 := os.Hostname()
|
||||
if err1 != nil {
|
||||
_, err2 := io.ReadFull(rand.Reader, id)
|
||||
if err2 != nil {
|
||||
panic(fmt.Errorf("cannot get hostname: %v; %v", err1, err2))
|
||||
}
|
||||
return id
|
||||
}
|
||||
hw := md5.New()
|
||||
hw.Write([]byte(hostname))
|
||||
copy(id, hw.Sum(nil))
|
||||
return id
|
||||
}
|
||||
|
||||
// NewObjectId returns a new unique ObjectId.
|
||||
func NewObjectId() ObjectId {
|
||||
var b [12]byte
|
||||
// Timestamp, 4 bytes, big endian
|
||||
binary.BigEndian.PutUint32(b[:], uint32(time.Now().Unix()))
|
||||
// Machine, first 3 bytes of md5(hostname)
|
||||
b[4] = machineId[0]
|
||||
b[5] = machineId[1]
|
||||
b[6] = machineId[2]
|
||||
// Pid, 2 bytes, specs don't specify endianness, but we use big endian.
|
||||
b[7] = byte(processId >> 8)
|
||||
b[8] = byte(processId)
|
||||
// Increment, 3 bytes, big endian
|
||||
i := atomic.AddUint32(&objectIdCounter, 1)
|
||||
b[9] = byte(i >> 16)
|
||||
b[10] = byte(i >> 8)
|
||||
b[11] = byte(i)
|
||||
return ObjectId(b[:])
|
||||
}
|
||||
|
||||
// NewObjectIdWithTime returns a dummy ObjectId with the timestamp part filled
|
||||
// with the provided number of seconds from epoch UTC, and all other parts
|
||||
// filled with zeroes. It's not safe to insert a document with an id generated
|
||||
// by this method, it is useful only for queries to find documents with ids
|
||||
// generated before or after the specified timestamp.
|
||||
func NewObjectIdWithTime(t time.Time) ObjectId {
|
||||
var b [12]byte
|
||||
binary.BigEndian.PutUint32(b[:4], uint32(t.Unix()))
|
||||
return ObjectId(string(b[:]))
|
||||
}
|
||||
|
||||
// String returns a hex string representation of the id.
|
||||
// Example: ObjectIdHex("4d88e15b60f486e428412dc9").
|
||||
func (id ObjectId) String() string {
|
||||
return fmt.Sprintf(`ObjectIdHex("%x")`, string(id))
|
||||
}
|
||||
|
||||
// Hex returns a hex representation of the ObjectId.
|
||||
func (id ObjectId) Hex() string {
|
||||
return hex.EncodeToString([]byte(id))
|
||||
}
|
||||
|
||||
// MarshalJSON turns a bson.ObjectId into a json.Marshaller.
|
||||
func (id ObjectId) MarshalJSON() ([]byte, error) {
|
||||
return []byte(fmt.Sprintf(`"%x"`, string(id))), nil
|
||||
}
|
||||
|
||||
var nullBytes = []byte("null")
|
||||
|
||||
// UnmarshalJSON turns *bson.ObjectId into a json.Unmarshaller.
|
||||
func (id *ObjectId) UnmarshalJSON(data []byte) error {
|
||||
if len(data) > 0 && (data[0] == '{' || data[0] == 'O') {
|
||||
var v struct {
|
||||
Id json.RawMessage `json:"$oid"`
|
||||
Func struct {
|
||||
Id json.RawMessage
|
||||
} `json:"$oidFunc"`
|
||||
}
|
||||
err := jdec(data, &v)
|
||||
if err == nil {
|
||||
if len(v.Id) > 0 {
|
||||
data = []byte(v.Id)
|
||||
} else {
|
||||
data = []byte(v.Func.Id)
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(data) == 2 && data[0] == '"' && data[1] == '"' || bytes.Equal(data, nullBytes) {
|
||||
*id = ""
|
||||
return nil
|
||||
}
|
||||
if len(data) != 26 || data[0] != '"' || data[25] != '"' {
|
||||
return fmt.Errorf("invalid ObjectId in JSON: %s", string(data))
|
||||
}
|
||||
var buf [12]byte
|
||||
_, err := hex.Decode(buf[:], data[1:25])
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid ObjectId in JSON: %s (%s)", string(data), err)
|
||||
}
|
||||
*id = ObjectId(string(buf[:]))
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalText turns bson.ObjectId into an encoding.TextMarshaler.
|
||||
func (id ObjectId) MarshalText() ([]byte, error) {
|
||||
return []byte(fmt.Sprintf("%x", string(id))), nil
|
||||
}
|
||||
|
||||
// UnmarshalText turns *bson.ObjectId into an encoding.TextUnmarshaler.
|
||||
func (id *ObjectId) UnmarshalText(data []byte) error {
|
||||
if len(data) == 1 && data[0] == ' ' || len(data) == 0 {
|
||||
*id = ""
|
||||
return nil
|
||||
}
|
||||
if len(data) != 24 {
|
||||
return fmt.Errorf("invalid ObjectId: %s", data)
|
||||
}
|
||||
var buf [12]byte
|
||||
_, err := hex.Decode(buf[:], data[:])
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid ObjectId: %s (%s)", data, err)
|
||||
}
|
||||
*id = ObjectId(string(buf[:]))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Valid returns true if id is valid. A valid id must contain exactly 12 bytes.
|
||||
func (id ObjectId) Valid() bool {
|
||||
return len(id) == 12
|
||||
}
|
||||
|
||||
// byteSlice returns byte slice of id from start to end.
|
||||
// Calling this function with an invalid id will cause a runtime panic.
|
||||
func (id ObjectId) byteSlice(start, end int) []byte {
|
||||
if len(id) != 12 {
|
||||
panic(fmt.Sprintf("invalid ObjectId: %q", string(id)))
|
||||
}
|
||||
return []byte(string(id)[start:end])
|
||||
}
|
||||
|
||||
// Time returns the timestamp part of the id.
|
||||
// It's a runtime error to call this method with an invalid id.
|
||||
func (id ObjectId) Time() time.Time {
|
||||
// First 4 bytes of ObjectId is 32-bit big-endian seconds from epoch.
|
||||
secs := int64(binary.BigEndian.Uint32(id.byteSlice(0, 4)))
|
||||
return time.Unix(secs, 0)
|
||||
}
|
||||
|
||||
// Machine returns the 3-byte machine id part of the id.
|
||||
// It's a runtime error to call this method with an invalid id.
|
||||
func (id ObjectId) Machine() []byte {
|
||||
return id.byteSlice(4, 7)
|
||||
}
|
||||
|
||||
// Pid returns the process id part of the id.
|
||||
// It's a runtime error to call this method with an invalid id.
|
||||
func (id ObjectId) Pid() uint16 {
|
||||
return binary.BigEndian.Uint16(id.byteSlice(7, 9))
|
||||
}
|
||||
|
||||
// Counter returns the incrementing value part of the id.
|
||||
// It's a runtime error to call this method with an invalid id.
|
||||
func (id ObjectId) Counter() int32 {
|
||||
b := id.byteSlice(9, 12)
|
||||
// Counter is stored as big-endian 3-byte value
|
||||
return int32(uint32(b[0])<<16 | uint32(b[1])<<8 | uint32(b[2]))
|
||||
}
|
||||
|
||||
// The Symbol type is similar to a string and is used in languages with a
|
||||
// distinct symbol type.
|
||||
type Symbol string
|
||||
|
||||
// Now returns the current time with millisecond precision. MongoDB stores
|
||||
// timestamps with the same precision, so a Time returned from this method
|
||||
// will not change after a roundtrip to the database. That's the only reason
|
||||
// why this function exists. Using the time.Now function also works fine
|
||||
// otherwise.
|
||||
func Now() time.Time {
|
||||
return time.Unix(0, time.Now().UnixNano()/1e6*1e6)
|
||||
}
|
||||
|
||||
// MongoTimestamp is a special internal type used by MongoDB that for some
|
||||
// strange reason has its own datatype defined in BSON.
|
||||
type MongoTimestamp int64
|
||||
|
||||
// Time returns the time part of ts which is stored with second precision.
|
||||
func (ts MongoTimestamp) Time() time.Time {
|
||||
return time.Unix(int64(uint64(ts)>>32), 0)
|
||||
}
|
||||
|
||||
// Counter returns the counter part of ts.
|
||||
func (ts MongoTimestamp) Counter() uint32 {
|
||||
return uint32(ts)
|
||||
}
|
||||
|
||||
// NewMongoTimestamp creates a timestamp using the given
|
||||
// date `t` (with second precision) and counter `c` (unique for `t`).
|
||||
//
|
||||
// Returns an error if time `t` is not between 1970-01-01T00:00:00Z
|
||||
// and 2106-02-07T06:28:15Z (inclusive).
|
||||
//
|
||||
// Note that two MongoTimestamps should never have the same (time, counter) combination:
|
||||
// the caller must ensure the counter `c` is increased if creating multiple MongoTimestamp
|
||||
// values for the same time `t` (ignoring fractions of seconds).
|
||||
func NewMongoTimestamp(t time.Time, c uint32) (MongoTimestamp, error) {
|
||||
u := t.Unix()
|
||||
if u < 0 || u > math.MaxUint32 {
|
||||
return -1, errors.New("invalid value for time")
|
||||
}
|
||||
|
||||
i := int64(u<<32 | int64(c))
|
||||
|
||||
return MongoTimestamp(i), nil
|
||||
}
|
||||
|
||||
type orderKey int64
|
||||
|
||||
// MaxKey is a special value that compares higher than all other possible BSON
|
||||
// values in a MongoDB database.
|
||||
var MaxKey = orderKey(1<<63 - 1)
|
||||
|
||||
// MinKey is a special value that compares lower than all other possible BSON
|
||||
// values in a MongoDB database.
|
||||
var MinKey = orderKey(-1 << 63)
|
||||
|
||||
type undefined struct{}
|
||||
|
||||
// Undefined represents the undefined BSON value.
|
||||
var Undefined undefined
|
||||
|
||||
// Binary is a representation for non-standard binary values. Any kind should
|
||||
// work, but the following are known as of this writing:
|
||||
//
|
||||
// 0x00 - Generic. This is decoded as []byte(data), not Binary{0x00, data}.
|
||||
// 0x01 - Function (!?)
|
||||
// 0x02 - Obsolete generic.
|
||||
// 0x03 - UUID
|
||||
// 0x05 - MD5
|
||||
// 0x80 - User defined.
|
||||
//
|
||||
type Binary struct {
|
||||
Kind byte
|
||||
Data []byte
|
||||
}
|
||||
|
||||
// RegEx represents a regular expression. The Options field may contain
|
||||
// individual characters defining the way in which the pattern should be
|
||||
// applied, and must be sorted. Valid options as of this writing are 'i' for
|
||||
// case insensitive matching, 'm' for multi-line matching, 'x' for verbose
|
||||
// mode, 'l' to make \w, \W, and similar be locale-dependent, 's' for dot-all
|
||||
// mode (a '.' matches everything), and 'u' to make \w, \W, and similar match
|
||||
// unicode. The value of the Options parameter is not verified before being
|
||||
// marshaled into the BSON format.
|
||||
type RegEx struct {
|
||||
Pattern string
|
||||
Options string
|
||||
}
|
||||
|
||||
// JavaScript is a type that holds JavaScript code. If Scope is non-nil, it
|
||||
// will be marshaled as a mapping from identifiers to values that may be
|
||||
// used when evaluating the provided Code.
|
||||
type JavaScript struct {
|
||||
Code string
|
||||
Scope interface{}
|
||||
}
|
||||
|
||||
// DBPointer refers to a document id in a namespace.
|
||||
//
|
||||
// This type is deprecated in the BSON specification and should not be used
|
||||
// except for backwards compatibility with ancient applications.
|
||||
type DBPointer struct {
|
||||
Namespace string
|
||||
Id ObjectId
|
||||
}
|
||||
|
||||
const initialBufferSize = 64
|
||||
|
||||
func handleErr(err *error) {
|
||||
if r := recover(); r != nil {
|
||||
if _, ok := r.(runtime.Error); ok {
|
||||
panic(r)
|
||||
} else if _, ok := r.(externalPanic); ok {
|
||||
panic(r)
|
||||
} else if s, ok := r.(string); ok {
|
||||
*err = errors.New(s)
|
||||
} else if e, ok := r.(error); ok {
|
||||
*err = e
|
||||
} else {
|
||||
panic(r)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Marshal serializes the in value, which may be a map or a struct value.
|
||||
// In the case of struct values, only exported fields will be serialized,
|
||||
// and the order of serialized fields will match that of the struct itself.
|
||||
// The lowercased field name is used as the key for each exported field,
|
||||
// but this behavior may be changed using the respective field tag.
|
||||
// The tag may also contain flags to tweak the marshalling behavior for
|
||||
// the field. The tag formats accepted are:
|
||||
//
|
||||
// "[<key>][,<flag1>[,<flag2>]]"
|
||||
//
|
||||
// `(...) bson:"[<key>][,<flag1>[,<flag2>]]" (...)`
|
||||
//
|
||||
// The following flags are currently supported:
|
||||
//
|
||||
// omitempty Only include the field if it's not set to the zero
|
||||
// value for the type or to empty slices or maps.
|
||||
//
|
||||
// minsize Marshal an int64 value as an int32, if that's feasible
|
||||
// while preserving the numeric value.
|
||||
//
|
||||
// inline Inline the field, which must be a struct or a map,
|
||||
// causing all of its fields or keys to be processed as if
|
||||
// they were part of the outer struct. For maps, keys must
|
||||
// not conflict with the bson keys of other struct fields.
|
||||
//
|
||||
// Some examples:
|
||||
//
|
||||
// type T struct {
|
||||
// A bool
|
||||
// B int "myb"
|
||||
// C string "myc,omitempty"
|
||||
// D string `bson:",omitempty" json:"jsonkey"`
|
||||
// E int64 ",minsize"
|
||||
// F int64 "myf,omitempty,minsize"
|
||||
// }
|
||||
//
|
||||
func Marshal(in interface{}) (out []byte, err error) {
|
||||
return MarshalBuffer(in, make([]byte, 0, initialBufferSize))
|
||||
}
|
||||
|
||||
// MarshalBuffer behaves the same way as Marshal, except that instead of
|
||||
// allocating a new byte slice it tries to use the received byte slice and
|
||||
// only allocates more memory if necessary to fit the marshaled value.
|
||||
func MarshalBuffer(in interface{}, buf []byte) (out []byte, err error) {
|
||||
defer handleErr(&err)
|
||||
e := &encoder{buf}
|
||||
e.addDoc(reflect.ValueOf(in))
|
||||
return e.out, nil
|
||||
}
|
||||
|
||||
// Unmarshal deserializes data from in into the out value. The out value
|
||||
// must be a map, a pointer to a struct, or a pointer to a bson.D value.
|
||||
// In the case of struct values, only exported fields will be deserialized.
|
||||
// The lowercased field name is used as the key for each exported field,
|
||||
// but this behavior may be changed using the respective field tag.
|
||||
// The tag may also contain flags to tweak the marshalling behavior for
|
||||
// the field. The tag formats accepted are:
|
||||
//
|
||||
// "[<key>][,<flag1>[,<flag2>]]"
|
||||
//
|
||||
// `(...) bson:"[<key>][,<flag1>[,<flag2>]]" (...)`
|
||||
//
|
||||
// The following flags are currently supported during unmarshal (see the
|
||||
// Marshal method for other flags):
|
||||
//
|
||||
// inline Inline the field, which must be a struct or a map.
|
||||
// Inlined structs are handled as if its fields were part
|
||||
// of the outer struct. An inlined map causes keys that do
|
||||
// not match any other struct field to be inserted in the
|
||||
// map rather than being discarded as usual.
|
||||
//
|
||||
// The target field or element types of out may not necessarily match
|
||||
// the BSON values of the provided data. The following conversions are
|
||||
// made automatically:
|
||||
//
|
||||
// - Numeric types are converted if at least the integer part of the
|
||||
// value would be preserved correctly
|
||||
// - Bools are converted to numeric types as 1 or 0
|
||||
// - Numeric types are converted to bools as true if not 0 or false otherwise
|
||||
// - Binary and string BSON data is converted to a string, array or byte slice
|
||||
//
|
||||
// If the value would not fit the type and cannot be converted, it's
|
||||
// silently skipped.
|
||||
//
|
||||
// Pointer values are initialized when necessary.
|
||||
func Unmarshal(in []byte, out interface{}) (err error) {
|
||||
if raw, ok := out.(*Raw); ok {
|
||||
raw.Kind = 3
|
||||
raw.Data = in
|
||||
return nil
|
||||
}
|
||||
defer handleErr(&err)
|
||||
v := reflect.ValueOf(out)
|
||||
switch v.Kind() {
|
||||
case reflect.Ptr:
|
||||
fallthrough
|
||||
case reflect.Map:
|
||||
d := newDecoder(in)
|
||||
d.readDocTo(v)
|
||||
if d.i < len(d.in) {
|
||||
return errors.New("document is corrupted")
|
||||
}
|
||||
case reflect.Struct:
|
||||
return errors.New("unmarshal can't deal with struct values. Use a pointer")
|
||||
default:
|
||||
return errors.New("unmarshal needs a map or a pointer to a struct")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Unmarshal deserializes raw into the out value. If the out value type
|
||||
// is not compatible with raw, a *bson.TypeError is returned.
|
||||
//
|
||||
// See the Unmarshal function documentation for more details on the
|
||||
// unmarshalling process.
|
||||
func (raw Raw) Unmarshal(out interface{}) (err error) {
|
||||
defer handleErr(&err)
|
||||
v := reflect.ValueOf(out)
|
||||
switch v.Kind() {
|
||||
case reflect.Ptr:
|
||||
v = v.Elem()
|
||||
fallthrough
|
||||
case reflect.Map:
|
||||
d := newDecoder(raw.Data)
|
||||
good := d.readElemTo(v, raw.Kind)
|
||||
if !good {
|
||||
return &TypeError{v.Type(), raw.Kind}
|
||||
}
|
||||
case reflect.Struct:
|
||||
return errors.New("raw Unmarshal can't deal with struct values. Use a pointer")
|
||||
default:
|
||||
return errors.New("raw Unmarshal needs a map or a valid pointer")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// TypeError store details for type error occuring
|
||||
// during unmarshaling
|
||||
type TypeError struct {
|
||||
Type reflect.Type
|
||||
Kind byte
|
||||
}
|
||||
|
||||
func (e *TypeError) Error() string {
|
||||
return fmt.Sprintf("BSON kind 0x%02x isn't compatible with type %s", e.Kind, e.Type.String())
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Maintain a mapping of keys to structure field indexes
|
||||
|
||||
type structInfo struct {
|
||||
FieldsMap map[string]fieldInfo
|
||||
FieldsList []fieldInfo
|
||||
InlineMap int
|
||||
Zero reflect.Value
|
||||
}
|
||||
|
||||
type fieldInfo struct {
|
||||
Key string
|
||||
Num int
|
||||
OmitEmpty bool
|
||||
MinSize bool
|
||||
Inline []int
|
||||
}
|
||||
|
||||
var structMap = make(map[reflect.Type]*structInfo)
|
||||
var structMapMutex sync.RWMutex
|
||||
|
||||
type externalPanic string
|
||||
|
||||
func (e externalPanic) String() string {
|
||||
return string(e)
|
||||
}
|
||||
|
||||
func getStructInfo(st reflect.Type) (*structInfo, error) {
|
||||
structMapMutex.RLock()
|
||||
sinfo, found := structMap[st]
|
||||
structMapMutex.RUnlock()
|
||||
if found {
|
||||
return sinfo, nil
|
||||
}
|
||||
n := st.NumField()
|
||||
fieldsMap := make(map[string]fieldInfo)
|
||||
fieldsList := make([]fieldInfo, 0, n)
|
||||
inlineMap := -1
|
||||
for i := 0; i != n; i++ {
|
||||
field := st.Field(i)
|
||||
if field.PkgPath != "" && !field.Anonymous {
|
||||
continue // Private field
|
||||
}
|
||||
|
||||
info := fieldInfo{Num: i}
|
||||
|
||||
tag := field.Tag.Get("bson")
|
||||
|
||||
// Fall-back to JSON struct tag, if feature flag is set.
|
||||
if tag == "" && useJSONTagFallback {
|
||||
tag = field.Tag.Get("json")
|
||||
}
|
||||
|
||||
// If there's no bson/json tag available.
|
||||
if tag == "" {
|
||||
// If there's no tag, and also no tag: value splits (i.e. no colon)
|
||||
// then assume the entire tag is the value
|
||||
if strings.Index(string(field.Tag), ":") < 0 {
|
||||
tag = string(field.Tag)
|
||||
}
|
||||
}
|
||||
|
||||
if tag == "-" {
|
||||
continue
|
||||
}
|
||||
|
||||
inline := false
|
||||
fields := strings.Split(tag, ",")
|
||||
if len(fields) > 1 {
|
||||
for _, flag := range fields[1:] {
|
||||
switch flag {
|
||||
case "omitempty":
|
||||
info.OmitEmpty = true
|
||||
case "minsize":
|
||||
info.MinSize = true
|
||||
case "inline":
|
||||
inline = true
|
||||
default:
|
||||
msg := fmt.Sprintf("Unsupported flag %q in tag %q of type %s", flag, tag, st)
|
||||
panic(externalPanic(msg))
|
||||
}
|
||||
}
|
||||
tag = fields[0]
|
||||
}
|
||||
|
||||
if inline {
|
||||
switch field.Type.Kind() {
|
||||
case reflect.Map:
|
||||
if inlineMap >= 0 {
|
||||
return nil, errors.New("Multiple ,inline maps in struct " + st.String())
|
||||
}
|
||||
if field.Type.Key() != reflect.TypeOf("") {
|
||||
return nil, errors.New("Option ,inline needs a map with string keys in struct " + st.String())
|
||||
}
|
||||
inlineMap = info.Num
|
||||
case reflect.Ptr:
|
||||
// allow only pointer to struct
|
||||
if kind := field.Type.Elem().Kind(); kind != reflect.Struct {
|
||||
return nil, errors.New("Option ,inline allows a pointer only to a struct, was given pointer to " + kind.String())
|
||||
}
|
||||
|
||||
field.Type = field.Type.Elem()
|
||||
fallthrough
|
||||
case reflect.Struct:
|
||||
sinfo, err := getStructInfo(field.Type)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, finfo := range sinfo.FieldsList {
|
||||
if _, found := fieldsMap[finfo.Key]; found {
|
||||
msg := "Duplicated key '" + finfo.Key + "' in struct " + st.String()
|
||||
return nil, errors.New(msg)
|
||||
}
|
||||
if finfo.Inline == nil {
|
||||
finfo.Inline = []int{i, finfo.Num}
|
||||
} else {
|
||||
finfo.Inline = append([]int{i}, finfo.Inline...)
|
||||
}
|
||||
fieldsMap[finfo.Key] = finfo
|
||||
fieldsList = append(fieldsList, finfo)
|
||||
}
|
||||
default:
|
||||
panic("Option ,inline needs a struct value or a pointer to a struct or map field")
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if tag != "" {
|
||||
info.Key = tag
|
||||
} else {
|
||||
info.Key = strings.ToLower(field.Name)
|
||||
}
|
||||
|
||||
if _, found = fieldsMap[info.Key]; found {
|
||||
msg := "Duplicated key '" + info.Key + "' in struct " + st.String()
|
||||
return nil, errors.New(msg)
|
||||
}
|
||||
|
||||
fieldsList = append(fieldsList, info)
|
||||
fieldsMap[info.Key] = info
|
||||
}
|
||||
sinfo = &structInfo{
|
||||
fieldsMap,
|
||||
fieldsList,
|
||||
inlineMap,
|
||||
reflect.New(st).Elem(),
|
||||
}
|
||||
structMapMutex.Lock()
|
||||
structMap[st] = sinfo
|
||||
structMapMutex.Unlock()
|
||||
return sinfo, nil
|
||||
}
|
||||
29
vendor/github.com/globalsign/mgo/bson/compatibility.go
generated
vendored
Normal file
29
vendor/github.com/globalsign/mgo/bson/compatibility.go
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
package bson
|
||||
|
||||
// Current state of the JSON tag fallback option.
|
||||
var useJSONTagFallback = false
|
||||
var useRespectNilValues = false
|
||||
|
||||
// SetJSONTagFallback enables or disables the JSON-tag fallback for structure tagging. When this is enabled, structures
|
||||
// without BSON tags on a field will fall-back to using the JSON tag (if present).
|
||||
func SetJSONTagFallback(state bool) {
|
||||
useJSONTagFallback = state
|
||||
}
|
||||
|
||||
// JSONTagFallbackState returns the current status of the JSON tag fallback compatability option. See SetJSONTagFallback
|
||||
// for more information.
|
||||
func JSONTagFallbackState() bool {
|
||||
return useJSONTagFallback
|
||||
}
|
||||
|
||||
// SetRespectNilValues enables or disables serializing nil slices or maps to `null` values.
|
||||
// In other words it enables `encoding/json` compatible behaviour.
|
||||
func SetRespectNilValues(state bool) {
|
||||
useRespectNilValues = state
|
||||
}
|
||||
|
||||
// RespectNilValuesState returns the current status of the JSON nil slices and maps fallback compatibility option.
|
||||
// See SetRespectNilValues for more information.
|
||||
func RespectNilValuesState() bool {
|
||||
return useRespectNilValues
|
||||
}
|
||||
312
vendor/github.com/globalsign/mgo/bson/decimal.go
generated
vendored
Normal file
312
vendor/github.com/globalsign/mgo/bson/decimal.go
generated
vendored
Normal file
@@ -0,0 +1,312 @@
|
||||
// BSON library for Go
|
||||
//
|
||||
// Copyright (c) 2010-2012 - Gustavo Niemeyer <gustavo@niemeyer.net>
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
package bson
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Decimal128 holds decimal128 BSON values.
|
||||
type Decimal128 struct {
|
||||
h, l uint64
|
||||
}
|
||||
|
||||
func (d Decimal128) String() string {
|
||||
var pos int // positive sign
|
||||
var e int // exponent
|
||||
var h, l uint64 // significand high/low
|
||||
|
||||
if d.h>>63&1 == 0 {
|
||||
pos = 1
|
||||
}
|
||||
|
||||
switch d.h >> 58 & (1<<5 - 1) {
|
||||
case 0x1F:
|
||||
return "NaN"
|
||||
case 0x1E:
|
||||
return "-Inf"[pos:]
|
||||
}
|
||||
|
||||
l = d.l
|
||||
if d.h>>61&3 == 3 {
|
||||
// Bits: 1*sign 2*ignored 14*exponent 111*significand.
|
||||
// Implicit 0b100 prefix in significand.
|
||||
e = int(d.h>>47&(1<<14-1)) - 6176
|
||||
//h = 4<<47 | d.h&(1<<47-1)
|
||||
// Spec says all of these values are out of range.
|
||||
h, l = 0, 0
|
||||
} else {
|
||||
// Bits: 1*sign 14*exponent 113*significand
|
||||
e = int(d.h>>49&(1<<14-1)) - 6176
|
||||
h = d.h & (1<<49 - 1)
|
||||
}
|
||||
|
||||
// Would be handled by the logic below, but that's trivial and common.
|
||||
if h == 0 && l == 0 && e == 0 {
|
||||
return "-0"[pos:]
|
||||
}
|
||||
|
||||
var repr [48]byte // Loop 5 times over 9 digits plus dot, negative sign, and leading zero.
|
||||
var last = len(repr)
|
||||
var i = len(repr)
|
||||
var dot = len(repr) + e
|
||||
var rem uint32
|
||||
Loop:
|
||||
for d9 := 0; d9 < 5; d9++ {
|
||||
h, l, rem = divmod(h, l, 1e9)
|
||||
for d1 := 0; d1 < 9; d1++ {
|
||||
// Handle "-0.0", "0.00123400", "-1.00E-6", "1.050E+3", etc.
|
||||
if i < len(repr) && (dot == i || l == 0 && h == 0 && rem > 0 && rem < 10 && (dot < i-6 || e > 0)) {
|
||||
e += len(repr) - i
|
||||
i--
|
||||
repr[i] = '.'
|
||||
last = i - 1
|
||||
dot = len(repr) // Unmark.
|
||||
}
|
||||
c := '0' + byte(rem%10)
|
||||
rem /= 10
|
||||
i--
|
||||
repr[i] = c
|
||||
// Handle "0E+3", "1E+3", etc.
|
||||
if l == 0 && h == 0 && rem == 0 && i == len(repr)-1 && (dot < i-5 || e > 0) {
|
||||
last = i
|
||||
break Loop
|
||||
}
|
||||
if c != '0' {
|
||||
last = i
|
||||
}
|
||||
// Break early. Works without it, but why.
|
||||
if dot > i && l == 0 && h == 0 && rem == 0 {
|
||||
break Loop
|
||||
}
|
||||
}
|
||||
}
|
||||
repr[last-1] = '-'
|
||||
last--
|
||||
|
||||
if e > 0 {
|
||||
return string(repr[last+pos:]) + "E+" + strconv.Itoa(e)
|
||||
}
|
||||
if e < 0 {
|
||||
return string(repr[last+pos:]) + "E" + strconv.Itoa(e)
|
||||
}
|
||||
return string(repr[last+pos:])
|
||||
}
|
||||
|
||||
func divmod(h, l uint64, div uint32) (qh, ql uint64, rem uint32) {
|
||||
div64 := uint64(div)
|
||||
a := h >> 32
|
||||
aq := a / div64
|
||||
ar := a % div64
|
||||
b := ar<<32 + h&(1<<32-1)
|
||||
bq := b / div64
|
||||
br := b % div64
|
||||
c := br<<32 + l>>32
|
||||
cq := c / div64
|
||||
cr := c % div64
|
||||
d := cr<<32 + l&(1<<32-1)
|
||||
dq := d / div64
|
||||
dr := d % div64
|
||||
return (aq<<32 | bq), (cq<<32 | dq), uint32(dr)
|
||||
}
|
||||
|
||||
var dNaN = Decimal128{0x1F << 58, 0}
|
||||
var dPosInf = Decimal128{0x1E << 58, 0}
|
||||
var dNegInf = Decimal128{0x3E << 58, 0}
|
||||
|
||||
func dErr(s string) (Decimal128, error) {
|
||||
return dNaN, fmt.Errorf("cannot parse %q as a decimal128", s)
|
||||
}
|
||||
|
||||
// ParseDecimal128 parse a string and return the corresponding value as
|
||||
// a decimal128
|
||||
func ParseDecimal128(s string) (Decimal128, error) {
|
||||
orig := s
|
||||
if s == "" {
|
||||
return dErr(orig)
|
||||
}
|
||||
neg := s[0] == '-'
|
||||
if neg || s[0] == '+' {
|
||||
s = s[1:]
|
||||
}
|
||||
|
||||
if (len(s) == 3 || len(s) == 8) && (s[0] == 'N' || s[0] == 'n' || s[0] == 'I' || s[0] == 'i') {
|
||||
if s == "NaN" || s == "nan" || strings.EqualFold(s, "nan") {
|
||||
return dNaN, nil
|
||||
}
|
||||
if s == "Inf" || s == "inf" || strings.EqualFold(s, "inf") || strings.EqualFold(s, "infinity") {
|
||||
if neg {
|
||||
return dNegInf, nil
|
||||
}
|
||||
return dPosInf, nil
|
||||
}
|
||||
return dErr(orig)
|
||||
}
|
||||
|
||||
var h, l uint64
|
||||
var e int
|
||||
|
||||
var add, ovr uint32
|
||||
var mul uint32 = 1
|
||||
var dot = -1
|
||||
var digits = 0
|
||||
var i = 0
|
||||
for i < len(s) {
|
||||
c := s[i]
|
||||
if mul == 1e9 {
|
||||
h, l, ovr = muladd(h, l, mul, add)
|
||||
mul, add = 1, 0
|
||||
if ovr > 0 || h&((1<<15-1)<<49) > 0 {
|
||||
return dErr(orig)
|
||||
}
|
||||
}
|
||||
if c >= '0' && c <= '9' {
|
||||
i++
|
||||
if c > '0' || digits > 0 {
|
||||
digits++
|
||||
}
|
||||
if digits > 34 {
|
||||
if c == '0' {
|
||||
// Exact rounding.
|
||||
e++
|
||||
continue
|
||||
}
|
||||
return dErr(orig)
|
||||
}
|
||||
mul *= 10
|
||||
add *= 10
|
||||
add += uint32(c - '0')
|
||||
continue
|
||||
}
|
||||
if c == '.' {
|
||||
i++
|
||||
if dot >= 0 || i == 1 && len(s) == 1 {
|
||||
return dErr(orig)
|
||||
}
|
||||
if i == len(s) {
|
||||
break
|
||||
}
|
||||
if s[i] < '0' || s[i] > '9' || e > 0 {
|
||||
return dErr(orig)
|
||||
}
|
||||
dot = i
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
if i == 0 {
|
||||
return dErr(orig)
|
||||
}
|
||||
if mul > 1 {
|
||||
h, l, ovr = muladd(h, l, mul, add)
|
||||
if ovr > 0 || h&((1<<15-1)<<49) > 0 {
|
||||
return dErr(orig)
|
||||
}
|
||||
}
|
||||
if dot >= 0 {
|
||||
e += dot - i
|
||||
}
|
||||
if i+1 < len(s) && (s[i] == 'E' || s[i] == 'e') {
|
||||
i++
|
||||
eneg := s[i] == '-'
|
||||
if eneg || s[i] == '+' {
|
||||
i++
|
||||
if i == len(s) {
|
||||
return dErr(orig)
|
||||
}
|
||||
}
|
||||
n := 0
|
||||
for i < len(s) && n < 1e4 {
|
||||
c := s[i]
|
||||
i++
|
||||
if c < '0' || c > '9' {
|
||||
return dErr(orig)
|
||||
}
|
||||
n *= 10
|
||||
n += int(c - '0')
|
||||
}
|
||||
if eneg {
|
||||
n = -n
|
||||
}
|
||||
e += n
|
||||
for e < -6176 {
|
||||
// Subnormal.
|
||||
var div uint32 = 1
|
||||
for div < 1e9 && e < -6176 {
|
||||
div *= 10
|
||||
e++
|
||||
}
|
||||
var rem uint32
|
||||
h, l, rem = divmod(h, l, div)
|
||||
if rem > 0 {
|
||||
return dErr(orig)
|
||||
}
|
||||
}
|
||||
for e > 6111 {
|
||||
// Clamped.
|
||||
var mul uint32 = 1
|
||||
for mul < 1e9 && e > 6111 {
|
||||
mul *= 10
|
||||
e--
|
||||
}
|
||||
h, l, ovr = muladd(h, l, mul, 0)
|
||||
if ovr > 0 || h&((1<<15-1)<<49) > 0 {
|
||||
return dErr(orig)
|
||||
}
|
||||
}
|
||||
if e < -6176 || e > 6111 {
|
||||
return dErr(orig)
|
||||
}
|
||||
}
|
||||
|
||||
if i < len(s) {
|
||||
return dErr(orig)
|
||||
}
|
||||
|
||||
h |= uint64(e+6176) & uint64(1<<14-1) << 49
|
||||
if neg {
|
||||
h |= 1 << 63
|
||||
}
|
||||
return Decimal128{h, l}, nil
|
||||
}
|
||||
|
||||
func muladd(h, l uint64, mul uint32, add uint32) (resh, resl uint64, overflow uint32) {
|
||||
mul64 := uint64(mul)
|
||||
a := mul64 * (l & (1<<32 - 1))
|
||||
b := a>>32 + mul64*(l>>32)
|
||||
c := b>>32 + mul64*(h&(1<<32-1))
|
||||
d := c>>32 + mul64*(h>>32)
|
||||
|
||||
a = a&(1<<32-1) + uint64(add)
|
||||
b = b&(1<<32-1) + a>>32
|
||||
c = c&(1<<32-1) + b>>32
|
||||
d = d&(1<<32-1) + c>>32
|
||||
|
||||
return (d<<32 | c&(1<<32-1)), (b<<32 | a&(1<<32-1)), uint32(d >> 32)
|
||||
}
|
||||
1055
vendor/github.com/globalsign/mgo/bson/decode.go
generated
vendored
Normal file
1055
vendor/github.com/globalsign/mgo/bson/decode.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
645
vendor/github.com/globalsign/mgo/bson/encode.go
generated
vendored
Normal file
645
vendor/github.com/globalsign/mgo/bson/encode.go
generated
vendored
Normal file
@@ -0,0 +1,645 @@
|
||||
// BSON library for Go
|
||||
//
|
||||
// Copyright (c) 2010-2012 - Gustavo Niemeyer <gustavo@niemeyer.net>
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this
|
||||
// list of conditions and the following disclaimer.
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
// gobson - BSON library for Go.
|
||||
|
||||
package bson
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Some internal infrastructure.
|
||||
|
||||
var (
|
||||
typeBinary = reflect.TypeOf(Binary{})
|
||||
typeObjectId = reflect.TypeOf(ObjectId(""))
|
||||
typeDBPointer = reflect.TypeOf(DBPointer{"", ObjectId("")})
|
||||
typeSymbol = reflect.TypeOf(Symbol(""))
|
||||
typeMongoTimestamp = reflect.TypeOf(MongoTimestamp(0))
|
||||
typeOrderKey = reflect.TypeOf(MinKey)
|
||||
typeDocElem = reflect.TypeOf(DocElem{})
|
||||
typeRawDocElem = reflect.TypeOf(RawDocElem{})
|
||||
typeRaw = reflect.TypeOf(Raw{})
|
||||
typeRawPtr = reflect.PtrTo(reflect.TypeOf(Raw{}))
|
||||
typeURL = reflect.TypeOf(url.URL{})
|
||||
typeTime = reflect.TypeOf(time.Time{})
|
||||
typeString = reflect.TypeOf("")
|
||||
typeJSONNumber = reflect.TypeOf(json.Number(""))
|
||||
typeTimeDuration = reflect.TypeOf(time.Duration(0))
|
||||
)
|
||||
|
||||
var (
|
||||
// spec for []uint8 or []byte encoding
|
||||
arrayOps = map[string]bool{
|
||||
"$in": true,
|
||||
"$nin": true,
|
||||
"$all": true,
|
||||
}
|
||||
)
|
||||
|
||||
const itoaCacheSize = 32
|
||||
|
||||
const (
|
||||
getterUnknown = iota
|
||||
getterNone
|
||||
getterTypeVal
|
||||
getterTypePtr
|
||||
getterAddr
|
||||
)
|
||||
|
||||
var itoaCache []string
|
||||
|
||||
var getterStyles map[reflect.Type]int
|
||||
var getterIface reflect.Type
|
||||
var getterMutex sync.RWMutex
|
||||
|
||||
func init() {
|
||||
itoaCache = make([]string, itoaCacheSize)
|
||||
for i := 0; i != itoaCacheSize; i++ {
|
||||
itoaCache[i] = strconv.Itoa(i)
|
||||
}
|
||||
var iface Getter
|
||||
getterIface = reflect.TypeOf(&iface).Elem()
|
||||
getterStyles = make(map[reflect.Type]int)
|
||||
}
|
||||
|
||||
func itoa(i int) string {
|
||||
if i < itoaCacheSize {
|
||||
return itoaCache[i]
|
||||
}
|
||||
return strconv.Itoa(i)
|
||||
}
|
||||
|
||||
func getterStyle(outt reflect.Type) int {
|
||||
getterMutex.RLock()
|
||||
style := getterStyles[outt]
|
||||
getterMutex.RUnlock()
|
||||
if style != getterUnknown {
|
||||
return style
|
||||
}
|
||||
|
||||
getterMutex.Lock()
|
||||
defer getterMutex.Unlock()
|
||||
if outt.Implements(getterIface) {
|
||||
vt := outt
|
||||
for vt.Kind() == reflect.Ptr {
|
||||
vt = vt.Elem()
|
||||
}
|
||||
if vt.Implements(getterIface) {
|
||||
style = getterTypeVal
|
||||
} else {
|
||||
style = getterTypePtr
|
||||
}
|
||||
} else if reflect.PtrTo(outt).Implements(getterIface) {
|
||||
style = getterAddr
|
||||
} else {
|
||||
style = getterNone
|
||||
}
|
||||
getterStyles[outt] = style
|
||||
return style
|
||||
}
|
||||
|
||||
func getGetter(outt reflect.Type, out reflect.Value) Getter {
|
||||
style := getterStyle(outt)
|
||||
if style == getterNone {
|
||||
return nil
|
||||
}
|
||||
if style == getterAddr {
|
||||
if !out.CanAddr() {
|
||||
return nil
|
||||
}
|
||||
return out.Addr().Interface().(Getter)
|
||||
}
|
||||
if style == getterTypeVal && out.Kind() == reflect.Ptr && out.IsNil() {
|
||||
return nil
|
||||
}
|
||||
return out.Interface().(Getter)
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Marshaling of the document value itself.
|
||||
|
||||
type encoder struct {
|
||||
out []byte
|
||||
}
|
||||
|
||||
func (e *encoder) addDoc(v reflect.Value) {
|
||||
for {
|
||||
if vi, ok := v.Interface().(Getter); ok {
|
||||
getv, err := vi.GetBSON()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
v = reflect.ValueOf(getv)
|
||||
continue
|
||||
}
|
||||
if v.Kind() == reflect.Ptr {
|
||||
v = v.Elem()
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
if v.Type() == typeRaw {
|
||||
raw := v.Interface().(Raw)
|
||||
if raw.Kind != 0x03 && raw.Kind != 0x00 {
|
||||
panic("Attempted to marshal Raw kind " + strconv.Itoa(int(raw.Kind)) + " as a document")
|
||||
}
|
||||
if len(raw.Data) == 0 {
|
||||
panic("Attempted to marshal empty Raw document")
|
||||
}
|
||||
e.addBytes(raw.Data...)
|
||||
return
|
||||
}
|
||||
|
||||
start := e.reserveInt32()
|
||||
|
||||
switch v.Kind() {
|
||||
case reflect.Map:
|
||||
e.addMap(v)
|
||||
case reflect.Struct:
|
||||
e.addStruct(v)
|
||||
case reflect.Array, reflect.Slice:
|
||||
e.addSlice(v)
|
||||
default:
|
||||
panic("Can't marshal " + v.Type().String() + " as a BSON document")
|
||||
}
|
||||
|
||||
e.addBytes(0)
|
||||
e.setInt32(start, int32(len(e.out)-start))
|
||||
}
|
||||
|
||||
func (e *encoder) addMap(v reflect.Value) {
|
||||
for _, k := range v.MapKeys() {
|
||||
e.addElem(fmt.Sprint(k), v.MapIndex(k), false)
|
||||
}
|
||||
}
|
||||
|
||||
func (e *encoder) addStruct(v reflect.Value) {
|
||||
sinfo, err := getStructInfo(v.Type())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
var value reflect.Value
|
||||
if sinfo.InlineMap >= 0 {
|
||||
m := v.Field(sinfo.InlineMap)
|
||||
if m.Len() > 0 {
|
||||
for _, k := range m.MapKeys() {
|
||||
ks := k.String()
|
||||
if _, found := sinfo.FieldsMap[ks]; found {
|
||||
panic(fmt.Sprintf("Can't have key %q in inlined map; conflicts with struct field", ks))
|
||||
}
|
||||
e.addElem(ks, m.MapIndex(k), false)
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, info := range sinfo.FieldsList {
|
||||
if info.Inline == nil {
|
||||
value = v.Field(info.Num)
|
||||
} else {
|
||||
// as pointers to struct are allowed here,
|
||||
// there is no guarantee that pointer won't be nil.
|
||||
//
|
||||
// It is expected allowed behaviour
|
||||
// so info.Inline MAY consist index to a nil pointer
|
||||
// and that is why we safely call v.FieldByIndex and just continue on panic
|
||||
field, errField := safeFieldByIndex(v, info.Inline)
|
||||
if errField != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
value = field
|
||||
}
|
||||
if info.OmitEmpty && isZero(value) {
|
||||
continue
|
||||
}
|
||||
if useRespectNilValues &&
|
||||
(value.Kind() == reflect.Slice || value.Kind() == reflect.Map) &&
|
||||
value.IsNil() {
|
||||
e.addElem(info.Key, reflect.ValueOf(nil), info.MinSize)
|
||||
continue
|
||||
}
|
||||
e.addElem(info.Key, value, info.MinSize)
|
||||
}
|
||||
}
|
||||
|
||||
func safeFieldByIndex(v reflect.Value, index []int) (result reflect.Value, err error) {
|
||||
defer func() {
|
||||
if recovered := recover(); recovered != nil {
|
||||
switch r := recovered.(type) {
|
||||
case string:
|
||||
err = fmt.Errorf("%s", r)
|
||||
case error:
|
||||
err = r
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
result = v.FieldByIndex(index)
|
||||
return
|
||||
}
|
||||
|
||||
func isZero(v reflect.Value) bool {
|
||||
switch v.Kind() {
|
||||
case reflect.String:
|
||||
return len(v.String()) == 0
|
||||
case reflect.Ptr, reflect.Interface:
|
||||
return v.IsNil()
|
||||
case reflect.Slice:
|
||||
return v.Len() == 0
|
||||
case reflect.Map:
|
||||
return v.Len() == 0
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
return v.Int() == 0
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
return v.Uint() == 0
|
||||
case reflect.Float32, reflect.Float64:
|
||||
return v.Float() == 0
|
||||
case reflect.Bool:
|
||||
return !v.Bool()
|
||||
case reflect.Struct:
|
||||
vt := v.Type()
|
||||
if vt == typeTime {
|
||||
return v.Interface().(time.Time).IsZero()
|
||||
}
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
if vt.Field(i).PkgPath != "" && !vt.Field(i).Anonymous {
|
||||
continue // Private field
|
||||
}
|
||||
if !isZero(v.Field(i)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (e *encoder) addSlice(v reflect.Value) {
|
||||
vi := v.Interface()
|
||||
if d, ok := vi.(D); ok {
|
||||
for _, elem := range d {
|
||||
e.addElem(elem.Name, reflect.ValueOf(elem.Value), false)
|
||||
}
|
||||
return
|
||||
}
|
||||
if d, ok := vi.(RawD); ok {
|
||||
for _, elem := range d {
|
||||
e.addElem(elem.Name, reflect.ValueOf(elem.Value), false)
|
||||
}
|
||||
return
|
||||
}
|
||||
l := v.Len()
|
||||
et := v.Type().Elem()
|
||||
if et == typeDocElem {
|
||||
for i := 0; i < l; i++ {
|
||||
elem := v.Index(i).Interface().(DocElem)
|
||||
e.addElem(elem.Name, reflect.ValueOf(elem.Value), false)
|
||||
}
|
||||
return
|
||||
}
|
||||
if et == typeRawDocElem {
|
||||
for i := 0; i < l; i++ {
|
||||
elem := v.Index(i).Interface().(RawDocElem)
|
||||
e.addElem(elem.Name, reflect.ValueOf(elem.Value), false)
|
||||
}
|
||||
return
|
||||
}
|
||||
for i := 0; i < l; i++ {
|
||||
e.addElem(itoa(i), v.Index(i), false)
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Marshaling of elements in a document.
|
||||
|
||||
func (e *encoder) addElemName(kind byte, name string) {
|
||||
e.addBytes(kind)
|
||||
e.addBytes([]byte(name)...)
|
||||
e.addBytes(0)
|
||||
}
|
||||
|
||||
func (e *encoder) addElem(name string, v reflect.Value, minSize bool) {
|
||||
|
||||
if !v.IsValid() {
|
||||
e.addElemName(0x0A, name)
|
||||
return
|
||||
}
|
||||
|
||||
if getter := getGetter(v.Type(), v); getter != nil {
|
||||
getv, err := getter.GetBSON()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
e.addElem(name, reflect.ValueOf(getv), minSize)
|
||||
return
|
||||
}
|
||||
|
||||
switch v.Kind() {
|
||||
|
||||
case reflect.Interface:
|
||||
e.addElem(name, v.Elem(), minSize)
|
||||
|
||||
case reflect.Ptr:
|
||||
e.addElem(name, v.Elem(), minSize)
|
||||
|
||||
case reflect.String:
|
||||
s := v.String()
|
||||
switch v.Type() {
|
||||
case typeObjectId:
|
||||
if len(s) != 12 {
|
||||
panic("ObjectIDs must be exactly 12 bytes long (got " +
|
||||
strconv.Itoa(len(s)) + ")")
|
||||
}
|
||||
e.addElemName(0x07, name)
|
||||
e.addBytes([]byte(s)...)
|
||||
case typeSymbol:
|
||||
e.addElemName(0x0E, name)
|
||||
e.addStr(s)
|
||||
case typeJSONNumber:
|
||||
n := v.Interface().(json.Number)
|
||||
if i, err := n.Int64(); err == nil {
|
||||
e.addElemName(0x12, name)
|
||||
e.addInt64(i)
|
||||
} else if f, err := n.Float64(); err == nil {
|
||||
e.addElemName(0x01, name)
|
||||
e.addFloat64(f)
|
||||
} else {
|
||||
panic("failed to convert json.Number to a number: " + s)
|
||||
}
|
||||
default:
|
||||
e.addElemName(0x02, name)
|
||||
e.addStr(s)
|
||||
}
|
||||
|
||||
case reflect.Float32, reflect.Float64:
|
||||
e.addElemName(0x01, name)
|
||||
e.addFloat64(v.Float())
|
||||
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
u := v.Uint()
|
||||
if int64(u) < 0 {
|
||||
panic("BSON has no uint64 type, and value is too large to fit correctly in an int64")
|
||||
} else if u <= math.MaxInt32 && (minSize || v.Kind() <= reflect.Uint32) {
|
||||
e.addElemName(0x10, name)
|
||||
e.addInt32(int32(u))
|
||||
} else {
|
||||
e.addElemName(0x12, name)
|
||||
e.addInt64(int64(u))
|
||||
}
|
||||
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
switch v.Type() {
|
||||
case typeMongoTimestamp:
|
||||
e.addElemName(0x11, name)
|
||||
e.addInt64(v.Int())
|
||||
|
||||
case typeOrderKey:
|
||||
if v.Int() == int64(MaxKey) {
|
||||
e.addElemName(0x7F, name)
|
||||
} else {
|
||||
e.addElemName(0xFF, name)
|
||||
}
|
||||
case typeTimeDuration:
|
||||
// Stored as int64
|
||||
e.addElemName(0x12, name)
|
||||
|
||||
e.addInt64(int64(v.Int() / 1e6))
|
||||
default:
|
||||
i := v.Int()
|
||||
if (minSize || v.Type().Kind() != reflect.Int64) && i >= math.MinInt32 && i <= math.MaxInt32 {
|
||||
// It fits into an int32, encode as such.
|
||||
e.addElemName(0x10, name)
|
||||
e.addInt32(int32(i))
|
||||
} else {
|
||||
e.addElemName(0x12, name)
|
||||
e.addInt64(i)
|
||||
}
|
||||
}
|
||||
|
||||
case reflect.Bool:
|
||||
e.addElemName(0x08, name)
|
||||
if v.Bool() {
|
||||
e.addBytes(1)
|
||||
} else {
|
||||
e.addBytes(0)
|
||||
}
|
||||
|
||||
case reflect.Map:
|
||||
e.addElemName(0x03, name)
|
||||
e.addDoc(v)
|
||||
|
||||
case reflect.Slice:
|
||||
vt := v.Type()
|
||||
et := vt.Elem()
|
||||
if et.Kind() == reflect.Uint8 {
|
||||
if arrayOps[name] {
|
||||
e.addElemName(0x04, name)
|
||||
e.addDoc(v)
|
||||
} else {
|
||||
e.addElemName(0x05, name)
|
||||
e.addBinary(0x00, v.Bytes())
|
||||
}
|
||||
} else if et == typeDocElem || et == typeRawDocElem {
|
||||
e.addElemName(0x03, name)
|
||||
e.addDoc(v)
|
||||
} else {
|
||||
e.addElemName(0x04, name)
|
||||
e.addDoc(v)
|
||||
}
|
||||
|
||||
case reflect.Array:
|
||||
et := v.Type().Elem()
|
||||
if et.Kind() == reflect.Uint8 {
|
||||
if arrayOps[name] {
|
||||
e.addElemName(0x04, name)
|
||||
e.addDoc(v)
|
||||
} else {
|
||||
e.addElemName(0x05, name)
|
||||
if v.CanAddr() {
|
||||
e.addBinary(0x00, v.Slice(0, v.Len()).Interface().([]byte))
|
||||
} else {
|
||||
n := v.Len()
|
||||
e.addInt32(int32(n))
|
||||
e.addBytes(0x00)
|
||||
for i := 0; i < n; i++ {
|
||||
el := v.Index(i)
|
||||
e.addBytes(byte(el.Uint()))
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
e.addElemName(0x04, name)
|
||||
e.addDoc(v)
|
||||
}
|
||||
|
||||
case reflect.Struct:
|
||||
switch s := v.Interface().(type) {
|
||||
|
||||
case Raw:
|
||||
kind := s.Kind
|
||||
if kind == 0x00 {
|
||||
kind = 0x03
|
||||
}
|
||||
if len(s.Data) == 0 && kind != 0x06 && kind != 0x0A && kind != 0xFF && kind != 0x7F {
|
||||
panic("Attempted to marshal empty Raw document")
|
||||
}
|
||||
e.addElemName(kind, name)
|
||||
e.addBytes(s.Data...)
|
||||
|
||||
case Binary:
|
||||
e.addElemName(0x05, name)
|
||||
e.addBinary(s.Kind, s.Data)
|
||||
|
||||
case Decimal128:
|
||||
e.addElemName(0x13, name)
|
||||
e.addInt64(int64(s.l))
|
||||
e.addInt64(int64(s.h))
|
||||
|
||||
case DBPointer:
|
||||
e.addElemName(0x0C, name)
|
||||
e.addStr(s.Namespace)
|
||||
if len(s.Id) != 12 {
|
||||
panic("ObjectIDs must be exactly 12 bytes long (got " +
|
||||
strconv.Itoa(len(s.Id)) + ")")
|
||||
}
|
||||
e.addBytes([]byte(s.Id)...)
|
||||
|
||||
case RegEx:
|
||||
e.addElemName(0x0B, name)
|
||||
e.addCStr(s.Pattern)
|
||||
options := runes(s.Options)
|
||||
sort.Sort(options)
|
||||
e.addCStr(string(options))
|
||||
|
||||
case JavaScript:
|
||||
if s.Scope == nil {
|
||||
e.addElemName(0x0D, name)
|
||||
e.addStr(s.Code)
|
||||
} else {
|
||||
e.addElemName(0x0F, name)
|
||||
start := e.reserveInt32()
|
||||
e.addStr(s.Code)
|
||||
e.addDoc(reflect.ValueOf(s.Scope))
|
||||
e.setInt32(start, int32(len(e.out)-start))
|
||||
}
|
||||
|
||||
case time.Time:
|
||||
// MongoDB handles timestamps as milliseconds.
|
||||
e.addElemName(0x09, name)
|
||||
e.addInt64(s.Unix()*1000 + int64(s.Nanosecond()/1e6))
|
||||
|
||||
case url.URL:
|
||||
e.addElemName(0x02, name)
|
||||
e.addStr(s.String())
|
||||
|
||||
case undefined:
|
||||
e.addElemName(0x06, name)
|
||||
|
||||
default:
|
||||
e.addElemName(0x03, name)
|
||||
e.addDoc(v)
|
||||
}
|
||||
|
||||
default:
|
||||
panic("Can't marshal " + v.Type().String() + " in a BSON document")
|
||||
}
|
||||
}
|
||||
|
||||
// -------------
|
||||
// Helper method for sorting regex options
|
||||
type runes []rune
|
||||
|
||||
func (a runes) Len() int { return len(a) }
|
||||
func (a runes) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||
func (a runes) Less(i, j int) bool { return a[i] < a[j] }
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Marshaling of base types.
|
||||
|
||||
func (e *encoder) addBinary(subtype byte, v []byte) {
|
||||
if subtype == 0x02 {
|
||||
// Wonder how that brilliant idea came to life. Obsolete, luckily.
|
||||
e.addInt32(int32(len(v) + 4))
|
||||
e.addBytes(subtype)
|
||||
e.addInt32(int32(len(v)))
|
||||
} else {
|
||||
e.addInt32(int32(len(v)))
|
||||
e.addBytes(subtype)
|
||||
}
|
||||
e.addBytes(v...)
|
||||
}
|
||||
|
||||
func (e *encoder) addStr(v string) {
|
||||
e.addInt32(int32(len(v) + 1))
|
||||
e.addCStr(v)
|
||||
}
|
||||
|
||||
func (e *encoder) addCStr(v string) {
|
||||
e.addBytes([]byte(v)...)
|
||||
e.addBytes(0)
|
||||
}
|
||||
|
||||
func (e *encoder) reserveInt32() (pos int) {
|
||||
pos = len(e.out)
|
||||
e.addBytes(0, 0, 0, 0)
|
||||
return pos
|
||||
}
|
||||
|
||||
func (e *encoder) setInt32(pos int, v int32) {
|
||||
e.out[pos+0] = byte(v)
|
||||
e.out[pos+1] = byte(v >> 8)
|
||||
e.out[pos+2] = byte(v >> 16)
|
||||
e.out[pos+3] = byte(v >> 24)
|
||||
}
|
||||
|
||||
func (e *encoder) addInt32(v int32) {
|
||||
u := uint32(v)
|
||||
e.addBytes(byte(u), byte(u>>8), byte(u>>16), byte(u>>24))
|
||||
}
|
||||
|
||||
func (e *encoder) addInt64(v int64) {
|
||||
u := uint64(v)
|
||||
e.addBytes(byte(u), byte(u>>8), byte(u>>16), byte(u>>24),
|
||||
byte(u>>32), byte(u>>40), byte(u>>48), byte(u>>56))
|
||||
}
|
||||
|
||||
func (e *encoder) addFloat64(v float64) {
|
||||
e.addInt64(int64(math.Float64bits(v)))
|
||||
}
|
||||
|
||||
func (e *encoder) addBytes(v ...byte) {
|
||||
e.out = append(e.out, v...)
|
||||
}
|
||||
384
vendor/github.com/globalsign/mgo/bson/json.go
generated
vendored
Normal file
384
vendor/github.com/globalsign/mgo/bson/json.go
generated
vendored
Normal file
@@ -0,0 +1,384 @@
|
||||
package bson
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/globalsign/mgo/internal/json"
|
||||
)
|
||||
|
||||
// UnmarshalJSON unmarshals a JSON value that may hold non-standard
|
||||
// syntax as defined in BSON's extended JSON specification.
|
||||
func UnmarshalJSON(data []byte, value interface{}) error {
|
||||
d := json.NewDecoder(bytes.NewBuffer(data))
|
||||
d.Extend(&jsonExt)
|
||||
return d.Decode(value)
|
||||
}
|
||||
|
||||
// MarshalJSON marshals a JSON value that may hold non-standard
|
||||
// syntax as defined in BSON's extended JSON specification.
|
||||
func MarshalJSON(value interface{}) ([]byte, error) {
|
||||
var buf bytes.Buffer
|
||||
e := json.NewEncoder(&buf)
|
||||
e.Extend(&jsonExt)
|
||||
err := e.Encode(value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
// jdec is used internally by the JSON decoding functions
|
||||
// so they may unmarshal functions without getting into endless
|
||||
// recursion due to keyed objects.
|
||||
func jdec(data []byte, value interface{}) error {
|
||||
d := json.NewDecoder(bytes.NewBuffer(data))
|
||||
d.Extend(&funcExt)
|
||||
return d.Decode(value)
|
||||
}
|
||||
|
||||
var jsonExt json.Extension
|
||||
var funcExt json.Extension
|
||||
|
||||
// TODO
|
||||
// - Shell regular expressions ("/regexp/opts")
|
||||
|
||||
func init() {
|
||||
jsonExt.DecodeUnquotedKeys(true)
|
||||
jsonExt.DecodeTrailingCommas(true)
|
||||
|
||||
funcExt.DecodeFunc("BinData", "$binaryFunc", "$type", "$binary")
|
||||
jsonExt.DecodeKeyed("$binary", jdecBinary)
|
||||
jsonExt.DecodeKeyed("$binaryFunc", jdecBinary)
|
||||
jsonExt.EncodeType([]byte(nil), jencBinarySlice)
|
||||
jsonExt.EncodeType(Binary{}, jencBinaryType)
|
||||
|
||||
funcExt.DecodeFunc("ISODate", "$dateFunc", "S")
|
||||
funcExt.DecodeFunc("new Date", "$dateFunc", "S")
|
||||
jsonExt.DecodeKeyed("$date", jdecDate)
|
||||
jsonExt.DecodeKeyed("$dateFunc", jdecDate)
|
||||
jsonExt.EncodeType(time.Time{}, jencDate)
|
||||
|
||||
funcExt.DecodeFunc("Timestamp", "$timestamp", "t", "i")
|
||||
jsonExt.DecodeKeyed("$timestamp", jdecTimestamp)
|
||||
jsonExt.EncodeType(MongoTimestamp(0), jencTimestamp)
|
||||
|
||||
funcExt.DecodeConst("undefined", Undefined)
|
||||
|
||||
jsonExt.DecodeKeyed("$regex", jdecRegEx)
|
||||
jsonExt.EncodeType(RegEx{}, jencRegEx)
|
||||
|
||||
funcExt.DecodeFunc("ObjectId", "$oidFunc", "Id")
|
||||
jsonExt.DecodeKeyed("$oid", jdecObjectId)
|
||||
jsonExt.DecodeKeyed("$oidFunc", jdecObjectId)
|
||||
jsonExt.EncodeType(ObjectId(""), jencObjectId)
|
||||
|
||||
funcExt.DecodeFunc("DBRef", "$dbrefFunc", "$ref", "$id")
|
||||
jsonExt.DecodeKeyed("$dbrefFunc", jdecDBRef)
|
||||
|
||||
funcExt.DecodeFunc("NumberLong", "$numberLongFunc", "N")
|
||||
jsonExt.DecodeKeyed("$numberLong", jdecNumberLong)
|
||||
jsonExt.DecodeKeyed("$numberLongFunc", jdecNumberLong)
|
||||
jsonExt.EncodeType(int64(0), jencNumberLong)
|
||||
jsonExt.EncodeType(int(0), jencInt)
|
||||
|
||||
funcExt.DecodeConst("MinKey", MinKey)
|
||||
funcExt.DecodeConst("MaxKey", MaxKey)
|
||||
jsonExt.DecodeKeyed("$minKey", jdecMinKey)
|
||||
jsonExt.DecodeKeyed("$maxKey", jdecMaxKey)
|
||||
jsonExt.EncodeType(orderKey(0), jencMinMaxKey)
|
||||
|
||||
jsonExt.DecodeKeyed("$undefined", jdecUndefined)
|
||||
jsonExt.EncodeType(Undefined, jencUndefined)
|
||||
|
||||
jsonExt.Extend(&funcExt)
|
||||
}
|
||||
|
||||
func fbytes(format string, args ...interface{}) []byte {
|
||||
var buf bytes.Buffer
|
||||
fmt.Fprintf(&buf, format, args...)
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
func jdecBinary(data []byte) (interface{}, error) {
|
||||
var v struct {
|
||||
Binary []byte `json:"$binary"`
|
||||
Type string `json:"$type"`
|
||||
Func struct {
|
||||
Binary []byte `json:"$binary"`
|
||||
Type int64 `json:"$type"`
|
||||
} `json:"$binaryFunc"`
|
||||
}
|
||||
err := jdec(data, &v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var binData []byte
|
||||
var binKind int64
|
||||
if v.Type == "" && v.Binary == nil {
|
||||
binData = v.Func.Binary
|
||||
binKind = v.Func.Type
|
||||
} else if v.Type == "" {
|
||||
return v.Binary, nil
|
||||
} else {
|
||||
binData = v.Binary
|
||||
binKind, err = strconv.ParseInt(v.Type, 0, 64)
|
||||
if err != nil {
|
||||
binKind = -1
|
||||
}
|
||||
}
|
||||
|
||||
if binKind == 0 {
|
||||
return binData, nil
|
||||
}
|
||||
if binKind < 0 || binKind > 255 {
|
||||
return nil, fmt.Errorf("invalid type in binary object: %s", data)
|
||||
}
|
||||
|
||||
return Binary{Kind: byte(binKind), Data: binData}, nil
|
||||
}
|
||||
|
||||
func jencBinarySlice(v interface{}) ([]byte, error) {
|
||||
in := v.([]byte)
|
||||
out := make([]byte, base64.StdEncoding.EncodedLen(len(in)))
|
||||
base64.StdEncoding.Encode(out, in)
|
||||
return fbytes(`{"$binary":"%s","$type":"0x0"}`, out), nil
|
||||
}
|
||||
|
||||
func jencBinaryType(v interface{}) ([]byte, error) {
|
||||
in := v.(Binary)
|
||||
out := make([]byte, base64.StdEncoding.EncodedLen(len(in.Data)))
|
||||
base64.StdEncoding.Encode(out, in.Data)
|
||||
return fbytes(`{"$binary":"%s","$type":"0x%x"}`, out, in.Kind), nil
|
||||
}
|
||||
|
||||
const jdateFormat = "2006-01-02T15:04:05.999Z07:00"
|
||||
|
||||
func jdecDate(data []byte) (interface{}, error) {
|
||||
var v struct {
|
||||
S string `json:"$date"`
|
||||
Func struct {
|
||||
S string
|
||||
} `json:"$dateFunc"`
|
||||
}
|
||||
_ = jdec(data, &v)
|
||||
if v.S == "" {
|
||||
v.S = v.Func.S
|
||||
}
|
||||
if v.S != "" {
|
||||
var errs []string
|
||||
for _, format := range []string{jdateFormat, "2006-01-02"} {
|
||||
t, err := time.Parse(format, v.S)
|
||||
if err == nil {
|
||||
return t, nil
|
||||
}
|
||||
errs = append(errs, err.Error())
|
||||
}
|
||||
return nil, fmt.Errorf("cannot parse date: %q [%s]", v.S, strings.Join(errs, ", "))
|
||||
}
|
||||
|
||||
var vn struct {
|
||||
Date struct {
|
||||
N int64 `json:"$numberLong,string"`
|
||||
} `json:"$date"`
|
||||
Func struct {
|
||||
S int64
|
||||
} `json:"$dateFunc"`
|
||||
}
|
||||
err := jdec(data, &vn)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot parse date: %q", data)
|
||||
}
|
||||
n := vn.Date.N
|
||||
if n == 0 {
|
||||
n = vn.Func.S
|
||||
}
|
||||
return time.Unix(n/1000, n%1000*1e6).UTC(), nil
|
||||
}
|
||||
|
||||
func jencDate(v interface{}) ([]byte, error) {
|
||||
t := v.(time.Time)
|
||||
return fbytes(`{"$date":%q}`, t.Format(jdateFormat)), nil
|
||||
}
|
||||
|
||||
func jdecTimestamp(data []byte) (interface{}, error) {
|
||||
var v struct {
|
||||
Func struct {
|
||||
T int32 `json:"t"`
|
||||
I int32 `json:"i"`
|
||||
} `json:"$timestamp"`
|
||||
}
|
||||
err := jdec(data, &v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return MongoTimestamp(uint64(v.Func.T)<<32 | uint64(uint32(v.Func.I))), nil
|
||||
}
|
||||
|
||||
func jencTimestamp(v interface{}) ([]byte, error) {
|
||||
ts := uint64(v.(MongoTimestamp))
|
||||
return fbytes(`{"$timestamp":{"t":%d,"i":%d}}`, ts>>32, uint32(ts)), nil
|
||||
}
|
||||
|
||||
func jdecRegEx(data []byte) (interface{}, error) {
|
||||
var v struct {
|
||||
Regex string `json:"$regex"`
|
||||
Options string `json:"$options"`
|
||||
}
|
||||
err := jdec(data, &v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return RegEx{v.Regex, v.Options}, nil
|
||||
}
|
||||
|
||||
func jencRegEx(v interface{}) ([]byte, error) {
|
||||
re := v.(RegEx)
|
||||
type regex struct {
|
||||
Regex string `json:"$regex"`
|
||||
Options string `json:"$options"`
|
||||
}
|
||||
return json.Marshal(regex{re.Pattern, re.Options})
|
||||
}
|
||||
|
||||
func jdecObjectId(data []byte) (interface{}, error) {
|
||||
var v struct {
|
||||
Id string `json:"$oid"`
|
||||
Func struct {
|
||||
Id string
|
||||
} `json:"$oidFunc"`
|
||||
}
|
||||
err := jdec(data, &v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if v.Id == "" {
|
||||
v.Id = v.Func.Id
|
||||
}
|
||||
return ObjectIdHex(v.Id), nil
|
||||
}
|
||||
|
||||
func jencObjectId(v interface{}) ([]byte, error) {
|
||||
return fbytes(`{"$oid":"%s"}`, v.(ObjectId).Hex()), nil
|
||||
}
|
||||
|
||||
func jdecDBRef(data []byte) (interface{}, error) {
|
||||
// TODO Support unmarshaling $ref and $id into the input value.
|
||||
var v struct {
|
||||
Obj map[string]interface{} `json:"$dbrefFunc"`
|
||||
}
|
||||
// TODO Fix this. Must not be required.
|
||||
v.Obj = make(map[string]interface{})
|
||||
err := jdec(data, &v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return v.Obj, nil
|
||||
}
|
||||
|
||||
func jdecNumberLong(data []byte) (interface{}, error) {
|
||||
var v struct {
|
||||
N int64 `json:"$numberLong,string"`
|
||||
Func struct {
|
||||
N int64 `json:",string"`
|
||||
} `json:"$numberLongFunc"`
|
||||
}
|
||||
var vn struct {
|
||||
N int64 `json:"$numberLong"`
|
||||
Func struct {
|
||||
N int64
|
||||
} `json:"$numberLongFunc"`
|
||||
}
|
||||
err := jdec(data, &v)
|
||||
if err != nil {
|
||||
err = jdec(data, &vn)
|
||||
v.N = vn.N
|
||||
v.Func.N = vn.Func.N
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if v.N != 0 {
|
||||
return v.N, nil
|
||||
}
|
||||
return v.Func.N, nil
|
||||
}
|
||||
|
||||
func jencNumberLong(v interface{}) ([]byte, error) {
|
||||
n := v.(int64)
|
||||
f := `{"$numberLong":"%d"}`
|
||||
if n <= 1<<53 {
|
||||
f = `{"$numberLong":%d}`
|
||||
}
|
||||
return fbytes(f, n), nil
|
||||
}
|
||||
|
||||
func jencInt(v interface{}) ([]byte, error) {
|
||||
n := v.(int)
|
||||
f := `{"$numberLong":"%d"}`
|
||||
if int64(n) <= 1<<53 {
|
||||
f = `%d`
|
||||
}
|
||||
return fbytes(f, n), nil
|
||||
}
|
||||
|
||||
func jdecMinKey(data []byte) (interface{}, error) {
|
||||
var v struct {
|
||||
N int64 `json:"$minKey"`
|
||||
}
|
||||
err := jdec(data, &v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if v.N != 1 {
|
||||
return nil, fmt.Errorf("invalid $minKey object: %s", data)
|
||||
}
|
||||
return MinKey, nil
|
||||
}
|
||||
|
||||
func jdecMaxKey(data []byte) (interface{}, error) {
|
||||
var v struct {
|
||||
N int64 `json:"$maxKey"`
|
||||
}
|
||||
err := jdec(data, &v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if v.N != 1 {
|
||||
return nil, fmt.Errorf("invalid $maxKey object: %s", data)
|
||||
}
|
||||
return MaxKey, nil
|
||||
}
|
||||
|
||||
func jencMinMaxKey(v interface{}) ([]byte, error) {
|
||||
switch v.(orderKey) {
|
||||
case MinKey:
|
||||
return []byte(`{"$minKey":1}`), nil
|
||||
case MaxKey:
|
||||
return []byte(`{"$maxKey":1}`), nil
|
||||
}
|
||||
panic(fmt.Sprintf("invalid $minKey/$maxKey value: %d", v))
|
||||
}
|
||||
|
||||
func jdecUndefined(data []byte) (interface{}, error) {
|
||||
var v struct {
|
||||
B bool `json:"$undefined"`
|
||||
}
|
||||
err := jdec(data, &v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !v.B {
|
||||
return nil, fmt.Errorf("invalid $undefined object: %s", data)
|
||||
}
|
||||
return Undefined, nil
|
||||
}
|
||||
|
||||
func jencUndefined(v interface{}) ([]byte, error) {
|
||||
return []byte(`{"$undefined":true}`), nil
|
||||
}
|
||||
90
vendor/github.com/globalsign/mgo/bson/stream.go
generated
vendored
Normal file
90
vendor/github.com/globalsign/mgo/bson/stream.go
generated
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
package bson
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
const (
|
||||
// MinDocumentSize is the size of the smallest possible valid BSON document:
|
||||
// an int32 size header + 0x00 (end of document).
|
||||
MinDocumentSize = 5
|
||||
|
||||
// MaxDocumentSize is the largest possible size for a BSON document allowed by MongoDB,
|
||||
// that is, 16 MiB (see https://docs.mongodb.com/manual/reference/limits/).
|
||||
MaxDocumentSize = 16777216
|
||||
)
|
||||
|
||||
// ErrInvalidDocumentSize is an error returned when a BSON document's header
|
||||
// contains a size smaller than MinDocumentSize or greater than MaxDocumentSize.
|
||||
type ErrInvalidDocumentSize struct {
|
||||
DocumentSize int32
|
||||
}
|
||||
|
||||
func (e ErrInvalidDocumentSize) Error() string {
|
||||
return fmt.Sprintf("invalid document size %d", e.DocumentSize)
|
||||
}
|
||||
|
||||
// A Decoder reads and decodes BSON values from an input stream.
|
||||
type Decoder struct {
|
||||
source io.Reader
|
||||
}
|
||||
|
||||
// NewDecoder returns a new Decoder that reads from source.
|
||||
// It does not add any extra buffering, and may not read data from source beyond the BSON values requested.
|
||||
func NewDecoder(source io.Reader) *Decoder {
|
||||
return &Decoder{source: source}
|
||||
}
|
||||
|
||||
// Decode reads the next BSON-encoded value from its input and stores it in the value pointed to by v.
|
||||
// See the documentation for Unmarshal for details about the conversion of BSON into a Go value.
|
||||
func (dec *Decoder) Decode(v interface{}) (err error) {
|
||||
// BSON documents start with their size as a *signed* int32.
|
||||
var docSize int32
|
||||
if err = binary.Read(dec.source, binary.LittleEndian, &docSize); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if docSize < MinDocumentSize || docSize > MaxDocumentSize {
|
||||
return ErrInvalidDocumentSize{DocumentSize: docSize}
|
||||
}
|
||||
|
||||
docBuffer := bytes.NewBuffer(make([]byte, 0, docSize))
|
||||
if err = binary.Write(docBuffer, binary.LittleEndian, docSize); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// docSize is the *full* document's size (including the 4-byte size header,
|
||||
// which has already been read).
|
||||
if _, err = io.CopyN(docBuffer, dec.source, int64(docSize-4)); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Let Unmarshal handle the rest.
|
||||
defer handleErr(&err)
|
||||
return Unmarshal(docBuffer.Bytes(), v)
|
||||
}
|
||||
|
||||
// An Encoder encodes and writes BSON values to an output stream.
|
||||
type Encoder struct {
|
||||
target io.Writer
|
||||
}
|
||||
|
||||
// NewEncoder returns a new Encoder that writes to target.
|
||||
func NewEncoder(target io.Writer) *Encoder {
|
||||
return &Encoder{target: target}
|
||||
}
|
||||
|
||||
// Encode encodes v to BSON, and if successful writes it to the Encoder's output stream.
|
||||
// See the documentation for Marshal for details about the conversion of Go values to BSON.
|
||||
func (enc *Encoder) Encode(v interface{}) error {
|
||||
data, err := Marshal(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = enc.target.Write(data)
|
||||
return err
|
||||
}
|
||||
27
vendor/github.com/globalsign/mgo/internal/json/LICENSE
generated
vendored
Normal file
27
vendor/github.com/globalsign/mgo/internal/json/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
Copyright (c) 2012 The Go Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
1685
vendor/github.com/globalsign/mgo/internal/json/decode.go
generated
vendored
Normal file
1685
vendor/github.com/globalsign/mgo/internal/json/decode.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1260
vendor/github.com/globalsign/mgo/internal/json/encode.go
generated
vendored
Normal file
1260
vendor/github.com/globalsign/mgo/internal/json/encode.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
95
vendor/github.com/globalsign/mgo/internal/json/extension.go
generated
vendored
Normal file
95
vendor/github.com/globalsign/mgo/internal/json/extension.go
generated
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
package json
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// Extension holds a set of additional rules to be used when unmarshaling
|
||||
// strict JSON or JSON-like content.
|
||||
type Extension struct {
|
||||
funcs map[string]funcExt
|
||||
consts map[string]interface{}
|
||||
keyed map[string]func([]byte) (interface{}, error)
|
||||
encode map[reflect.Type]func(v interface{}) ([]byte, error)
|
||||
|
||||
unquotedKeys bool
|
||||
trailingCommas bool
|
||||
}
|
||||
|
||||
type funcExt struct {
|
||||
key string
|
||||
args []string
|
||||
}
|
||||
|
||||
// Extend changes the decoder behavior to consider the provided extension.
|
||||
func (dec *Decoder) Extend(ext *Extension) { dec.d.ext = *ext }
|
||||
|
||||
// Extend changes the encoder behavior to consider the provided extension.
|
||||
func (enc *Encoder) Extend(ext *Extension) { enc.ext = *ext }
|
||||
|
||||
// Extend includes in e the extensions defined in ext.
|
||||
func (e *Extension) Extend(ext *Extension) {
|
||||
for name, fext := range ext.funcs {
|
||||
e.DecodeFunc(name, fext.key, fext.args...)
|
||||
}
|
||||
for name, value := range ext.consts {
|
||||
e.DecodeConst(name, value)
|
||||
}
|
||||
for key, decode := range ext.keyed {
|
||||
e.DecodeKeyed(key, decode)
|
||||
}
|
||||
for typ, encode := range ext.encode {
|
||||
if e.encode == nil {
|
||||
e.encode = make(map[reflect.Type]func(v interface{}) ([]byte, error))
|
||||
}
|
||||
e.encode[typ] = encode
|
||||
}
|
||||
}
|
||||
|
||||
// DecodeFunc defines a function call that may be observed inside JSON content.
|
||||
// A function with the provided name will be unmarshaled as the document
|
||||
// {key: {args[0]: ..., args[N]: ...}}.
|
||||
func (e *Extension) DecodeFunc(name string, key string, args ...string) {
|
||||
if e.funcs == nil {
|
||||
e.funcs = make(map[string]funcExt)
|
||||
}
|
||||
e.funcs[name] = funcExt{key, args}
|
||||
}
|
||||
|
||||
// DecodeConst defines a constant name that may be observed inside JSON content
|
||||
// and will be decoded with the provided value.
|
||||
func (e *Extension) DecodeConst(name string, value interface{}) {
|
||||
if e.consts == nil {
|
||||
e.consts = make(map[string]interface{})
|
||||
}
|
||||
e.consts[name] = value
|
||||
}
|
||||
|
||||
// DecodeKeyed defines a key that when observed as the first element inside a
|
||||
// JSON document triggers the decoding of that document via the provided
|
||||
// decode function.
|
||||
func (e *Extension) DecodeKeyed(key string, decode func(data []byte) (interface{}, error)) {
|
||||
if e.keyed == nil {
|
||||
e.keyed = make(map[string]func([]byte) (interface{}, error))
|
||||
}
|
||||
e.keyed[key] = decode
|
||||
}
|
||||
|
||||
// DecodeUnquotedKeys defines whether to accept map keys that are unquoted strings.
|
||||
func (e *Extension) DecodeUnquotedKeys(accept bool) {
|
||||
e.unquotedKeys = accept
|
||||
}
|
||||
|
||||
// DecodeTrailingCommas defines whether to accept trailing commas in maps and arrays.
|
||||
func (e *Extension) DecodeTrailingCommas(accept bool) {
|
||||
e.trailingCommas = accept
|
||||
}
|
||||
|
||||
// EncodeType registers a function to encode values with the same type of the
|
||||
// provided sample.
|
||||
func (e *Extension) EncodeType(sample interface{}, encode func(v interface{}) ([]byte, error)) {
|
||||
if e.encode == nil {
|
||||
e.encode = make(map[reflect.Type]func(v interface{}) ([]byte, error))
|
||||
}
|
||||
e.encode[reflect.TypeOf(sample)] = encode
|
||||
}
|
||||
143
vendor/github.com/globalsign/mgo/internal/json/fold.go
generated
vendored
Normal file
143
vendor/github.com/globalsign/mgo/internal/json/fold.go
generated
vendored
Normal file
@@ -0,0 +1,143 @@
|
||||
// Copyright 2013 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package json
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
const (
|
||||
caseMask = ^byte(0x20) // Mask to ignore case in ASCII.
|
||||
kelvin = '\u212a'
|
||||
smallLongEss = '\u017f'
|
||||
)
|
||||
|
||||
// foldFunc returns one of four different case folding equivalence
|
||||
// functions, from most general (and slow) to fastest:
|
||||
//
|
||||
// 1) bytes.EqualFold, if the key s contains any non-ASCII UTF-8
|
||||
// 2) equalFoldRight, if s contains special folding ASCII ('k', 'K', 's', 'S')
|
||||
// 3) asciiEqualFold, no special, but includes non-letters (including _)
|
||||
// 4) simpleLetterEqualFold, no specials, no non-letters.
|
||||
//
|
||||
// The letters S and K are special because they map to 3 runes, not just 2:
|
||||
// * S maps to s and to U+017F 'ſ' Latin small letter long s
|
||||
// * k maps to K and to U+212A 'K' Kelvin sign
|
||||
// See https://play.golang.org/p/tTxjOc0OGo
|
||||
//
|
||||
// The returned function is specialized for matching against s and
|
||||
// should only be given s. It's not curried for performance reasons.
|
||||
func foldFunc(s []byte) func(s, t []byte) bool {
|
||||
nonLetter := false
|
||||
special := false // special letter
|
||||
for _, b := range s {
|
||||
if b >= utf8.RuneSelf {
|
||||
return bytes.EqualFold
|
||||
}
|
||||
upper := b & caseMask
|
||||
if upper < 'A' || upper > 'Z' {
|
||||
nonLetter = true
|
||||
} else if upper == 'K' || upper == 'S' {
|
||||
// See above for why these letters are special.
|
||||
special = true
|
||||
}
|
||||
}
|
||||
if special {
|
||||
return equalFoldRight
|
||||
}
|
||||
if nonLetter {
|
||||
return asciiEqualFold
|
||||
}
|
||||
return simpleLetterEqualFold
|
||||
}
|
||||
|
||||
// equalFoldRight is a specialization of bytes.EqualFold when s is
|
||||
// known to be all ASCII (including punctuation), but contains an 's',
|
||||
// 'S', 'k', or 'K', requiring a Unicode fold on the bytes in t.
|
||||
// See comments on foldFunc.
|
||||
func equalFoldRight(s, t []byte) bool {
|
||||
for _, sb := range s {
|
||||
if len(t) == 0 {
|
||||
return false
|
||||
}
|
||||
tb := t[0]
|
||||
if tb < utf8.RuneSelf {
|
||||
if sb != tb {
|
||||
sbUpper := sb & caseMask
|
||||
if 'A' <= sbUpper && sbUpper <= 'Z' {
|
||||
if sbUpper != tb&caseMask {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
t = t[1:]
|
||||
continue
|
||||
}
|
||||
// sb is ASCII and t is not. t must be either kelvin
|
||||
// sign or long s; sb must be s, S, k, or K.
|
||||
tr, size := utf8.DecodeRune(t)
|
||||
switch sb {
|
||||
case 's', 'S':
|
||||
if tr != smallLongEss {
|
||||
return false
|
||||
}
|
||||
case 'k', 'K':
|
||||
if tr != kelvin {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
return false
|
||||
}
|
||||
t = t[size:]
|
||||
|
||||
}
|
||||
if len(t) > 0 {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// asciiEqualFold is a specialization of bytes.EqualFold for use when
|
||||
// s is all ASCII (but may contain non-letters) and contains no
|
||||
// special-folding letters.
|
||||
// See comments on foldFunc.
|
||||
func asciiEqualFold(s, t []byte) bool {
|
||||
if len(s) != len(t) {
|
||||
return false
|
||||
}
|
||||
for i, sb := range s {
|
||||
tb := t[i]
|
||||
if sb == tb {
|
||||
continue
|
||||
}
|
||||
if ('a' <= sb && sb <= 'z') || ('A' <= sb && sb <= 'Z') {
|
||||
if sb&caseMask != tb&caseMask {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// simpleLetterEqualFold is a specialization of bytes.EqualFold for
|
||||
// use when s is all ASCII letters (no underscores, etc) and also
|
||||
// doesn't contain 'k', 'K', 's', or 'S'.
|
||||
// See comments on foldFunc.
|
||||
func simpleLetterEqualFold(s, t []byte) bool {
|
||||
if len(s) != len(t) {
|
||||
return false
|
||||
}
|
||||
for i, b := range s {
|
||||
if b&caseMask != t[i]&caseMask {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
141
vendor/github.com/globalsign/mgo/internal/json/indent.go
generated
vendored
Normal file
141
vendor/github.com/globalsign/mgo/internal/json/indent.go
generated
vendored
Normal file
@@ -0,0 +1,141 @@
|
||||
// Copyright 2010 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package json
|
||||
|
||||
import "bytes"
|
||||
|
||||
// Compact appends to dst the JSON-encoded src with
|
||||
// insignificant space characters elided.
|
||||
func Compact(dst *bytes.Buffer, src []byte) error {
|
||||
return compact(dst, src, false)
|
||||
}
|
||||
|
||||
func compact(dst *bytes.Buffer, src []byte, escape bool) error {
|
||||
origLen := dst.Len()
|
||||
var scan scanner
|
||||
scan.reset()
|
||||
start := 0
|
||||
for i, c := range src {
|
||||
if escape && (c == '<' || c == '>' || c == '&') {
|
||||
if start < i {
|
||||
dst.Write(src[start:i])
|
||||
}
|
||||
dst.WriteString(`\u00`)
|
||||
dst.WriteByte(hex[c>>4])
|
||||
dst.WriteByte(hex[c&0xF])
|
||||
start = i + 1
|
||||
}
|
||||
// Convert U+2028 and U+2029 (E2 80 A8 and E2 80 A9).
|
||||
if c == 0xE2 && i+2 < len(src) && src[i+1] == 0x80 && src[i+2]&^1 == 0xA8 {
|
||||
if start < i {
|
||||
dst.Write(src[start:i])
|
||||
}
|
||||
dst.WriteString(`\u202`)
|
||||
dst.WriteByte(hex[src[i+2]&0xF])
|
||||
start = i + 3
|
||||
}
|
||||
v := scan.step(&scan, c)
|
||||
if v >= scanSkipSpace {
|
||||
if v == scanError {
|
||||
break
|
||||
}
|
||||
if start < i {
|
||||
dst.Write(src[start:i])
|
||||
}
|
||||
start = i + 1
|
||||
}
|
||||
}
|
||||
if scan.eof() == scanError {
|
||||
dst.Truncate(origLen)
|
||||
return scan.err
|
||||
}
|
||||
if start < len(src) {
|
||||
dst.Write(src[start:])
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func newline(dst *bytes.Buffer, prefix, indent string, depth int) {
|
||||
dst.WriteByte('\n')
|
||||
dst.WriteString(prefix)
|
||||
for i := 0; i < depth; i++ {
|
||||
dst.WriteString(indent)
|
||||
}
|
||||
}
|
||||
|
||||
// Indent appends to dst an indented form of the JSON-encoded src.
|
||||
// Each element in a JSON object or array begins on a new,
|
||||
// indented line beginning with prefix followed by one or more
|
||||
// copies of indent according to the indentation nesting.
|
||||
// The data appended to dst does not begin with the prefix nor
|
||||
// any indentation, to make it easier to embed inside other formatted JSON data.
|
||||
// Although leading space characters (space, tab, carriage return, newline)
|
||||
// at the beginning of src are dropped, trailing space characters
|
||||
// at the end of src are preserved and copied to dst.
|
||||
// For example, if src has no trailing spaces, neither will dst;
|
||||
// if src ends in a trailing newline, so will dst.
|
||||
func Indent(dst *bytes.Buffer, src []byte, prefix, indent string) error {
|
||||
origLen := dst.Len()
|
||||
var scan scanner
|
||||
scan.reset()
|
||||
needIndent := false
|
||||
depth := 0
|
||||
for _, c := range src {
|
||||
scan.bytes++
|
||||
v := scan.step(&scan, c)
|
||||
if v == scanSkipSpace {
|
||||
continue
|
||||
}
|
||||
if v == scanError {
|
||||
break
|
||||
}
|
||||
if needIndent && v != scanEndObject && v != scanEndArray {
|
||||
needIndent = false
|
||||
depth++
|
||||
newline(dst, prefix, indent, depth)
|
||||
}
|
||||
|
||||
// Emit semantically uninteresting bytes
|
||||
// (in particular, punctuation in strings) unmodified.
|
||||
if v == scanContinue {
|
||||
dst.WriteByte(c)
|
||||
continue
|
||||
}
|
||||
|
||||
// Add spacing around real punctuation.
|
||||
switch c {
|
||||
case '{', '[':
|
||||
// delay indent so that empty object and array are formatted as {} and [].
|
||||
needIndent = true
|
||||
dst.WriteByte(c)
|
||||
|
||||
case ',':
|
||||
dst.WriteByte(c)
|
||||
newline(dst, prefix, indent, depth)
|
||||
|
||||
case ':':
|
||||
dst.WriteByte(c)
|
||||
dst.WriteByte(' ')
|
||||
|
||||
case '}', ']':
|
||||
if needIndent {
|
||||
// suppress indent in empty object/array
|
||||
needIndent = false
|
||||
} else {
|
||||
depth--
|
||||
newline(dst, prefix, indent, depth)
|
||||
}
|
||||
dst.WriteByte(c)
|
||||
|
||||
default:
|
||||
dst.WriteByte(c)
|
||||
}
|
||||
}
|
||||
if scan.eof() == scanError {
|
||||
dst.Truncate(origLen)
|
||||
return scan.err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
697
vendor/github.com/globalsign/mgo/internal/json/scanner.go
generated
vendored
Normal file
697
vendor/github.com/globalsign/mgo/internal/json/scanner.go
generated
vendored
Normal file
@@ -0,0 +1,697 @@
|
||||
// Copyright 2010 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package json
|
||||
|
||||
// JSON value parser state machine.
|
||||
// Just about at the limit of what is reasonable to write by hand.
|
||||
// Some parts are a bit tedious, but overall it nicely factors out the
|
||||
// otherwise common code from the multiple scanning functions
|
||||
// in this package (Compact, Indent, checkValid, nextValue, etc).
|
||||
//
|
||||
// This file starts with two simple examples using the scanner
|
||||
// before diving into the scanner itself.
|
||||
|
||||
import "strconv"
|
||||
|
||||
// checkValid verifies that data is valid JSON-encoded data.
|
||||
// scan is passed in for use by checkValid to avoid an allocation.
|
||||
func checkValid(data []byte, scan *scanner) error {
|
||||
scan.reset()
|
||||
for _, c := range data {
|
||||
scan.bytes++
|
||||
if scan.step(scan, c) == scanError {
|
||||
return scan.err
|
||||
}
|
||||
}
|
||||
if scan.eof() == scanError {
|
||||
return scan.err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// nextValue splits data after the next whole JSON value,
|
||||
// returning that value and the bytes that follow it as separate slices.
|
||||
// scan is passed in for use by nextValue to avoid an allocation.
|
||||
func nextValue(data []byte, scan *scanner) (value, rest []byte, err error) {
|
||||
scan.reset()
|
||||
for i, c := range data {
|
||||
v := scan.step(scan, c)
|
||||
if v >= scanEndObject {
|
||||
switch v {
|
||||
// probe the scanner with a space to determine whether we will
|
||||
// get scanEnd on the next character. Otherwise, if the next character
|
||||
// is not a space, scanEndTop allocates a needless error.
|
||||
case scanEndObject, scanEndArray, scanEndParams:
|
||||
if scan.step(scan, ' ') == scanEnd {
|
||||
return data[:i+1], data[i+1:], nil
|
||||
}
|
||||
case scanError:
|
||||
return nil, nil, scan.err
|
||||
case scanEnd:
|
||||
return data[:i], data[i:], nil
|
||||
}
|
||||
}
|
||||
}
|
||||
if scan.eof() == scanError {
|
||||
return nil, nil, scan.err
|
||||
}
|
||||
return data, nil, nil
|
||||
}
|
||||
|
||||
// A SyntaxError is a description of a JSON syntax error.
|
||||
type SyntaxError struct {
|
||||
msg string // description of error
|
||||
Offset int64 // error occurred after reading Offset bytes
|
||||
}
|
||||
|
||||
func (e *SyntaxError) Error() string { return e.msg }
|
||||
|
||||
// A scanner is a JSON scanning state machine.
|
||||
// Callers call scan.reset() and then pass bytes in one at a time
|
||||
// by calling scan.step(&scan, c) for each byte.
|
||||
// The return value, referred to as an opcode, tells the
|
||||
// caller about significant parsing events like beginning
|
||||
// and ending literals, objects, and arrays, so that the
|
||||
// caller can follow along if it wishes.
|
||||
// The return value scanEnd indicates that a single top-level
|
||||
// JSON value has been completed, *before* the byte that
|
||||
// just got passed in. (The indication must be delayed in order
|
||||
// to recognize the end of numbers: is 123 a whole value or
|
||||
// the beginning of 12345e+6?).
|
||||
type scanner struct {
|
||||
// The step is a func to be called to execute the next transition.
|
||||
// Also tried using an integer constant and a single func
|
||||
// with a switch, but using the func directly was 10% faster
|
||||
// on a 64-bit Mac Mini, and it's nicer to read.
|
||||
step func(*scanner, byte) int
|
||||
|
||||
// Reached end of top-level value.
|
||||
endTop bool
|
||||
|
||||
// Stack of what we're in the middle of - array values, object keys, object values.
|
||||
parseState []int
|
||||
|
||||
// Error that happened, if any.
|
||||
err error
|
||||
|
||||
// 1-byte redo (see undo method)
|
||||
redo bool
|
||||
redoCode int
|
||||
redoState func(*scanner, byte) int
|
||||
|
||||
// total bytes consumed, updated by decoder.Decode
|
||||
bytes int64
|
||||
}
|
||||
|
||||
// These values are returned by the state transition functions
|
||||
// assigned to scanner.state and the method scanner.eof.
|
||||
// They give details about the current state of the scan that
|
||||
// callers might be interested to know about.
|
||||
// It is okay to ignore the return value of any particular
|
||||
// call to scanner.state: if one call returns scanError,
|
||||
// every subsequent call will return scanError too.
|
||||
const (
|
||||
// Continue.
|
||||
scanContinue = iota // uninteresting byte
|
||||
scanBeginLiteral // end implied by next result != scanContinue
|
||||
scanBeginObject // begin object
|
||||
scanObjectKey // just finished object key (string)
|
||||
scanObjectValue // just finished non-last object value
|
||||
scanEndObject // end object (implies scanObjectValue if possible)
|
||||
scanBeginArray // begin array
|
||||
scanArrayValue // just finished array value
|
||||
scanEndArray // end array (implies scanArrayValue if possible)
|
||||
scanBeginName // begin function call
|
||||
scanParam // begin function argument
|
||||
scanEndParams // end function call
|
||||
scanSkipSpace // space byte; can skip; known to be last "continue" result
|
||||
|
||||
// Stop.
|
||||
scanEnd // top-level value ended *before* this byte; known to be first "stop" result
|
||||
scanError // hit an error, scanner.err.
|
||||
)
|
||||
|
||||
// These values are stored in the parseState stack.
|
||||
// They give the current state of a composite value
|
||||
// being scanned. If the parser is inside a nested value
|
||||
// the parseState describes the nested state, outermost at entry 0.
|
||||
const (
|
||||
parseObjectKey = iota // parsing object key (before colon)
|
||||
parseObjectValue // parsing object value (after colon)
|
||||
parseArrayValue // parsing array value
|
||||
parseName // parsing unquoted name
|
||||
parseParam // parsing function argument value
|
||||
)
|
||||
|
||||
// reset prepares the scanner for use.
|
||||
// It must be called before calling s.step.
|
||||
func (s *scanner) reset() {
|
||||
s.step = stateBeginValue
|
||||
s.parseState = s.parseState[0:0]
|
||||
s.err = nil
|
||||
s.redo = false
|
||||
s.endTop = false
|
||||
}
|
||||
|
||||
// eof tells the scanner that the end of input has been reached.
|
||||
// It returns a scan status just as s.step does.
|
||||
func (s *scanner) eof() int {
|
||||
if s.err != nil {
|
||||
return scanError
|
||||
}
|
||||
if s.endTop {
|
||||
return scanEnd
|
||||
}
|
||||
s.step(s, ' ')
|
||||
if s.endTop {
|
||||
return scanEnd
|
||||
}
|
||||
if s.err == nil {
|
||||
s.err = &SyntaxError{"unexpected end of JSON input", s.bytes}
|
||||
}
|
||||
return scanError
|
||||
}
|
||||
|
||||
// pushParseState pushes a new parse state p onto the parse stack.
|
||||
func (s *scanner) pushParseState(p int) {
|
||||
s.parseState = append(s.parseState, p)
|
||||
}
|
||||
|
||||
// popParseState pops a parse state (already obtained) off the stack
|
||||
// and updates s.step accordingly.
|
||||
func (s *scanner) popParseState() {
|
||||
n := len(s.parseState) - 1
|
||||
s.parseState = s.parseState[0:n]
|
||||
s.redo = false
|
||||
if n == 0 {
|
||||
s.step = stateEndTop
|
||||
s.endTop = true
|
||||
} else {
|
||||
s.step = stateEndValue
|
||||
}
|
||||
}
|
||||
|
||||
func isSpace(c byte) bool {
|
||||
return c == ' ' || c == '\t' || c == '\r' || c == '\n'
|
||||
}
|
||||
|
||||
// stateBeginValueOrEmpty is the state after reading `[`.
|
||||
func stateBeginValueOrEmpty(s *scanner, c byte) int {
|
||||
if c <= ' ' && isSpace(c) {
|
||||
return scanSkipSpace
|
||||
}
|
||||
if c == ']' {
|
||||
return stateEndValue(s, c)
|
||||
}
|
||||
return stateBeginValue(s, c)
|
||||
}
|
||||
|
||||
// stateBeginValue is the state at the beginning of the input.
|
||||
func stateBeginValue(s *scanner, c byte) int {
|
||||
if c <= ' ' && isSpace(c) {
|
||||
return scanSkipSpace
|
||||
}
|
||||
switch c {
|
||||
case '{':
|
||||
s.step = stateBeginStringOrEmpty
|
||||
s.pushParseState(parseObjectKey)
|
||||
return scanBeginObject
|
||||
case '[':
|
||||
s.step = stateBeginValueOrEmpty
|
||||
s.pushParseState(parseArrayValue)
|
||||
return scanBeginArray
|
||||
case '"':
|
||||
s.step = stateInString
|
||||
return scanBeginLiteral
|
||||
case '-':
|
||||
s.step = stateNeg
|
||||
return scanBeginLiteral
|
||||
case '0': // beginning of 0.123
|
||||
s.step = state0
|
||||
return scanBeginLiteral
|
||||
case 'n':
|
||||
s.step = stateNew0
|
||||
return scanBeginName
|
||||
}
|
||||
if '1' <= c && c <= '9' { // beginning of 1234.5
|
||||
s.step = state1
|
||||
return scanBeginLiteral
|
||||
}
|
||||
if isName(c) {
|
||||
s.step = stateName
|
||||
return scanBeginName
|
||||
}
|
||||
return s.error(c, "looking for beginning of value")
|
||||
}
|
||||
|
||||
func isName(c byte) bool {
|
||||
return c == '$' || c == '_' || 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9'
|
||||
}
|
||||
|
||||
// stateBeginStringOrEmpty is the state after reading `{`.
|
||||
func stateBeginStringOrEmpty(s *scanner, c byte) int {
|
||||
if c <= ' ' && isSpace(c) {
|
||||
return scanSkipSpace
|
||||
}
|
||||
if c == '}' {
|
||||
n := len(s.parseState)
|
||||
s.parseState[n-1] = parseObjectValue
|
||||
return stateEndValue(s, c)
|
||||
}
|
||||
return stateBeginString(s, c)
|
||||
}
|
||||
|
||||
// stateBeginString is the state after reading `{"key": value,`.
|
||||
func stateBeginString(s *scanner, c byte) int {
|
||||
if c <= ' ' && isSpace(c) {
|
||||
return scanSkipSpace
|
||||
}
|
||||
if c == '"' {
|
||||
s.step = stateInString
|
||||
return scanBeginLiteral
|
||||
}
|
||||
if isName(c) {
|
||||
s.step = stateName
|
||||
return scanBeginName
|
||||
}
|
||||
return s.error(c, "looking for beginning of object key string")
|
||||
}
|
||||
|
||||
// stateEndValue is the state after completing a value,
|
||||
// such as after reading `{}` or `true` or `["x"`.
|
||||
func stateEndValue(s *scanner, c byte) int {
|
||||
n := len(s.parseState)
|
||||
if n == 0 {
|
||||
// Completed top-level before the current byte.
|
||||
s.step = stateEndTop
|
||||
s.endTop = true
|
||||
return stateEndTop(s, c)
|
||||
}
|
||||
if c <= ' ' && isSpace(c) {
|
||||
s.step = stateEndValue
|
||||
return scanSkipSpace
|
||||
}
|
||||
ps := s.parseState[n-1]
|
||||
switch ps {
|
||||
case parseObjectKey:
|
||||
if c == ':' {
|
||||
s.parseState[n-1] = parseObjectValue
|
||||
s.step = stateBeginValue
|
||||
return scanObjectKey
|
||||
}
|
||||
return s.error(c, "after object key")
|
||||
case parseObjectValue:
|
||||
if c == ',' {
|
||||
s.parseState[n-1] = parseObjectKey
|
||||
s.step = stateBeginStringOrEmpty
|
||||
return scanObjectValue
|
||||
}
|
||||
if c == '}' {
|
||||
s.popParseState()
|
||||
return scanEndObject
|
||||
}
|
||||
return s.error(c, "after object key:value pair")
|
||||
case parseArrayValue:
|
||||
if c == ',' {
|
||||
s.step = stateBeginValueOrEmpty
|
||||
return scanArrayValue
|
||||
}
|
||||
if c == ']' {
|
||||
s.popParseState()
|
||||
return scanEndArray
|
||||
}
|
||||
return s.error(c, "after array element")
|
||||
case parseParam:
|
||||
if c == ',' {
|
||||
s.step = stateBeginValue
|
||||
return scanParam
|
||||
}
|
||||
if c == ')' {
|
||||
s.popParseState()
|
||||
return scanEndParams
|
||||
}
|
||||
return s.error(c, "after array element")
|
||||
}
|
||||
return s.error(c, "")
|
||||
}
|
||||
|
||||
// stateEndTop is the state after finishing the top-level value,
|
||||
// such as after reading `{}` or `[1,2,3]`.
|
||||
// Only space characters should be seen now.
|
||||
func stateEndTop(s *scanner, c byte) int {
|
||||
if c != ' ' && c != '\t' && c != '\r' && c != '\n' {
|
||||
// Complain about non-space byte on next call.
|
||||
s.error(c, "after top-level value")
|
||||
}
|
||||
return scanEnd
|
||||
}
|
||||
|
||||
// stateInString is the state after reading `"`.
|
||||
func stateInString(s *scanner, c byte) int {
|
||||
if c == '"' {
|
||||
s.step = stateEndValue
|
||||
return scanContinue
|
||||
}
|
||||
if c == '\\' {
|
||||
s.step = stateInStringEsc
|
||||
return scanContinue
|
||||
}
|
||||
if c < 0x20 {
|
||||
return s.error(c, "in string literal")
|
||||
}
|
||||
return scanContinue
|
||||
}
|
||||
|
||||
// stateInStringEsc is the state after reading `"\` during a quoted string.
|
||||
func stateInStringEsc(s *scanner, c byte) int {
|
||||
switch c {
|
||||
case 'b', 'f', 'n', 'r', 't', '\\', '/', '"':
|
||||
s.step = stateInString
|
||||
return scanContinue
|
||||
case 'u':
|
||||
s.step = stateInStringEscU
|
||||
return scanContinue
|
||||
}
|
||||
return s.error(c, "in string escape code")
|
||||
}
|
||||
|
||||
// stateInStringEscU is the state after reading `"\u` during a quoted string.
|
||||
func stateInStringEscU(s *scanner, c byte) int {
|
||||
if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' {
|
||||
s.step = stateInStringEscU1
|
||||
return scanContinue
|
||||
}
|
||||
// numbers
|
||||
return s.error(c, "in \\u hexadecimal character escape")
|
||||
}
|
||||
|
||||
// stateInStringEscU1 is the state after reading `"\u1` during a quoted string.
|
||||
func stateInStringEscU1(s *scanner, c byte) int {
|
||||
if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' {
|
||||
s.step = stateInStringEscU12
|
||||
return scanContinue
|
||||
}
|
||||
// numbers
|
||||
return s.error(c, "in \\u hexadecimal character escape")
|
||||
}
|
||||
|
||||
// stateInStringEscU12 is the state after reading `"\u12` during a quoted string.
|
||||
func stateInStringEscU12(s *scanner, c byte) int {
|
||||
if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' {
|
||||
s.step = stateInStringEscU123
|
||||
return scanContinue
|
||||
}
|
||||
// numbers
|
||||
return s.error(c, "in \\u hexadecimal character escape")
|
||||
}
|
||||
|
||||
// stateInStringEscU123 is the state after reading `"\u123` during a quoted string.
|
||||
func stateInStringEscU123(s *scanner, c byte) int {
|
||||
if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F' {
|
||||
s.step = stateInString
|
||||
return scanContinue
|
||||
}
|
||||
// numbers
|
||||
return s.error(c, "in \\u hexadecimal character escape")
|
||||
}
|
||||
|
||||
// stateNeg is the state after reading `-` during a number.
|
||||
func stateNeg(s *scanner, c byte) int {
|
||||
if c == '0' {
|
||||
s.step = state0
|
||||
return scanContinue
|
||||
}
|
||||
if '1' <= c && c <= '9' {
|
||||
s.step = state1
|
||||
return scanContinue
|
||||
}
|
||||
return s.error(c, "in numeric literal")
|
||||
}
|
||||
|
||||
// state1 is the state after reading a non-zero integer during a number,
|
||||
// such as after reading `1` or `100` but not `0`.
|
||||
func state1(s *scanner, c byte) int {
|
||||
if '0' <= c && c <= '9' {
|
||||
s.step = state1
|
||||
return scanContinue
|
||||
}
|
||||
return state0(s, c)
|
||||
}
|
||||
|
||||
// state0 is the state after reading `0` during a number.
|
||||
func state0(s *scanner, c byte) int {
|
||||
if c == '.' {
|
||||
s.step = stateDot
|
||||
return scanContinue
|
||||
}
|
||||
if c == 'e' || c == 'E' {
|
||||
s.step = stateE
|
||||
return scanContinue
|
||||
}
|
||||
return stateEndValue(s, c)
|
||||
}
|
||||
|
||||
// stateDot is the state after reading the integer and decimal point in a number,
|
||||
// such as after reading `1.`.
|
||||
func stateDot(s *scanner, c byte) int {
|
||||
if '0' <= c && c <= '9' {
|
||||
s.step = stateDot0
|
||||
return scanContinue
|
||||
}
|
||||
return s.error(c, "after decimal point in numeric literal")
|
||||
}
|
||||
|
||||
// stateDot0 is the state after reading the integer, decimal point, and subsequent
|
||||
// digits of a number, such as after reading `3.14`.
|
||||
func stateDot0(s *scanner, c byte) int {
|
||||
if '0' <= c && c <= '9' {
|
||||
return scanContinue
|
||||
}
|
||||
if c == 'e' || c == 'E' {
|
||||
s.step = stateE
|
||||
return scanContinue
|
||||
}
|
||||
return stateEndValue(s, c)
|
||||
}
|
||||
|
||||
// stateE is the state after reading the mantissa and e in a number,
|
||||
// such as after reading `314e` or `0.314e`.
|
||||
func stateE(s *scanner, c byte) int {
|
||||
if c == '+' || c == '-' {
|
||||
s.step = stateESign
|
||||
return scanContinue
|
||||
}
|
||||
return stateESign(s, c)
|
||||
}
|
||||
|
||||
// stateESign is the state after reading the mantissa, e, and sign in a number,
|
||||
// such as after reading `314e-` or `0.314e+`.
|
||||
func stateESign(s *scanner, c byte) int {
|
||||
if '0' <= c && c <= '9' {
|
||||
s.step = stateE0
|
||||
return scanContinue
|
||||
}
|
||||
return s.error(c, "in exponent of numeric literal")
|
||||
}
|
||||
|
||||
// stateE0 is the state after reading the mantissa, e, optional sign,
|
||||
// and at least one digit of the exponent in a number,
|
||||
// such as after reading `314e-2` or `0.314e+1` or `3.14e0`.
|
||||
func stateE0(s *scanner, c byte) int {
|
||||
if '0' <= c && c <= '9' {
|
||||
return scanContinue
|
||||
}
|
||||
return stateEndValue(s, c)
|
||||
}
|
||||
|
||||
// stateNew0 is the state after reading `n`.
|
||||
func stateNew0(s *scanner, c byte) int {
|
||||
if c == 'e' {
|
||||
s.step = stateNew1
|
||||
return scanContinue
|
||||
}
|
||||
s.step = stateName
|
||||
return stateName(s, c)
|
||||
}
|
||||
|
||||
// stateNew1 is the state after reading `ne`.
|
||||
func stateNew1(s *scanner, c byte) int {
|
||||
if c == 'w' {
|
||||
s.step = stateNew2
|
||||
return scanContinue
|
||||
}
|
||||
s.step = stateName
|
||||
return stateName(s, c)
|
||||
}
|
||||
|
||||
// stateNew2 is the state after reading `new`.
|
||||
func stateNew2(s *scanner, c byte) int {
|
||||
s.step = stateName
|
||||
if c == ' ' {
|
||||
return scanContinue
|
||||
}
|
||||
return stateName(s, c)
|
||||
}
|
||||
|
||||
// stateName is the state while reading an unquoted function name.
|
||||
func stateName(s *scanner, c byte) int {
|
||||
if isName(c) {
|
||||
return scanContinue
|
||||
}
|
||||
if c == '(' {
|
||||
s.step = stateParamOrEmpty
|
||||
s.pushParseState(parseParam)
|
||||
return scanParam
|
||||
}
|
||||
return stateEndValue(s, c)
|
||||
}
|
||||
|
||||
// stateParamOrEmpty is the state after reading `(`.
|
||||
func stateParamOrEmpty(s *scanner, c byte) int {
|
||||
if c <= ' ' && isSpace(c) {
|
||||
return scanSkipSpace
|
||||
}
|
||||
if c == ')' {
|
||||
return stateEndValue(s, c)
|
||||
}
|
||||
return stateBeginValue(s, c)
|
||||
}
|
||||
|
||||
// stateT is the state after reading `t`.
|
||||
func stateT(s *scanner, c byte) int {
|
||||
if c == 'r' {
|
||||
s.step = stateTr
|
||||
return scanContinue
|
||||
}
|
||||
return s.error(c, "in literal true (expecting 'r')")
|
||||
}
|
||||
|
||||
// stateTr is the state after reading `tr`.
|
||||
func stateTr(s *scanner, c byte) int {
|
||||
if c == 'u' {
|
||||
s.step = stateTru
|
||||
return scanContinue
|
||||
}
|
||||
return s.error(c, "in literal true (expecting 'u')")
|
||||
}
|
||||
|
||||
// stateTru is the state after reading `tru`.
|
||||
func stateTru(s *scanner, c byte) int {
|
||||
if c == 'e' {
|
||||
s.step = stateEndValue
|
||||
return scanContinue
|
||||
}
|
||||
return s.error(c, "in literal true (expecting 'e')")
|
||||
}
|
||||
|
||||
// stateF is the state after reading `f`.
|
||||
func stateF(s *scanner, c byte) int {
|
||||
if c == 'a' {
|
||||
s.step = stateFa
|
||||
return scanContinue
|
||||
}
|
||||
return s.error(c, "in literal false (expecting 'a')")
|
||||
}
|
||||
|
||||
// stateFa is the state after reading `fa`.
|
||||
func stateFa(s *scanner, c byte) int {
|
||||
if c == 'l' {
|
||||
s.step = stateFal
|
||||
return scanContinue
|
||||
}
|
||||
return s.error(c, "in literal false (expecting 'l')")
|
||||
}
|
||||
|
||||
// stateFal is the state after reading `fal`.
|
||||
func stateFal(s *scanner, c byte) int {
|
||||
if c == 's' {
|
||||
s.step = stateFals
|
||||
return scanContinue
|
||||
}
|
||||
return s.error(c, "in literal false (expecting 's')")
|
||||
}
|
||||
|
||||
// stateFals is the state after reading `fals`.
|
||||
func stateFals(s *scanner, c byte) int {
|
||||
if c == 'e' {
|
||||
s.step = stateEndValue
|
||||
return scanContinue
|
||||
}
|
||||
return s.error(c, "in literal false (expecting 'e')")
|
||||
}
|
||||
|
||||
// stateN is the state after reading `n`.
|
||||
func stateN(s *scanner, c byte) int {
|
||||
if c == 'u' {
|
||||
s.step = stateNu
|
||||
return scanContinue
|
||||
}
|
||||
return s.error(c, "in literal null (expecting 'u')")
|
||||
}
|
||||
|
||||
// stateNu is the state after reading `nu`.
|
||||
func stateNu(s *scanner, c byte) int {
|
||||
if c == 'l' {
|
||||
s.step = stateNul
|
||||
return scanContinue
|
||||
}
|
||||
return s.error(c, "in literal null (expecting 'l')")
|
||||
}
|
||||
|
||||
// stateNul is the state after reading `nul`.
|
||||
func stateNul(s *scanner, c byte) int {
|
||||
if c == 'l' {
|
||||
s.step = stateEndValue
|
||||
return scanContinue
|
||||
}
|
||||
return s.error(c, "in literal null (expecting 'l')")
|
||||
}
|
||||
|
||||
// stateError is the state after reaching a syntax error,
|
||||
// such as after reading `[1}` or `5.1.2`.
|
||||
func stateError(s *scanner, c byte) int {
|
||||
return scanError
|
||||
}
|
||||
|
||||
// error records an error and switches to the error state.
|
||||
func (s *scanner) error(c byte, context string) int {
|
||||
s.step = stateError
|
||||
s.err = &SyntaxError{"invalid character " + quoteChar(c) + " " + context, s.bytes}
|
||||
return scanError
|
||||
}
|
||||
|
||||
// quoteChar formats c as a quoted character literal
|
||||
func quoteChar(c byte) string {
|
||||
// special cases - different from quoted strings
|
||||
if c == '\'' {
|
||||
return `'\''`
|
||||
}
|
||||
if c == '"' {
|
||||
return `'"'`
|
||||
}
|
||||
|
||||
// use quoted string with different quotation marks
|
||||
s := strconv.Quote(string(c))
|
||||
return "'" + s[1:len(s)-1] + "'"
|
||||
}
|
||||
|
||||
// undo causes the scanner to return scanCode from the next state transition.
|
||||
// This gives callers a simple 1-byte undo mechanism.
|
||||
func (s *scanner) undo(scanCode int) {
|
||||
if s.redo {
|
||||
panic("json: invalid use of scanner")
|
||||
}
|
||||
s.redoCode = scanCode
|
||||
s.redoState = s.step
|
||||
s.step = stateRedo
|
||||
s.redo = true
|
||||
}
|
||||
|
||||
// stateRedo helps implement the scanner's 1-byte undo.
|
||||
func stateRedo(s *scanner, c byte) int {
|
||||
s.redo = false
|
||||
s.step = s.redoState
|
||||
return s.redoCode
|
||||
}
|
||||
510
vendor/github.com/globalsign/mgo/internal/json/stream.go
generated
vendored
Normal file
510
vendor/github.com/globalsign/mgo/internal/json/stream.go
generated
vendored
Normal file
@@ -0,0 +1,510 @@
|
||||
// Copyright 2010 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package json
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"io"
|
||||
)
|
||||
|
||||
// A Decoder reads and decodes JSON values from an input stream.
|
||||
type Decoder struct {
|
||||
r io.Reader
|
||||
buf []byte
|
||||
d decodeState
|
||||
scanp int // start of unread data in buf
|
||||
scan scanner
|
||||
err error
|
||||
|
||||
tokenState int
|
||||
tokenStack []int
|
||||
}
|
||||
|
||||
// NewDecoder returns a new decoder that reads from r.
|
||||
//
|
||||
// The decoder introduces its own buffering and may
|
||||
// read data from r beyond the JSON values requested.
|
||||
func NewDecoder(r io.Reader) *Decoder {
|
||||
return &Decoder{r: r}
|
||||
}
|
||||
|
||||
// UseNumber causes the Decoder to unmarshal a number into an interface{} as a
|
||||
// Number instead of as a float64.
|
||||
func (dec *Decoder) UseNumber() { dec.d.useNumber = true }
|
||||
|
||||
// Decode reads the next JSON-encoded value from its
|
||||
// input and stores it in the value pointed to by v.
|
||||
//
|
||||
// See the documentation for Unmarshal for details about
|
||||
// the conversion of JSON into a Go value.
|
||||
func (dec *Decoder) Decode(v interface{}) error {
|
||||
if dec.err != nil {
|
||||
return dec.err
|
||||
}
|
||||
|
||||
if err := dec.tokenPrepareForDecode(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !dec.tokenValueAllowed() {
|
||||
return &SyntaxError{msg: "not at beginning of value"}
|
||||
}
|
||||
|
||||
// Read whole value into buffer.
|
||||
n, err := dec.readValue()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dec.d.init(dec.buf[dec.scanp : dec.scanp+n])
|
||||
dec.scanp += n
|
||||
|
||||
// Don't save err from unmarshal into dec.err:
|
||||
// the connection is still usable since we read a complete JSON
|
||||
// object from it before the error happened.
|
||||
err = dec.d.unmarshal(v)
|
||||
|
||||
// fixup token streaming state
|
||||
dec.tokenValueEnd()
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// Buffered returns a reader of the data remaining in the Decoder's
|
||||
// buffer. The reader is valid until the next call to Decode.
|
||||
func (dec *Decoder) Buffered() io.Reader {
|
||||
return bytes.NewReader(dec.buf[dec.scanp:])
|
||||
}
|
||||
|
||||
// readValue reads a JSON value into dec.buf.
|
||||
// It returns the length of the encoding.
|
||||
func (dec *Decoder) readValue() (int, error) {
|
||||
dec.scan.reset()
|
||||
|
||||
scanp := dec.scanp
|
||||
var err error
|
||||
Input:
|
||||
for {
|
||||
// Look in the buffer for a new value.
|
||||
for i, c := range dec.buf[scanp:] {
|
||||
dec.scan.bytes++
|
||||
v := dec.scan.step(&dec.scan, c)
|
||||
if v == scanEnd {
|
||||
scanp += i
|
||||
break Input
|
||||
}
|
||||
// scanEnd is delayed one byte.
|
||||
// We might block trying to get that byte from src,
|
||||
// so instead invent a space byte.
|
||||
if (v == scanEndObject || v == scanEndArray) && dec.scan.step(&dec.scan, ' ') == scanEnd {
|
||||
scanp += i + 1
|
||||
break Input
|
||||
}
|
||||
if v == scanError {
|
||||
dec.err = dec.scan.err
|
||||
return 0, dec.scan.err
|
||||
}
|
||||
}
|
||||
scanp = len(dec.buf)
|
||||
|
||||
// Did the last read have an error?
|
||||
// Delayed until now to allow buffer scan.
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
if dec.scan.step(&dec.scan, ' ') == scanEnd {
|
||||
break Input
|
||||
}
|
||||
if nonSpace(dec.buf) {
|
||||
err = io.ErrUnexpectedEOF
|
||||
}
|
||||
}
|
||||
dec.err = err
|
||||
return 0, err
|
||||
}
|
||||
|
||||
n := scanp - dec.scanp
|
||||
err = dec.refill()
|
||||
scanp = dec.scanp + n
|
||||
}
|
||||
return scanp - dec.scanp, nil
|
||||
}
|
||||
|
||||
func (dec *Decoder) refill() error {
|
||||
// Make room to read more into the buffer.
|
||||
// First slide down data already consumed.
|
||||
if dec.scanp > 0 {
|
||||
n := copy(dec.buf, dec.buf[dec.scanp:])
|
||||
dec.buf = dec.buf[:n]
|
||||
dec.scanp = 0
|
||||
}
|
||||
|
||||
// Grow buffer if not large enough.
|
||||
const minRead = 512
|
||||
if cap(dec.buf)-len(dec.buf) < minRead {
|
||||
newBuf := make([]byte, len(dec.buf), 2*cap(dec.buf)+minRead)
|
||||
copy(newBuf, dec.buf)
|
||||
dec.buf = newBuf
|
||||
}
|
||||
|
||||
// Read. Delay error for next iteration (after scan).
|
||||
n, err := dec.r.Read(dec.buf[len(dec.buf):cap(dec.buf)])
|
||||
dec.buf = dec.buf[0 : len(dec.buf)+n]
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func nonSpace(b []byte) bool {
|
||||
for _, c := range b {
|
||||
if !isSpace(c) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// An Encoder writes JSON values to an output stream.
|
||||
type Encoder struct {
|
||||
w io.Writer
|
||||
err error
|
||||
escapeHTML bool
|
||||
|
||||
indentBuf *bytes.Buffer
|
||||
indentPrefix string
|
||||
indentValue string
|
||||
|
||||
ext Extension
|
||||
}
|
||||
|
||||
// NewEncoder returns a new encoder that writes to w.
|
||||
func NewEncoder(w io.Writer) *Encoder {
|
||||
return &Encoder{w: w, escapeHTML: true}
|
||||
}
|
||||
|
||||
// Encode writes the JSON encoding of v to the stream,
|
||||
// followed by a newline character.
|
||||
//
|
||||
// See the documentation for Marshal for details about the
|
||||
// conversion of Go values to JSON.
|
||||
func (enc *Encoder) Encode(v interface{}) error {
|
||||
if enc.err != nil {
|
||||
return enc.err
|
||||
}
|
||||
e := newEncodeState()
|
||||
e.ext = enc.ext
|
||||
err := e.marshal(v, encOpts{escapeHTML: enc.escapeHTML})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Terminate each value with a newline.
|
||||
// This makes the output look a little nicer
|
||||
// when debugging, and some kind of space
|
||||
// is required if the encoded value was a number,
|
||||
// so that the reader knows there aren't more
|
||||
// digits coming.
|
||||
e.WriteByte('\n')
|
||||
|
||||
b := e.Bytes()
|
||||
if enc.indentBuf != nil {
|
||||
enc.indentBuf.Reset()
|
||||
err = Indent(enc.indentBuf, b, enc.indentPrefix, enc.indentValue)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
b = enc.indentBuf.Bytes()
|
||||
}
|
||||
if _, err = enc.w.Write(b); err != nil {
|
||||
enc.err = err
|
||||
}
|
||||
encodeStatePool.Put(e)
|
||||
return err
|
||||
}
|
||||
|
||||
// Indent sets the encoder to format each encoded value with Indent.
|
||||
func (enc *Encoder) Indent(prefix, indent string) {
|
||||
enc.indentBuf = new(bytes.Buffer)
|
||||
enc.indentPrefix = prefix
|
||||
enc.indentValue = indent
|
||||
}
|
||||
|
||||
// DisableHTMLEscaping causes the encoder not to escape angle brackets
|
||||
// ("<" and ">") or ampersands ("&") in JSON strings.
|
||||
func (enc *Encoder) DisableHTMLEscaping() {
|
||||
enc.escapeHTML = false
|
||||
}
|
||||
|
||||
// RawMessage is a raw encoded JSON value.
|
||||
// It implements Marshaler and Unmarshaler and can
|
||||
// be used to delay JSON decoding or precompute a JSON encoding.
|
||||
type RawMessage []byte
|
||||
|
||||
// MarshalJSON returns *m as the JSON encoding of m.
|
||||
func (m *RawMessage) MarshalJSON() ([]byte, error) {
|
||||
return *m, nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets *m to a copy of data.
|
||||
func (m *RawMessage) UnmarshalJSON(data []byte) error {
|
||||
if m == nil {
|
||||
return errors.New("json.RawMessage: UnmarshalJSON on nil pointer")
|
||||
}
|
||||
*m = append((*m)[0:0], data...)
|
||||
return nil
|
||||
}
|
||||
|
||||
var _ Marshaler = (*RawMessage)(nil)
|
||||
var _ Unmarshaler = (*RawMessage)(nil)
|
||||
|
||||
// A Token holds a value of one of these types:
|
||||
//
|
||||
// Delim, for the four JSON delimiters [ ] { }
|
||||
// bool, for JSON booleans
|
||||
// float64, for JSON numbers
|
||||
// Number, for JSON numbers
|
||||
// string, for JSON string literals
|
||||
// nil, for JSON null
|
||||
//
|
||||
type Token interface{}
|
||||
|
||||
const (
|
||||
tokenTopValue = iota
|
||||
tokenArrayStart
|
||||
tokenArrayValue
|
||||
tokenArrayComma
|
||||
tokenObjectStart
|
||||
tokenObjectKey
|
||||
tokenObjectColon
|
||||
tokenObjectValue
|
||||
tokenObjectComma
|
||||
)
|
||||
|
||||
// advance tokenstate from a separator state to a value state
|
||||
func (dec *Decoder) tokenPrepareForDecode() error {
|
||||
// Note: Not calling peek before switch, to avoid
|
||||
// putting peek into the standard Decode path.
|
||||
// peek is only called when using the Token API.
|
||||
switch dec.tokenState {
|
||||
case tokenArrayComma:
|
||||
c, err := dec.peek()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if c != ',' {
|
||||
return &SyntaxError{"expected comma after array element", 0}
|
||||
}
|
||||
dec.scanp++
|
||||
dec.tokenState = tokenArrayValue
|
||||
case tokenObjectColon:
|
||||
c, err := dec.peek()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if c != ':' {
|
||||
return &SyntaxError{"expected colon after object key", 0}
|
||||
}
|
||||
dec.scanp++
|
||||
dec.tokenState = tokenObjectValue
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dec *Decoder) tokenValueAllowed() bool {
|
||||
switch dec.tokenState {
|
||||
case tokenTopValue, tokenArrayStart, tokenArrayValue, tokenObjectValue:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (dec *Decoder) tokenValueEnd() {
|
||||
switch dec.tokenState {
|
||||
case tokenArrayStart, tokenArrayValue:
|
||||
dec.tokenState = tokenArrayComma
|
||||
case tokenObjectValue:
|
||||
dec.tokenState = tokenObjectComma
|
||||
}
|
||||
}
|
||||
|
||||
// A Delim is a JSON array or object delimiter, one of [ ] { or }.
|
||||
type Delim rune
|
||||
|
||||
func (d Delim) String() string {
|
||||
return string(d)
|
||||
}
|
||||
|
||||
// Token returns the next JSON token in the input stream.
|
||||
// At the end of the input stream, Token returns nil, io.EOF.
|
||||
//
|
||||
// Token guarantees that the delimiters [ ] { } it returns are
|
||||
// properly nested and matched: if Token encounters an unexpected
|
||||
// delimiter in the input, it will return an error.
|
||||
//
|
||||
// The input stream consists of basic JSON values—bool, string,
|
||||
// number, and null—along with delimiters [ ] { } of type Delim
|
||||
// to mark the start and end of arrays and objects.
|
||||
// Commas and colons are elided.
|
||||
func (dec *Decoder) Token() (Token, error) {
|
||||
for {
|
||||
c, err := dec.peek()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch c {
|
||||
case '[':
|
||||
if !dec.tokenValueAllowed() {
|
||||
return dec.tokenError(c)
|
||||
}
|
||||
dec.scanp++
|
||||
dec.tokenStack = append(dec.tokenStack, dec.tokenState)
|
||||
dec.tokenState = tokenArrayStart
|
||||
return Delim('['), nil
|
||||
|
||||
case ']':
|
||||
if dec.tokenState != tokenArrayStart && dec.tokenState != tokenArrayComma {
|
||||
return dec.tokenError(c)
|
||||
}
|
||||
dec.scanp++
|
||||
dec.tokenState = dec.tokenStack[len(dec.tokenStack)-1]
|
||||
dec.tokenStack = dec.tokenStack[:len(dec.tokenStack)-1]
|
||||
dec.tokenValueEnd()
|
||||
return Delim(']'), nil
|
||||
|
||||
case '{':
|
||||
if !dec.tokenValueAllowed() {
|
||||
return dec.tokenError(c)
|
||||
}
|
||||
dec.scanp++
|
||||
dec.tokenStack = append(dec.tokenStack, dec.tokenState)
|
||||
dec.tokenState = tokenObjectStart
|
||||
return Delim('{'), nil
|
||||
|
||||
case '}':
|
||||
if dec.tokenState != tokenObjectStart && dec.tokenState != tokenObjectComma {
|
||||
return dec.tokenError(c)
|
||||
}
|
||||
dec.scanp++
|
||||
dec.tokenState = dec.tokenStack[len(dec.tokenStack)-1]
|
||||
dec.tokenStack = dec.tokenStack[:len(dec.tokenStack)-1]
|
||||
dec.tokenValueEnd()
|
||||
return Delim('}'), nil
|
||||
|
||||
case ':':
|
||||
if dec.tokenState != tokenObjectColon {
|
||||
return dec.tokenError(c)
|
||||
}
|
||||
dec.scanp++
|
||||
dec.tokenState = tokenObjectValue
|
||||
continue
|
||||
|
||||
case ',':
|
||||
if dec.tokenState == tokenArrayComma {
|
||||
dec.scanp++
|
||||
dec.tokenState = tokenArrayValue
|
||||
continue
|
||||
}
|
||||
if dec.tokenState == tokenObjectComma {
|
||||
dec.scanp++
|
||||
dec.tokenState = tokenObjectKey
|
||||
continue
|
||||
}
|
||||
return dec.tokenError(c)
|
||||
|
||||
case '"':
|
||||
if dec.tokenState == tokenObjectStart || dec.tokenState == tokenObjectKey {
|
||||
var x string
|
||||
old := dec.tokenState
|
||||
dec.tokenState = tokenTopValue
|
||||
err := dec.Decode(&x)
|
||||
dec.tokenState = old
|
||||
if err != nil {
|
||||
clearOffset(err)
|
||||
return nil, err
|
||||
}
|
||||
dec.tokenState = tokenObjectColon
|
||||
return x, nil
|
||||
}
|
||||
fallthrough
|
||||
|
||||
default:
|
||||
if !dec.tokenValueAllowed() {
|
||||
return dec.tokenError(c)
|
||||
}
|
||||
var x interface{}
|
||||
if err := dec.Decode(&x); err != nil {
|
||||
clearOffset(err)
|
||||
return nil, err
|
||||
}
|
||||
return x, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func clearOffset(err error) {
|
||||
if s, ok := err.(*SyntaxError); ok {
|
||||
s.Offset = 0
|
||||
}
|
||||
}
|
||||
|
||||
func (dec *Decoder) tokenError(c byte) (Token, error) {
|
||||
var context string
|
||||
switch dec.tokenState {
|
||||
case tokenTopValue:
|
||||
context = " looking for beginning of value"
|
||||
case tokenArrayStart, tokenArrayValue, tokenObjectValue:
|
||||
context = " looking for beginning of value"
|
||||
case tokenArrayComma:
|
||||
context = " after array element"
|
||||
case tokenObjectKey:
|
||||
context = " looking for beginning of object key string"
|
||||
case tokenObjectColon:
|
||||
context = " after object key"
|
||||
case tokenObjectComma:
|
||||
context = " after object key:value pair"
|
||||
}
|
||||
return nil, &SyntaxError{"invalid character " + quoteChar(c) + " " + context, 0}
|
||||
}
|
||||
|
||||
// More reports whether there is another element in the
|
||||
// current array or object being parsed.
|
||||
func (dec *Decoder) More() bool {
|
||||
c, err := dec.peek()
|
||||
return err == nil && c != ']' && c != '}'
|
||||
}
|
||||
|
||||
func (dec *Decoder) peek() (byte, error) {
|
||||
var err error
|
||||
for {
|
||||
for i := dec.scanp; i < len(dec.buf); i++ {
|
||||
c := dec.buf[i]
|
||||
if isSpace(c) {
|
||||
continue
|
||||
}
|
||||
dec.scanp = i
|
||||
return c, nil
|
||||
}
|
||||
// buffer has been scanned, now report any error
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
err = dec.refill()
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
TODO
|
||||
|
||||
// EncodeToken writes the given JSON token to the stream.
|
||||
// It returns an error if the delimiters [ ] { } are not properly used.
|
||||
//
|
||||
// EncodeToken does not call Flush, because usually it is part of
|
||||
// a larger operation such as Encode, and those will call Flush when finished.
|
||||
// Callers that create an Encoder and then invoke EncodeToken directly,
|
||||
// without using Encode, need to call Flush when finished to ensure that
|
||||
// the JSON is written to the underlying writer.
|
||||
func (e *Encoder) EncodeToken(t Token) error {
|
||||
...
|
||||
}
|
||||
|
||||
*/
|
||||
44
vendor/github.com/globalsign/mgo/internal/json/tags.go
generated
vendored
Normal file
44
vendor/github.com/globalsign/mgo/internal/json/tags.go
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package json
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// tagOptions is the string following a comma in a struct field's "json"
|
||||
// tag, or the empty string. It does not include the leading comma.
|
||||
type tagOptions string
|
||||
|
||||
// parseTag splits a struct field's json tag into its name and
|
||||
// comma-separated options.
|
||||
func parseTag(tag string) (string, tagOptions) {
|
||||
if idx := strings.Index(tag, ","); idx != -1 {
|
||||
return tag[:idx], tagOptions(tag[idx+1:])
|
||||
}
|
||||
return tag, tagOptions("")
|
||||
}
|
||||
|
||||
// Contains reports whether a comma-separated list of options
|
||||
// contains a particular substr flag. substr must be surrounded by a
|
||||
// string boundary or commas.
|
||||
func (o tagOptions) Contains(optionName string) bool {
|
||||
if len(o) == 0 {
|
||||
return false
|
||||
}
|
||||
s := string(o)
|
||||
for s != "" {
|
||||
var next string
|
||||
i := strings.Index(s, ",")
|
||||
if i >= 0 {
|
||||
s, next = s[:i], s[i+1:]
|
||||
}
|
||||
if s == optionName {
|
||||
return true
|
||||
}
|
||||
s = next
|
||||
}
|
||||
return false
|
||||
}
|
||||
2
vendor/github.com/go-openapi/errors/.gitignore
generated
vendored
Normal file
2
vendor/github.com/go-openapi/errors/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
secrets.yml
|
||||
coverage.out
|
||||
14
vendor/github.com/go-openapi/errors/.travis.yml
generated
vendored
Normal file
14
vendor/github.com/go-openapi/errors/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
after_success:
|
||||
- bash <(curl -s https://codecov.io/bash)
|
||||
go:
|
||||
- '1.9'
|
||||
- 1.10.x
|
||||
- 1.11.x
|
||||
install:
|
||||
- go get -u github.com/stretchr/testify/assert
|
||||
language: go
|
||||
notifications:
|
||||
slack:
|
||||
secure: gZGp9NaHxi7zawlXJXKY92BGeDR1x0tbIcTyU5nMKLq0fhIaiEBJEeALwZ4VgqsSv3DytSSF5mLH8fevAM3ixE6hxjKQ+lQuf7V/w3btCN1CSWgoua5LOh1kTnqZQtJuRvO4pzoJcT3bJWBsVZ07VGNVzzJEy/zAKCHFqBUCXShw7QemlLBcYWFNqveTlvDIfCzvouoLnPoXwxEpkjxe9uz/ZKZgAnup/fXjC8RFctmgCnkCyvJTk0Y/fZCsufixJrJhshBWTnlrFCzRmgNkz2d+i1Ls3+MJ5EJJ2Tx/A5S63dL49J1f9Kr0AKHADmulSy8JNzIckKwbyFMYUecrsW+Lsu9DhnVMy1jj5pKsJDLRi2iIU3fXTMWbcyQbXjbbnBO2mPdP3Tzme75y4D9fc8hUPeyqVv2BU26NEbQ7EF2pKJ93OXvci7HlwRBgdJa8j6mP2LEDClcPQW00g7N/OZe0cTOMa8L5AwiBlbArwqt9wv6YLJoTG0wpDhzWsFvbCg5bJxe28Yn3fIDD0Lk1I7iSnBbp/5gzF19jmxqvcT8tHRkDL4xfjbENFTZjA5uB4Z4pj4WSyWQILLV/Jwhe3fi9uQwdviFHfj5pnVrmNUiGSOQL672K5wl2c3E9mGwejvsu2dfEz28n7Y/FUnOpY3/cBS0n27JJaerS0zMKNLE=
|
||||
script:
|
||||
- go test -v -race -cover -coverprofile=coverage.txt -covermode=atomic ./...
|
||||
74
vendor/github.com/go-openapi/errors/CODE_OF_CONDUCT.md
generated
vendored
Normal file
74
vendor/github.com/go-openapi/errors/CODE_OF_CONDUCT.md
generated
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as
|
||||
contributors and maintainers pledge to making participation in our project and
|
||||
our community a harassment-free experience for everyone, regardless of age, body
|
||||
size, disability, ethnicity, gender identity and expression, level of experience,
|
||||
nationality, personal appearance, race, religion, or sexual identity and
|
||||
orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment
|
||||
include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||
advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic
|
||||
address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable
|
||||
behavior and are expected to take appropriate and fair corrective action in
|
||||
response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or
|
||||
reject comments, commits, code, wiki edits, issues, and other contributions
|
||||
that are not aligned to this Code of Conduct, or to ban temporarily or
|
||||
permanently any contributor for other behaviors that they deem inappropriate,
|
||||
threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces
|
||||
when an individual is representing the project or its community. Examples of
|
||||
representing a project or community include using an official project e-mail
|
||||
address, posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event. Representation of a project may be
|
||||
further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported by contacting the project team at ivan+abuse@flanders.co.nz. All
|
||||
complaints will be reviewed and investigated and will result in a response that
|
||||
is deemed necessary and appropriate to the circumstances. The project team is
|
||||
obligated to maintain confidentiality with regard to the reporter of an incident.
|
||||
Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good
|
||||
faith may face temporary or permanent repercussions as determined by other
|
||||
members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
||||
available at [http://contributor-covenant.org/version/1/4][version]
|
||||
|
||||
[homepage]: http://contributor-covenant.org
|
||||
[version]: http://contributor-covenant.org/version/1/4/
|
||||
202
vendor/github.com/go-openapi/errors/LICENSE
generated
vendored
Normal file
202
vendor/github.com/go-openapi/errors/LICENSE
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.
|
||||
8
vendor/github.com/go-openapi/errors/README.md
generated
vendored
Normal file
8
vendor/github.com/go-openapi/errors/README.md
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
# OpenAPI errors [](https://travis-ci.org/go-openapi/errors) [](https://codecov.io/gh/go-openapi/errors) [](https://slackin.goswagger.io)
|
||||
|
||||
[](https://raw.githubusercontent.com/go-openapi/errors/master/LICENSE)
|
||||
[](http://godoc.org/github.com/go-openapi/errors)
|
||||
[](https://golangci.com)
|
||||
[](https://goreportcard.com/report/github.com/go-openapi/errors)
|
||||
|
||||
Shared errors and error interface used throughout the various libraries found in the go-openapi toolkit.
|
||||
166
vendor/github.com/go-openapi/errors/api.go
generated
vendored
Normal file
166
vendor/github.com/go-openapi/errors/api.go
generated
vendored
Normal file
@@ -0,0 +1,166 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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 errors
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// DefaultHTTPCode is used when the error Code cannot be used as an HTTP code.
|
||||
var DefaultHTTPCode = 422
|
||||
|
||||
// Error represents a error interface all swagger framework errors implement
|
||||
type Error interface {
|
||||
error
|
||||
Code() int32
|
||||
}
|
||||
|
||||
type apiError struct {
|
||||
code int32
|
||||
message string
|
||||
}
|
||||
|
||||
func (a *apiError) Error() string {
|
||||
return a.message
|
||||
}
|
||||
|
||||
func (a *apiError) Code() int32 {
|
||||
return a.code
|
||||
}
|
||||
|
||||
// New creates a new API error with a code and a message
|
||||
func New(code int32, message string, args ...interface{}) Error {
|
||||
if len(args) > 0 {
|
||||
return &apiError{code, fmt.Sprintf(message, args...)}
|
||||
}
|
||||
return &apiError{code, message}
|
||||
}
|
||||
|
||||
// NotFound creates a new not found error
|
||||
func NotFound(message string, args ...interface{}) Error {
|
||||
if message == "" {
|
||||
message = "Not found"
|
||||
}
|
||||
return New(http.StatusNotFound, fmt.Sprintf(message, args...))
|
||||
}
|
||||
|
||||
// NotImplemented creates a new not implemented error
|
||||
func NotImplemented(message string) Error {
|
||||
return New(http.StatusNotImplemented, message)
|
||||
}
|
||||
|
||||
// MethodNotAllowedError represents an error for when the path matches but the method doesn't
|
||||
type MethodNotAllowedError struct {
|
||||
code int32
|
||||
Allowed []string
|
||||
message string
|
||||
}
|
||||
|
||||
func (m *MethodNotAllowedError) Error() string {
|
||||
return m.message
|
||||
}
|
||||
|
||||
// Code the error code
|
||||
func (m *MethodNotAllowedError) Code() int32 {
|
||||
return m.code
|
||||
}
|
||||
|
||||
func errorAsJSON(err Error) []byte {
|
||||
b, _ := json.Marshal(struct {
|
||||
Code int32 `json:"code"`
|
||||
Message string `json:"message"`
|
||||
}{err.Code(), err.Error()})
|
||||
return b
|
||||
}
|
||||
|
||||
func flattenComposite(errs *CompositeError) *CompositeError {
|
||||
var res []error
|
||||
for _, er := range errs.Errors {
|
||||
switch e := er.(type) {
|
||||
case *CompositeError:
|
||||
if len(e.Errors) > 0 {
|
||||
flat := flattenComposite(e)
|
||||
if len(flat.Errors) > 0 {
|
||||
res = append(res, flat.Errors...)
|
||||
}
|
||||
}
|
||||
default:
|
||||
if e != nil {
|
||||
res = append(res, e)
|
||||
}
|
||||
}
|
||||
}
|
||||
return CompositeValidationError(res...)
|
||||
}
|
||||
|
||||
// MethodNotAllowed creates a new method not allowed error
|
||||
func MethodNotAllowed(requested string, allow []string) Error {
|
||||
msg := fmt.Sprintf("method %s is not allowed, but [%s] are", requested, strings.Join(allow, ","))
|
||||
return &MethodNotAllowedError{code: http.StatusMethodNotAllowed, Allowed: allow, message: msg}
|
||||
}
|
||||
|
||||
const head = "HEAD"
|
||||
|
||||
// ServeError the error handler interface implementation
|
||||
func ServeError(rw http.ResponseWriter, r *http.Request, err error) {
|
||||
rw.Header().Set("Content-Type", "application/json")
|
||||
switch e := err.(type) {
|
||||
case *CompositeError:
|
||||
er := flattenComposite(e)
|
||||
// strips composite errors to first element only
|
||||
if len(er.Errors) > 0 {
|
||||
ServeError(rw, r, er.Errors[0])
|
||||
} else {
|
||||
// guard against empty CompositeError (invalid construct)
|
||||
ServeError(rw, r, nil)
|
||||
}
|
||||
case *MethodNotAllowedError:
|
||||
rw.Header().Add("Allow", strings.Join(err.(*MethodNotAllowedError).Allowed, ","))
|
||||
rw.WriteHeader(asHTTPCode(int(e.Code())))
|
||||
if r == nil || r.Method != head {
|
||||
rw.Write(errorAsJSON(e))
|
||||
}
|
||||
case Error:
|
||||
value := reflect.ValueOf(e)
|
||||
if value.Kind() == reflect.Ptr && value.IsNil() {
|
||||
rw.WriteHeader(http.StatusInternalServerError)
|
||||
rw.Write(errorAsJSON(New(http.StatusInternalServerError, "Unknown error")))
|
||||
return
|
||||
}
|
||||
rw.WriteHeader(asHTTPCode(int(e.Code())))
|
||||
if r == nil || r.Method != head {
|
||||
rw.Write(errorAsJSON(e))
|
||||
}
|
||||
case nil:
|
||||
rw.WriteHeader(http.StatusInternalServerError)
|
||||
rw.Write(errorAsJSON(New(http.StatusInternalServerError, "Unknown error")))
|
||||
default:
|
||||
rw.WriteHeader(http.StatusInternalServerError)
|
||||
if r == nil || r.Method != head {
|
||||
rw.Write(errorAsJSON(New(http.StatusInternalServerError, err.Error())))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func asHTTPCode(input int) int {
|
||||
if input >= 600 {
|
||||
return DefaultHTTPCode
|
||||
}
|
||||
return input
|
||||
}
|
||||
20
vendor/github.com/go-openapi/errors/auth.go
generated
vendored
Normal file
20
vendor/github.com/go-openapi/errors/auth.go
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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 errors
|
||||
|
||||
// Unauthenticated returns an unauthenticated error
|
||||
func Unauthenticated(scheme string) Error {
|
||||
return New(401, "unauthenticated for %s", scheme)
|
||||
}
|
||||
28
vendor/github.com/go-openapi/errors/doc.go
generated
vendored
Normal file
28
vendor/github.com/go-openapi/errors/doc.go
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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 errors provides an Error interface and several concrete types
|
||||
implementing this interface to manage API errors and JSON-schema validation
|
||||
errors.
|
||||
|
||||
A middleware handler ServeError() is provided to serve the errors types
|
||||
it defines.
|
||||
|
||||
It is used throughout the various go-openapi toolkit libraries
|
||||
(https://github.com/go-openapi).
|
||||
|
||||
*/
|
||||
package errors
|
||||
7
vendor/github.com/go-openapi/errors/go.mod
generated
vendored
Normal file
7
vendor/github.com/go-openapi/errors/go.mod
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
module github.com/go-openapi/errors
|
||||
|
||||
require (
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/stretchr/testify v1.2.2
|
||||
)
|
||||
5
vendor/github.com/go-openapi/errors/go.sum
generated
vendored
Normal file
5
vendor/github.com/go-openapi/errors/go.sum
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
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/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
85
vendor/github.com/go-openapi/errors/headers.go
generated
vendored
Normal file
85
vendor/github.com/go-openapi/errors/headers.go
generated
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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 errors
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// Validation represents a failure of a precondition
|
||||
type Validation struct {
|
||||
code int32
|
||||
Name string
|
||||
In string
|
||||
Value interface{}
|
||||
message string
|
||||
Values []interface{}
|
||||
}
|
||||
|
||||
func (e *Validation) Error() string {
|
||||
return e.message
|
||||
}
|
||||
|
||||
// Code the error code
|
||||
func (e *Validation) Code() int32 {
|
||||
return e.code
|
||||
}
|
||||
|
||||
// ValidateName produces an error message name for an aliased property
|
||||
func (e *Validation) ValidateName(name string) *Validation {
|
||||
if e.Name == "" && name != "" {
|
||||
e.Name = name
|
||||
e.message = name + e.message
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
const (
|
||||
contentTypeFail = `unsupported media type %q, only %v are allowed`
|
||||
responseFormatFail = `unsupported media type requested, only %v are available`
|
||||
)
|
||||
|
||||
// InvalidContentType error for an invalid content type
|
||||
func InvalidContentType(value string, allowed []string) *Validation {
|
||||
var values []interface{}
|
||||
for _, v := range allowed {
|
||||
values = append(values, v)
|
||||
}
|
||||
return &Validation{
|
||||
code: http.StatusUnsupportedMediaType,
|
||||
Name: "Content-Type",
|
||||
In: "header",
|
||||
Value: value,
|
||||
Values: values,
|
||||
message: fmt.Sprintf(contentTypeFail, value, allowed),
|
||||
}
|
||||
}
|
||||
|
||||
// InvalidResponseFormat error for an unacceptable response format request
|
||||
func InvalidResponseFormat(value string, allowed []string) *Validation {
|
||||
var values []interface{}
|
||||
for _, v := range allowed {
|
||||
values = append(values, v)
|
||||
}
|
||||
return &Validation{
|
||||
code: http.StatusNotAcceptable,
|
||||
Name: "Accept",
|
||||
In: "header",
|
||||
Value: value,
|
||||
Values: values,
|
||||
message: fmt.Sprintf(responseFormatFail, allowed),
|
||||
}
|
||||
}
|
||||
51
vendor/github.com/go-openapi/errors/middleware.go
generated
vendored
Normal file
51
vendor/github.com/go-openapi/errors/middleware.go
generated
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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 errors
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// APIVerificationFailed is an error that contains all the missing info for a mismatched section
|
||||
// between the api registrations and the api spec
|
||||
type APIVerificationFailed struct {
|
||||
Section string
|
||||
MissingSpecification []string
|
||||
MissingRegistration []string
|
||||
}
|
||||
|
||||
//
|
||||
func (v *APIVerificationFailed) Error() string {
|
||||
buf := bytes.NewBuffer(nil)
|
||||
|
||||
hasRegMissing := len(v.MissingRegistration) > 0
|
||||
hasSpecMissing := len(v.MissingSpecification) > 0
|
||||
|
||||
if hasRegMissing {
|
||||
buf.WriteString(fmt.Sprintf("missing [%s] %s registrations", strings.Join(v.MissingRegistration, ", "), v.Section))
|
||||
}
|
||||
|
||||
if hasRegMissing && hasSpecMissing {
|
||||
buf.WriteString("\n")
|
||||
}
|
||||
|
||||
if hasSpecMissing {
|
||||
buf.WriteString(fmt.Sprintf("missing from spec file [%s] %s", strings.Join(v.MissingSpecification, ", "), v.Section))
|
||||
}
|
||||
|
||||
return buf.String()
|
||||
}
|
||||
59
vendor/github.com/go-openapi/errors/parsing.go
generated
vendored
Normal file
59
vendor/github.com/go-openapi/errors/parsing.go
generated
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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 errors
|
||||
|
||||
import "fmt"
|
||||
|
||||
// ParseError respresents a parsing error
|
||||
type ParseError struct {
|
||||
code int32
|
||||
Name string
|
||||
In string
|
||||
Value string
|
||||
Reason error
|
||||
message string
|
||||
}
|
||||
|
||||
func (e *ParseError) Error() string {
|
||||
return e.message
|
||||
}
|
||||
|
||||
// Code returns the http status code for this error
|
||||
func (e *ParseError) Code() int32 {
|
||||
return e.code
|
||||
}
|
||||
|
||||
const (
|
||||
parseErrorTemplContent = `parsing %s %s from %q failed, because %s`
|
||||
parseErrorTemplContentNoIn = `parsing %s from %q failed, because %s`
|
||||
)
|
||||
|
||||
// NewParseError creates a new parse error
|
||||
func NewParseError(name, in, value string, reason error) *ParseError {
|
||||
var msg string
|
||||
if in == "" {
|
||||
msg = fmt.Sprintf(parseErrorTemplContentNoIn, name, value, reason)
|
||||
} else {
|
||||
msg = fmt.Sprintf(parseErrorTemplContent, name, in, value, reason)
|
||||
}
|
||||
return &ParseError{
|
||||
code: 400,
|
||||
Name: name,
|
||||
In: in,
|
||||
Value: value,
|
||||
Reason: reason,
|
||||
message: msg,
|
||||
}
|
||||
}
|
||||
562
vendor/github.com/go-openapi/errors/schema.go
generated
vendored
Normal file
562
vendor/github.com/go-openapi/errors/schema.go
generated
vendored
Normal file
@@ -0,0 +1,562 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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 errors
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
invalidType = "%s is an invalid type name"
|
||||
typeFail = "%s in %s must be of type %s"
|
||||
typeFailWithData = "%s in %s must be of type %s: %q"
|
||||
typeFailWithError = "%s in %s must be of type %s, because: %s"
|
||||
requiredFail = "%s in %s is required"
|
||||
tooLongMessage = "%s in %s should be at most %d chars long"
|
||||
tooShortMessage = "%s in %s should be at least %d chars long"
|
||||
patternFail = "%s in %s should match '%s'"
|
||||
enumFail = "%s in %s should be one of %v"
|
||||
multipleOfFail = "%s in %s should be a multiple of %v"
|
||||
maxIncFail = "%s in %s should be less than or equal to %v"
|
||||
maxExcFail = "%s in %s should be less than %v"
|
||||
minIncFail = "%s in %s should be greater than or equal to %v"
|
||||
minExcFail = "%s in %s should be greater than %v"
|
||||
uniqueFail = "%s in %s shouldn't contain duplicates"
|
||||
maxItemsFail = "%s in %s should have at most %d items"
|
||||
minItemsFail = "%s in %s should have at least %d items"
|
||||
typeFailNoIn = "%s must be of type %s"
|
||||
typeFailWithDataNoIn = "%s must be of type %s: %q"
|
||||
typeFailWithErrorNoIn = "%s must be of type %s, because: %s"
|
||||
requiredFailNoIn = "%s is required"
|
||||
tooLongMessageNoIn = "%s should be at most %d chars long"
|
||||
tooShortMessageNoIn = "%s should be at least %d chars long"
|
||||
patternFailNoIn = "%s should match '%s'"
|
||||
enumFailNoIn = "%s should be one of %v"
|
||||
multipleOfFailNoIn = "%s should be a multiple of %v"
|
||||
maxIncFailNoIn = "%s should be less than or equal to %v"
|
||||
maxExcFailNoIn = "%s should be less than %v"
|
||||
minIncFailNoIn = "%s should be greater than or equal to %v"
|
||||
minExcFailNoIn = "%s should be greater than %v"
|
||||
uniqueFailNoIn = "%s shouldn't contain duplicates"
|
||||
maxItemsFailNoIn = "%s should have at most %d items"
|
||||
minItemsFailNoIn = "%s should have at least %d items"
|
||||
noAdditionalItems = "%s in %s can't have additional items"
|
||||
noAdditionalItemsNoIn = "%s can't have additional items"
|
||||
tooFewProperties = "%s in %s should have at least %d properties"
|
||||
tooFewPropertiesNoIn = "%s should have at least %d properties"
|
||||
tooManyProperties = "%s in %s should have at most %d properties"
|
||||
tooManyPropertiesNoIn = "%s should have at most %d properties"
|
||||
unallowedProperty = "%s.%s in %s is a forbidden property"
|
||||
unallowedPropertyNoIn = "%s.%s is a forbidden property"
|
||||
failedAllPatternProps = "%s.%s in %s failed all pattern properties"
|
||||
failedAllPatternPropsNoIn = "%s.%s failed all pattern properties"
|
||||
multipleOfMustBePositive = "factor MultipleOf declared for %s must be positive: %v"
|
||||
)
|
||||
|
||||
// All code responses can be used to differentiate errors for different handling
|
||||
// by the consuming program
|
||||
const (
|
||||
// CompositeErrorCode remains 422 for backwards-compatibility
|
||||
// and to separate it from validation errors with cause
|
||||
CompositeErrorCode = 422
|
||||
// InvalidTypeCode is used for any subclass of invalid types
|
||||
InvalidTypeCode = 600 + iota
|
||||
RequiredFailCode
|
||||
TooLongFailCode
|
||||
TooShortFailCode
|
||||
PatternFailCode
|
||||
EnumFailCode
|
||||
MultipleOfFailCode
|
||||
MaxFailCode
|
||||
MinFailCode
|
||||
UniqueFailCode
|
||||
MaxItemsFailCode
|
||||
MinItemsFailCode
|
||||
NoAdditionalItemsCode
|
||||
TooFewPropertiesCode
|
||||
TooManyPropertiesCode
|
||||
UnallowedPropertyCode
|
||||
FailedAllPatternPropsCode
|
||||
MultipleOfMustBePositiveCode
|
||||
)
|
||||
|
||||
// CompositeError is an error that groups several errors together
|
||||
type CompositeError struct {
|
||||
Errors []error
|
||||
code int32
|
||||
message string
|
||||
}
|
||||
|
||||
// Code for this error
|
||||
func (c *CompositeError) Code() int32 {
|
||||
return c.code
|
||||
}
|
||||
|
||||
func (c *CompositeError) Error() string {
|
||||
if len(c.Errors) > 0 {
|
||||
msgs := []string{c.message + ":"}
|
||||
for _, e := range c.Errors {
|
||||
msgs = append(msgs, e.Error())
|
||||
}
|
||||
return strings.Join(msgs, "\n")
|
||||
}
|
||||
return c.message
|
||||
}
|
||||
|
||||
// CompositeValidationError an error to wrap a bunch of other errors
|
||||
func CompositeValidationError(errors ...error) *CompositeError {
|
||||
return &CompositeError{
|
||||
code: CompositeErrorCode,
|
||||
Errors: append([]error{}, errors...),
|
||||
message: "validation failure list",
|
||||
}
|
||||
}
|
||||
|
||||
// FailedAllPatternProperties an error for when the property doesn't match a pattern
|
||||
func FailedAllPatternProperties(name, in, key string) *Validation {
|
||||
msg := fmt.Sprintf(failedAllPatternProps, name, key, in)
|
||||
if in == "" {
|
||||
msg = fmt.Sprintf(failedAllPatternPropsNoIn, name, key)
|
||||
}
|
||||
return &Validation{
|
||||
code: FailedAllPatternPropsCode,
|
||||
Name: name,
|
||||
In: in,
|
||||
Value: key,
|
||||
message: msg,
|
||||
}
|
||||
}
|
||||
|
||||
// PropertyNotAllowed an error for when the property doesn't match a pattern
|
||||
func PropertyNotAllowed(name, in, key string) *Validation {
|
||||
msg := fmt.Sprintf(unallowedProperty, name, key, in)
|
||||
if in == "" {
|
||||
msg = fmt.Sprintf(unallowedPropertyNoIn, name, key)
|
||||
}
|
||||
return &Validation{
|
||||
code: UnallowedPropertyCode,
|
||||
Name: name,
|
||||
In: in,
|
||||
Value: key,
|
||||
message: msg,
|
||||
}
|
||||
}
|
||||
|
||||
// TooFewProperties an error for an object with too few properties
|
||||
func TooFewProperties(name, in string, n int64) *Validation {
|
||||
msg := fmt.Sprintf(tooFewProperties, name, in, n)
|
||||
if in == "" {
|
||||
msg = fmt.Sprintf(tooFewPropertiesNoIn, name, n)
|
||||
}
|
||||
return &Validation{
|
||||
code: TooFewPropertiesCode,
|
||||
Name: name,
|
||||
In: in,
|
||||
Value: n,
|
||||
message: msg,
|
||||
}
|
||||
}
|
||||
|
||||
// TooManyProperties an error for an object with too many properties
|
||||
func TooManyProperties(name, in string, n int64) *Validation {
|
||||
msg := fmt.Sprintf(tooManyProperties, name, in, n)
|
||||
if in == "" {
|
||||
msg = fmt.Sprintf(tooManyPropertiesNoIn, name, n)
|
||||
}
|
||||
return &Validation{
|
||||
code: TooManyPropertiesCode,
|
||||
Name: name,
|
||||
In: in,
|
||||
Value: n,
|
||||
message: msg,
|
||||
}
|
||||
}
|
||||
|
||||
// AdditionalItemsNotAllowed an error for invalid additional items
|
||||
func AdditionalItemsNotAllowed(name, in string) *Validation {
|
||||
msg := fmt.Sprintf(noAdditionalItems, name, in)
|
||||
if in == "" {
|
||||
msg = fmt.Sprintf(noAdditionalItemsNoIn, name)
|
||||
}
|
||||
return &Validation{
|
||||
code: NoAdditionalItemsCode,
|
||||
Name: name,
|
||||
In: in,
|
||||
message: msg,
|
||||
}
|
||||
}
|
||||
|
||||
// InvalidCollectionFormat another flavor of invalid type error
|
||||
func InvalidCollectionFormat(name, in, format string) *Validation {
|
||||
return &Validation{
|
||||
code: InvalidTypeCode,
|
||||
Name: name,
|
||||
In: in,
|
||||
Value: format,
|
||||
message: fmt.Sprintf("the collection format %q is not supported for the %s param %q", format, in, name),
|
||||
}
|
||||
}
|
||||
|
||||
// InvalidTypeName an error for when the type is invalid
|
||||
func InvalidTypeName(typeName string) *Validation {
|
||||
return &Validation{
|
||||
code: InvalidTypeCode,
|
||||
Value: typeName,
|
||||
message: fmt.Sprintf(invalidType, typeName),
|
||||
}
|
||||
}
|
||||
|
||||
// InvalidType creates an error for when the type is invalid
|
||||
func InvalidType(name, in, typeName string, value interface{}) *Validation {
|
||||
var message string
|
||||
|
||||
if in != "" {
|
||||
switch value.(type) {
|
||||
case string:
|
||||
message = fmt.Sprintf(typeFailWithData, name, in, typeName, value)
|
||||
case error:
|
||||
message = fmt.Sprintf(typeFailWithError, name, in, typeName, value)
|
||||
default:
|
||||
message = fmt.Sprintf(typeFail, name, in, typeName)
|
||||
}
|
||||
} else {
|
||||
switch value.(type) {
|
||||
case string:
|
||||
message = fmt.Sprintf(typeFailWithDataNoIn, name, typeName, value)
|
||||
case error:
|
||||
message = fmt.Sprintf(typeFailWithErrorNoIn, name, typeName, value)
|
||||
default:
|
||||
message = fmt.Sprintf(typeFailNoIn, name, typeName)
|
||||
}
|
||||
}
|
||||
|
||||
return &Validation{
|
||||
code: InvalidTypeCode,
|
||||
Name: name,
|
||||
In: in,
|
||||
Value: value,
|
||||
message: message,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// DuplicateItems error for when an array contains duplicates
|
||||
func DuplicateItems(name, in string) *Validation {
|
||||
msg := fmt.Sprintf(uniqueFail, name, in)
|
||||
if in == "" {
|
||||
msg = fmt.Sprintf(uniqueFailNoIn, name)
|
||||
}
|
||||
return &Validation{
|
||||
code: UniqueFailCode,
|
||||
Name: name,
|
||||
In: in,
|
||||
message: msg,
|
||||
}
|
||||
}
|
||||
|
||||
// TooManyItems error for when an array contains too many items
|
||||
func TooManyItems(name, in string, max int64) *Validation {
|
||||
msg := fmt.Sprintf(maxItemsFail, name, in, max)
|
||||
if in == "" {
|
||||
msg = fmt.Sprintf(maxItemsFailNoIn, name, max)
|
||||
}
|
||||
|
||||
return &Validation{
|
||||
code: MaxItemsFailCode,
|
||||
Name: name,
|
||||
In: in,
|
||||
message: msg,
|
||||
}
|
||||
}
|
||||
|
||||
// TooFewItems error for when an array contains too few items
|
||||
func TooFewItems(name, in string, min int64) *Validation {
|
||||
msg := fmt.Sprintf(minItemsFail, name, in, min)
|
||||
if in == "" {
|
||||
msg = fmt.Sprintf(minItemsFailNoIn, name, min)
|
||||
}
|
||||
return &Validation{
|
||||
code: MinItemsFailCode,
|
||||
Name: name,
|
||||
In: in,
|
||||
message: msg,
|
||||
}
|
||||
}
|
||||
|
||||
// ExceedsMaximumInt error for when maxinum validation fails
|
||||
func ExceedsMaximumInt(name, in string, max int64, exclusive bool) *Validation {
|
||||
var message string
|
||||
if in == "" {
|
||||
m := maxIncFailNoIn
|
||||
if exclusive {
|
||||
m = maxExcFailNoIn
|
||||
}
|
||||
message = fmt.Sprintf(m, name, max)
|
||||
} else {
|
||||
m := maxIncFail
|
||||
if exclusive {
|
||||
m = maxExcFail
|
||||
}
|
||||
message = fmt.Sprintf(m, name, in, max)
|
||||
}
|
||||
return &Validation{
|
||||
code: MaxFailCode,
|
||||
Name: name,
|
||||
In: in,
|
||||
Value: max,
|
||||
message: message,
|
||||
}
|
||||
}
|
||||
|
||||
// ExceedsMaximumUint error for when maxinum validation fails
|
||||
func ExceedsMaximumUint(name, in string, max uint64, exclusive bool) *Validation {
|
||||
var message string
|
||||
if in == "" {
|
||||
m := maxIncFailNoIn
|
||||
if exclusive {
|
||||
m = maxExcFailNoIn
|
||||
}
|
||||
message = fmt.Sprintf(m, name, max)
|
||||
} else {
|
||||
m := maxIncFail
|
||||
if exclusive {
|
||||
m = maxExcFail
|
||||
}
|
||||
message = fmt.Sprintf(m, name, in, max)
|
||||
}
|
||||
return &Validation{
|
||||
code: MaxFailCode,
|
||||
Name: name,
|
||||
In: in,
|
||||
Value: max,
|
||||
message: message,
|
||||
}
|
||||
}
|
||||
|
||||
// ExceedsMaximum error for when maxinum validation fails
|
||||
func ExceedsMaximum(name, in string, max float64, exclusive bool) *Validation {
|
||||
var message string
|
||||
if in == "" {
|
||||
m := maxIncFailNoIn
|
||||
if exclusive {
|
||||
m = maxExcFailNoIn
|
||||
}
|
||||
message = fmt.Sprintf(m, name, max)
|
||||
} else {
|
||||
m := maxIncFail
|
||||
if exclusive {
|
||||
m = maxExcFail
|
||||
}
|
||||
message = fmt.Sprintf(m, name, in, max)
|
||||
}
|
||||
return &Validation{
|
||||
code: MaxFailCode,
|
||||
Name: name,
|
||||
In: in,
|
||||
Value: max,
|
||||
message: message,
|
||||
}
|
||||
}
|
||||
|
||||
// ExceedsMinimumInt error for when maxinum validation fails
|
||||
func ExceedsMinimumInt(name, in string, min int64, exclusive bool) *Validation {
|
||||
var message string
|
||||
if in == "" {
|
||||
m := minIncFailNoIn
|
||||
if exclusive {
|
||||
m = minExcFailNoIn
|
||||
}
|
||||
message = fmt.Sprintf(m, name, min)
|
||||
} else {
|
||||
m := minIncFail
|
||||
if exclusive {
|
||||
m = minExcFail
|
||||
}
|
||||
message = fmt.Sprintf(m, name, in, min)
|
||||
}
|
||||
return &Validation{
|
||||
code: MinFailCode,
|
||||
Name: name,
|
||||
In: in,
|
||||
Value: min,
|
||||
message: message,
|
||||
}
|
||||
}
|
||||
|
||||
// ExceedsMinimumUint error for when maxinum validation fails
|
||||
func ExceedsMinimumUint(name, in string, min uint64, exclusive bool) *Validation {
|
||||
var message string
|
||||
if in == "" {
|
||||
m := minIncFailNoIn
|
||||
if exclusive {
|
||||
m = minExcFailNoIn
|
||||
}
|
||||
message = fmt.Sprintf(m, name, min)
|
||||
} else {
|
||||
m := minIncFail
|
||||
if exclusive {
|
||||
m = minExcFail
|
||||
}
|
||||
message = fmt.Sprintf(m, name, in, min)
|
||||
}
|
||||
return &Validation{
|
||||
code: MinFailCode,
|
||||
Name: name,
|
||||
In: in,
|
||||
Value: min,
|
||||
message: message,
|
||||
}
|
||||
}
|
||||
|
||||
// ExceedsMinimum error for when maxinum validation fails
|
||||
func ExceedsMinimum(name, in string, min float64, exclusive bool) *Validation {
|
||||
var message string
|
||||
if in == "" {
|
||||
m := minIncFailNoIn
|
||||
if exclusive {
|
||||
m = minExcFailNoIn
|
||||
}
|
||||
message = fmt.Sprintf(m, name, min)
|
||||
} else {
|
||||
m := minIncFail
|
||||
if exclusive {
|
||||
m = minExcFail
|
||||
}
|
||||
message = fmt.Sprintf(m, name, in, min)
|
||||
}
|
||||
return &Validation{
|
||||
code: MinFailCode,
|
||||
Name: name,
|
||||
In: in,
|
||||
Value: min,
|
||||
message: message,
|
||||
}
|
||||
}
|
||||
|
||||
// NotMultipleOf error for when multiple of validation fails
|
||||
func NotMultipleOf(name, in string, multiple interface{}) *Validation {
|
||||
var msg string
|
||||
if in == "" {
|
||||
msg = fmt.Sprintf(multipleOfFailNoIn, name, multiple)
|
||||
} else {
|
||||
msg = fmt.Sprintf(multipleOfFail, name, in, multiple)
|
||||
}
|
||||
return &Validation{
|
||||
code: MultipleOfFailCode,
|
||||
Name: name,
|
||||
In: in,
|
||||
Value: multiple,
|
||||
message: msg,
|
||||
}
|
||||
}
|
||||
|
||||
// EnumFail error for when an enum validation fails
|
||||
func EnumFail(name, in string, value interface{}, values []interface{}) *Validation {
|
||||
var msg string
|
||||
if in == "" {
|
||||
msg = fmt.Sprintf(enumFailNoIn, name, values)
|
||||
} else {
|
||||
msg = fmt.Sprintf(enumFail, name, in, values)
|
||||
}
|
||||
|
||||
return &Validation{
|
||||
code: EnumFailCode,
|
||||
Name: name,
|
||||
In: in,
|
||||
Value: value,
|
||||
Values: values,
|
||||
message: msg,
|
||||
}
|
||||
}
|
||||
|
||||
// Required error for when a value is missing
|
||||
func Required(name, in string) *Validation {
|
||||
var msg string
|
||||
if in == "" {
|
||||
msg = fmt.Sprintf(requiredFailNoIn, name)
|
||||
} else {
|
||||
msg = fmt.Sprintf(requiredFail, name, in)
|
||||
}
|
||||
return &Validation{
|
||||
code: RequiredFailCode,
|
||||
Name: name,
|
||||
In: in,
|
||||
message: msg,
|
||||
}
|
||||
}
|
||||
|
||||
// TooLong error for when a string is too long
|
||||
func TooLong(name, in string, max int64) *Validation {
|
||||
var msg string
|
||||
if in == "" {
|
||||
msg = fmt.Sprintf(tooLongMessageNoIn, name, max)
|
||||
} else {
|
||||
msg = fmt.Sprintf(tooLongMessage, name, in, max)
|
||||
}
|
||||
return &Validation{
|
||||
code: TooLongFailCode,
|
||||
Name: name,
|
||||
In: in,
|
||||
message: msg,
|
||||
}
|
||||
}
|
||||
|
||||
// TooShort error for when a string is too short
|
||||
func TooShort(name, in string, min int64) *Validation {
|
||||
var msg string
|
||||
if in == "" {
|
||||
msg = fmt.Sprintf(tooShortMessageNoIn, name, min)
|
||||
} else {
|
||||
msg = fmt.Sprintf(tooShortMessage, name, in, min)
|
||||
}
|
||||
|
||||
return &Validation{
|
||||
code: TooShortFailCode,
|
||||
Name: name,
|
||||
In: in,
|
||||
message: msg,
|
||||
}
|
||||
}
|
||||
|
||||
// FailedPattern error for when a string fails a regex pattern match
|
||||
// the pattern that is returned is the ECMA syntax version of the pattern not the golang version.
|
||||
func FailedPattern(name, in, pattern string) *Validation {
|
||||
var msg string
|
||||
if in == "" {
|
||||
msg = fmt.Sprintf(patternFailNoIn, name, pattern)
|
||||
} else {
|
||||
msg = fmt.Sprintf(patternFail, name, in, pattern)
|
||||
}
|
||||
|
||||
return &Validation{
|
||||
code: PatternFailCode,
|
||||
Name: name,
|
||||
In: in,
|
||||
message: msg,
|
||||
}
|
||||
}
|
||||
|
||||
// MultipleOfMustBePositive error for when a
|
||||
// multipleOf factor is negative
|
||||
func MultipleOfMustBePositive(name, in string, factor interface{}) *Validation {
|
||||
return &Validation{
|
||||
code: MultipleOfMustBePositiveCode,
|
||||
Name: name,
|
||||
In: in,
|
||||
Value: factor,
|
||||
message: fmt.Sprintf(multipleOfMustBePositive, name, factor),
|
||||
}
|
||||
}
|
||||
26
vendor/github.com/go-openapi/strfmt/.editorconfig
generated
vendored
Normal file
26
vendor/github.com/go-openapi/strfmt/.editorconfig
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
# top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
# Unix-style newlines with a newline ending every file
|
||||
[*]
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
# Set default charset
|
||||
[*.{js,py,go,scala,rb,java,html,css,less,sass,md}]
|
||||
charset = utf-8
|
||||
|
||||
# Tab indentation (no size specified)
|
||||
[*.go]
|
||||
indent_style = tab
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
# Matches the exact files either package.json or .travis.yml
|
||||
[{package.json,.travis.yml}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
2
vendor/github.com/go-openapi/strfmt/.gitignore
generated
vendored
Normal file
2
vendor/github.com/go-openapi/strfmt/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
secrets.yml
|
||||
coverage.out
|
||||
29
vendor/github.com/go-openapi/strfmt/.golangci.yml
generated
vendored
Normal file
29
vendor/github.com/go-openapi/strfmt/.golangci.yml
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
linters-settings:
|
||||
govet:
|
||||
check-shadowing: true
|
||||
golint:
|
||||
min-confidence: 0
|
||||
gocyclo:
|
||||
min-complexity: 31
|
||||
maligned:
|
||||
suggest-new: true
|
||||
dupl:
|
||||
threshold: 100
|
||||
goconst:
|
||||
min-len: 2
|
||||
min-occurrences: 4
|
||||
|
||||
linters:
|
||||
enable-all: true
|
||||
disable:
|
||||
- maligned
|
||||
- lll
|
||||
- gochecknoinits
|
||||
- gochecknoglobals
|
||||
|
||||
issues:
|
||||
exclude-rules:
|
||||
- path: bson.go
|
||||
text: "should be .*ObjectID"
|
||||
linters:
|
||||
- golint
|
||||
20
vendor/github.com/go-openapi/strfmt/.travis.yml
generated
vendored
Normal file
20
vendor/github.com/go-openapi/strfmt/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
after_success:
|
||||
- bash <(curl -s https://codecov.io/bash)
|
||||
go:
|
||||
- '1.9'
|
||||
- 1.10.x
|
||||
- 1.11.x
|
||||
install:
|
||||
- go get -u github.com/stretchr/testify/assert
|
||||
- go get -u github.com/google/uuid
|
||||
- go get -u github.com/asaskevich/govalidator
|
||||
- go get -u github.com/mailru/easyjson
|
||||
- go get -u github.com/go-openapi/errors
|
||||
- go get -u github.com/mitchellh/mapstructure
|
||||
- go get -u github.com/globalsign/mgo/bson
|
||||
language: go
|
||||
notifications:
|
||||
slack:
|
||||
secure: zE5AtIYTpYfQPnTzP+EaQPN7JKtfFAGv6PrJqoIZLOXa8B6zGb6+J1JRNNxWi7faWbyJOxa4FSSsuPsKZMycUK6wlLFIdhDxwqeo7Ew8r6rdZKdfUHQggfNS9wO79ARoNYUDHtmnaBUS+eWSM1YqSc4i99QxyyfuURLOeAaA/q14YbdlTlaw3lrZ0qT92ot1FnVGNOx064zuHtFeUf+jAVRMZ6Q3rvqllwIlPszE6rmHGXBt2VoJxRaBetdwd7FgkcYw9FPXKHhadwC7/75ZAdmxIukhxNMw4Tr5NuPcqNcnbYLenDP7B3lssGVIrP4BRSqekS1d/tqvdvnnFWHMwrNCkSnSc065G5+qWTlXKAemIclgiXXqE2furBNLm05MDdG8fn5epS0UNarkjD+zX336RiqwBlOX4KbF+vPyqcO98CsN0lnd+H6loc9reiTHs37orFFpQ+309av9be2GGsHUsRB9ssIyrewmhAccOmkRtr2dVTZJNFQwa5Kph5TNJuTjnZEwG/xUkEX2YSfwShOsb062JWiflV6PJdnl80pc9Tn7D5sO5Bf9DbijGRJwwP+YiiJtwtr+vsvS+n4sM0b5eqm4UoRo+JJO8ffoJtHS7ItuyRbVQCwEPJ4221WLcf5PquEEDdAPwR+K4Gj8qTXqTDdxOiES1xFUKVgmzhI=
|
||||
script:
|
||||
- ./hack/coverage
|
||||
74
vendor/github.com/go-openapi/strfmt/CODE_OF_CONDUCT.md
generated
vendored
Normal file
74
vendor/github.com/go-openapi/strfmt/CODE_OF_CONDUCT.md
generated
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as
|
||||
contributors and maintainers pledge to making participation in our project and
|
||||
our community a harassment-free experience for everyone, regardless of age, body
|
||||
size, disability, ethnicity, gender identity and expression, level of experience,
|
||||
nationality, personal appearance, race, religion, or sexual identity and
|
||||
orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment
|
||||
include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||
advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic
|
||||
address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable
|
||||
behavior and are expected to take appropriate and fair corrective action in
|
||||
response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or
|
||||
reject comments, commits, code, wiki edits, issues, and other contributions
|
||||
that are not aligned to this Code of Conduct, or to ban temporarily or
|
||||
permanently any contributor for other behaviors that they deem inappropriate,
|
||||
threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces
|
||||
when an individual is representing the project or its community. Examples of
|
||||
representing a project or community include using an official project e-mail
|
||||
address, posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event. Representation of a project may be
|
||||
further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported by contacting the project team at ivan+abuse@flanders.co.nz. All
|
||||
complaints will be reviewed and investigated and will result in a response that
|
||||
is deemed necessary and appropriate to the circumstances. The project team is
|
||||
obligated to maintain confidentiality with regard to the reporter of an incident.
|
||||
Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good
|
||||
faith may face temporary or permanent repercussions as determined by other
|
||||
members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
||||
available at [http://contributor-covenant.org/version/1/4][version]
|
||||
|
||||
[homepage]: http://contributor-covenant.org
|
||||
[version]: http://contributor-covenant.org/version/1/4/
|
||||
202
vendor/github.com/go-openapi/strfmt/LICENSE
generated
vendored
Normal file
202
vendor/github.com/go-openapi/strfmt/LICENSE
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.
|
||||
73
vendor/github.com/go-openapi/strfmt/README.md
generated
vendored
Normal file
73
vendor/github.com/go-openapi/strfmt/README.md
generated
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
# Strfmt [](https://travis-ci.org/go-openapi/strfmt) [](https://codecov.io/gh/go-openapi/strfmt) [](https://slackin.goswagger.io)
|
||||
|
||||
[](https://raw.githubusercontent.com/go-openapi/strfmt/master/LICENSE)
|
||||
[](http://godoc.org/github.com/go-openapi/strfmt)
|
||||
[](https://golangci.com)
|
||||
[](https://goreportcard.com/report/github.com/go-openapi/strfmt)
|
||||
|
||||
This package exposes a registry of data types to support string formats in the go-openapi toolkit.
|
||||
|
||||
strfmt represents a well known string format such as credit card or email. The go toolkit for OpenAPI specifications knows how to deal with those.
|
||||
|
||||
## Supported data formats
|
||||
go-openapi/strfmt follows the swagger 2.0 specification with the following formats
|
||||
defined [here](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#data-types).
|
||||
|
||||
It also provides convenient extensions to go-openapi users.
|
||||
|
||||
- [x] JSON-schema draft 4 formats
|
||||
- date-time
|
||||
- email
|
||||
- hostname
|
||||
- ipv4
|
||||
- ipv6
|
||||
- uri
|
||||
- [x] swagger 2.0 format extensions
|
||||
- binary
|
||||
- byte (e.g. base64 encoded string)
|
||||
- date (e.g. "1970-01-01")
|
||||
- password
|
||||
- [x] go-openapi custom format extensions
|
||||
- bsonobjectid (BSON objectID)
|
||||
- creditcard
|
||||
- duration (e.g. "3 weeks", "1ms")
|
||||
- hexcolor (e.g. "#FFFFFF")
|
||||
- isbn, isbn10, isbn13
|
||||
- mac (e.g "01:02:03:04:05:06")
|
||||
- rgbcolor (e.g. "rgb(100,100,100)")
|
||||
- ssn
|
||||
- uuid, uuid3, uuid4, uuid5
|
||||
- cidr (e.g. "192.0.2.1/24", "2001:db8:a0b:12f0::1/32")
|
||||
|
||||
> NOTE: as the name stands for, this package is intended to support string formatting only.
|
||||
> It does not provide validation for numerical values with swagger format extension for JSON types "number" or
|
||||
> "integer" (e.g. float, double, int32...).
|
||||
|
||||
## Format types
|
||||
Types defined in strfmt expose marshaling and validation capabilities.
|
||||
|
||||
List of defined types:
|
||||
- Base64
|
||||
- CreditCard
|
||||
- Date
|
||||
- DateTime
|
||||
- Duration
|
||||
- Email
|
||||
- HexColor
|
||||
- Hostname
|
||||
- IPv4
|
||||
- IPv6
|
||||
- CIDR
|
||||
- ISBN
|
||||
- ISBN10
|
||||
- ISBN13
|
||||
- MAC
|
||||
- ObjectId
|
||||
- Password
|
||||
- RGBColor
|
||||
- SSN
|
||||
- URI
|
||||
- UUID
|
||||
- UUID3
|
||||
- UUID4
|
||||
- UUID5
|
||||
142
vendor/github.com/go-openapi/strfmt/bson.go
generated
vendored
Normal file
142
vendor/github.com/go-openapi/strfmt/bson.go
generated
vendored
Normal file
@@ -0,0 +1,142 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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 strfmt
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/globalsign/mgo/bson"
|
||||
"github.com/mailru/easyjson/jlexer"
|
||||
"github.com/mailru/easyjson/jwriter"
|
||||
)
|
||||
|
||||
func init() {
|
||||
var id ObjectId
|
||||
// register this format in the default registry
|
||||
Default.Add("bsonobjectid", &id, IsBSONObjectID)
|
||||
}
|
||||
|
||||
// IsBSONObjectID returns true when the string is a valid BSON.ObjectId
|
||||
func IsBSONObjectID(str string) bool {
|
||||
return bson.IsObjectIdHex(str)
|
||||
}
|
||||
|
||||
// ObjectId represents a BSON object ID (alias to github.com/globalsign/mgo/bson.ObjectId)
|
||||
//
|
||||
// swagger:strfmt bsonobjectid
|
||||
type ObjectId bson.ObjectId
|
||||
|
||||
// NewObjectId creates a ObjectId from a Hex String
|
||||
func NewObjectId(hex string) ObjectId {
|
||||
return ObjectId(bson.ObjectIdHex(hex))
|
||||
}
|
||||
|
||||
// MarshalText turns this instance into text
|
||||
func (id *ObjectId) MarshalText() ([]byte, error) {
|
||||
return []byte(bson.ObjectId(*id).Hex()), nil
|
||||
}
|
||||
|
||||
// UnmarshalText hydrates this instance from text
|
||||
func (id *ObjectId) UnmarshalText(data []byte) error { // validation is performed later on
|
||||
*id = ObjectId(bson.ObjectIdHex(string(data)))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Scan read a value from a database driver
|
||||
func (id *ObjectId) Scan(raw interface{}) error {
|
||||
var data []byte
|
||||
switch v := raw.(type) {
|
||||
case []byte:
|
||||
data = v
|
||||
case string:
|
||||
data = []byte(v)
|
||||
default:
|
||||
return fmt.Errorf("cannot sql.Scan() strfmt.URI from: %#v", v)
|
||||
}
|
||||
|
||||
return id.UnmarshalText(data)
|
||||
}
|
||||
|
||||
// Value converts a value to a database driver value
|
||||
func (id *ObjectId) Value() (driver.Value, error) {
|
||||
return driver.Value(string(*id)), nil
|
||||
}
|
||||
|
||||
func (id *ObjectId) String() string {
|
||||
return string(*id)
|
||||
}
|
||||
|
||||
// MarshalJSON returns the ObjectId as JSON
|
||||
func (id *ObjectId) MarshalJSON() ([]byte, error) {
|
||||
var w jwriter.Writer
|
||||
id.MarshalEasyJSON(&w)
|
||||
return w.BuildBytes()
|
||||
}
|
||||
|
||||
// MarshalEasyJSON writes the ObjectId to a easyjson.Writer
|
||||
func (id *ObjectId) MarshalEasyJSON(w *jwriter.Writer) {
|
||||
w.String(bson.ObjectId(*id).Hex())
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets the ObjectId from JSON
|
||||
func (id *ObjectId) UnmarshalJSON(data []byte) error {
|
||||
l := jlexer.Lexer{Data: data}
|
||||
id.UnmarshalEasyJSON(&l)
|
||||
return l.Error()
|
||||
}
|
||||
|
||||
// UnmarshalEasyJSON sets the ObjectId from a easyjson.Lexer
|
||||
func (id *ObjectId) UnmarshalEasyJSON(in *jlexer.Lexer) {
|
||||
if data := in.String(); in.Ok() {
|
||||
*id = NewObjectId(data)
|
||||
}
|
||||
}
|
||||
|
||||
// GetBSON returns the hex representation of the ObjectId as a bson.M{} map.
|
||||
func (id *ObjectId) GetBSON() (interface{}, error) {
|
||||
return bson.M{"data": bson.ObjectId(*id).Hex()}, nil
|
||||
}
|
||||
|
||||
// SetBSON sets the ObjectId from raw bson data
|
||||
func (id *ObjectId) SetBSON(raw bson.Raw) error {
|
||||
var m bson.M
|
||||
if err := raw.Unmarshal(&m); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if data, ok := m["data"].(string); ok {
|
||||
*id = NewObjectId(data)
|
||||
return nil
|
||||
}
|
||||
|
||||
return errors.New("couldn't unmarshal bson raw value as ObjectId")
|
||||
}
|
||||
|
||||
// DeepCopyInto copies the receiver and writes its value into out.
|
||||
func (id *ObjectId) DeepCopyInto(out *ObjectId) {
|
||||
*out = *id
|
||||
}
|
||||
|
||||
// DeepCopy copies the receiver into a new ObjectId.
|
||||
func (id *ObjectId) DeepCopy() *ObjectId {
|
||||
if id == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ObjectId)
|
||||
id.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
165
vendor/github.com/go-openapi/strfmt/date.go
generated
vendored
Normal file
165
vendor/github.com/go-openapi/strfmt/date.go
generated
vendored
Normal file
@@ -0,0 +1,165 @@
|
||||
// Copyright 2015 go-swagger maintainers
|
||||
//
|
||||
// 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 strfmt
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/globalsign/mgo/bson"
|
||||
"github.com/mailru/easyjson/jlexer"
|
||||
"github.com/mailru/easyjson/jwriter"
|
||||
)
|
||||
|
||||
func init() {
|
||||
d := Date{}
|
||||
// register this format in the default registry
|
||||
Default.Add("date", &d, IsDate)
|
||||
}
|
||||
|
||||
// IsDate returns true when the string is a valid date
|
||||
func IsDate(str string) bool {
|
||||
_, err := time.Parse(RFC3339FullDate, str)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
const (
|
||||
// RFC3339FullDate represents a full-date as specified by RFC3339
|
||||
// See: http://goo.gl/xXOvVd
|
||||
RFC3339FullDate = "2006-01-02"
|
||||
)
|
||||
|
||||
// Date represents a date from the API
|
||||
//
|
||||
// swagger:strfmt date
|
||||
type Date time.Time
|
||||
|
||||
// String converts this date into a string
|
||||
func (d Date) String() string {
|
||||
return time.Time(d).Format(RFC3339FullDate)
|
||||
}
|
||||
|
||||
// UnmarshalText parses a text representation into a date type
|
||||
func (d *Date) UnmarshalText(text []byte) error {
|
||||
if len(text) == 0 {
|
||||
return nil
|
||||
}
|
||||
dd, err := time.Parse(RFC3339FullDate, string(text))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*d = Date(dd)
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalText serializes this date type to string
|
||||
func (d Date) MarshalText() ([]byte, error) {
|
||||
return []byte(d.String()), nil
|
||||
}
|
||||
|
||||
// Scan scans a Date value from database driver type.
|
||||
func (d *Date) Scan(raw interface{}) error {
|
||||
switch v := raw.(type) {
|
||||
case []byte:
|
||||
return d.UnmarshalText(v)
|
||||
case string:
|
||||
return d.UnmarshalText([]byte(v))
|
||||
case time.Time:
|
||||
*d = Date(v)
|
||||
return nil
|
||||
case nil:
|
||||
*d = Date{}
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("cannot sql.Scan() strfmt.Date from: %#v", v)
|
||||
}
|
||||
}
|
||||
|
||||
// Value converts Date to a primitive value ready to written to a database.
|
||||
func (d Date) Value() (driver.Value, error) {
|
||||
return driver.Value(d.String()), nil
|
||||
}
|
||||
|
||||
// MarshalJSON returns the Date as JSON
|
||||
func (d Date) MarshalJSON() ([]byte, error) {
|
||||
var w jwriter.Writer
|
||||
d.MarshalEasyJSON(&w)
|
||||
return w.BuildBytes()
|
||||
}
|
||||
|
||||
// MarshalEasyJSON writes the Date to a easyjson.Writer
|
||||
func (d Date) MarshalEasyJSON(w *jwriter.Writer) {
|
||||
w.String(time.Time(d).Format(RFC3339FullDate))
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets the Date from JSON
|
||||
func (d *Date) UnmarshalJSON(data []byte) error {
|
||||
if string(data) == jsonNull {
|
||||
return nil
|
||||
}
|
||||
l := jlexer.Lexer{Data: data}
|
||||
d.UnmarshalEasyJSON(&l)
|
||||
return l.Error()
|
||||
}
|
||||
|
||||
// UnmarshalEasyJSON sets the Date from a easyjson.Lexer
|
||||
func (d *Date) UnmarshalEasyJSON(in *jlexer.Lexer) {
|
||||
if data := in.String(); in.Ok() {
|
||||
tt, err := time.Parse(RFC3339FullDate, data)
|
||||
if err != nil {
|
||||
in.AddError(err)
|
||||
return
|
||||
}
|
||||
*d = Date(tt)
|
||||
}
|
||||
}
|
||||
|
||||
// GetBSON returns the Date as a bson.M{} map.
|
||||
func (d *Date) GetBSON() (interface{}, error) {
|
||||
return bson.M{"data": d.String()}, nil
|
||||
}
|
||||
|
||||
// SetBSON sets the Date from raw bson data
|
||||
func (d *Date) SetBSON(raw bson.Raw) error {
|
||||
var m bson.M
|
||||
if err := raw.Unmarshal(&m); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if data, ok := m["data"].(string); ok {
|
||||
rd, err := time.Parse(RFC3339FullDate, data)
|
||||
*d = Date(rd)
|
||||
return err
|
||||
}
|
||||
|
||||
return errors.New("couldn't unmarshal bson raw value as Date")
|
||||
}
|
||||
|
||||
// DeepCopyInto copies the receiver and writes its value into out.
|
||||
func (d *Date) DeepCopyInto(out *Date) {
|
||||
*out = *d
|
||||
}
|
||||
|
||||
// DeepCopy copies the receiver into a new Date.
|
||||
func (d *Date) DeepCopy() *Date {
|
||||
if d == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Date)
|
||||
d.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
2244
vendor/github.com/go-openapi/strfmt/default.go
generated
vendored
Normal file
2244
vendor/github.com/go-openapi/strfmt/default.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