mirror of
https://github.com/redhat-developer/odo.git
synced 2025-10-19 03:06:19 +03:00
Enter Telemetry (#4482)
* Send telemetry to segment * Add tests and other properties * Add comments * Fix fmt * Add telemetry dev key * Add non-test related changes requested to the PR and add consenttelemetry prompt * Handle prompt while running tests * First attempt at fixing unit job failure * Modify tests as requested * Stop prompting when preference is called * Fix comments * Add more unit tests and integration test(WIP) * Fix failing tests * Stop prompting when help is called * Make tests more verbose * Add Usage data doc * Add segment key * Add a better usage doc * Add comments, move tests and other requested changes * Fix comments and remove focus * Add set ConsentTelemetry unit tests * Change want from string to bool * Fix failing integration test * Fix failing operator hub test * Fix failing devfile integration test * Fix tests failing due to cmdwrapper WithEnv Co-authored-by: Dharmit Shah <shahdharmit@gmail.com>
This commit is contained in:
29
USAGE_DATA.adoc
Normal file
29
USAGE_DATA.adoc
Normal file
@@ -0,0 +1,29 @@
|
||||
[[odo]]
|
||||
= `odo` - Developer-focused CLI for Kubernetes and OpenShift
|
||||
:toc: macro
|
||||
:toc-title:
|
||||
:toclevels: 1
|
||||
|
||||
[[usage-data]]
|
||||
== Usage Data
|
||||
|
||||
If the user has consented to `odo` collecting usage data, the following data is collected when a command is executed -
|
||||
|
||||
* command's ID
|
||||
* command's duration time
|
||||
* command's error message and error type (in case of failure)
|
||||
* whether the command was run from a terminal
|
||||
* system information such as OS type
|
||||
* `odo` version in use
|
||||
|
||||
|
||||
[[enable-disable]]
|
||||
== Enable/Disable preference
|
||||
|
||||
Enable::
|
||||
`odo preference set ConsentTelemetry true`
|
||||
|
||||
Disable::
|
||||
`odo preference set ConsentTelemetry false`
|
||||
|
||||
Note: If earlier the `ConsentTelemetry` preference was enabled, then the data will be collected about the disabling of the preference.
|
||||
@@ -53,13 +53,14 @@ func main() {
|
||||
return
|
||||
}
|
||||
|
||||
// Call commands
|
||||
// checking the value of updatenotification in config
|
||||
// before proceeding with fetching the latest version
|
||||
cfg, err := preference.New()
|
||||
if err != nil {
|
||||
util.LogErrorAndExit(err, "")
|
||||
}
|
||||
|
||||
// Call commands
|
||||
// checking the value of updatenotification in config
|
||||
// before proceeding with fetching the latest version
|
||||
if cfg.GetUpdateNotification() {
|
||||
updateInfo := make(chan string)
|
||||
go version.GetLatestReleaseInfo(updateInfo)
|
||||
|
||||
5
go.mod
5
go.mod
@@ -18,7 +18,6 @@ require (
|
||||
github.com/go-git/go-git/v5 v5.2.0
|
||||
github.com/gobwas/glob v0.2.4-0.20181002190808-e7a84e9525fe
|
||||
github.com/golang/mock v1.4.4
|
||||
github.com/gosimple/slug v1.9.0
|
||||
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79
|
||||
github.com/hinshun/vt10x v0.0.0-20180809195222-d55458df857c
|
||||
github.com/imdario/mergo v0.3.11 // indirect
|
||||
@@ -40,20 +39,24 @@ require (
|
||||
github.com/openshift/library-go v0.0.0-20200407165825-2e79bd232e72
|
||||
github.com/openshift/oc v0.0.0-alpha.0.0.20200305142246-2576e482bf00
|
||||
github.com/operator-framework/operator-lifecycle-manager v0.0.0-20200422144016-a6acf50218ed
|
||||
github.com/pborman/uuid v1.2.0
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/posener/complete v1.1.2
|
||||
github.com/redhat-developer/service-binding-operator v0.3.0
|
||||
github.com/segmentio/backo-go v0.0.0-20200129164019-23eae7c10bd3 // indirect
|
||||
github.com/spf13/afero v1.2.2
|
||||
github.com/spf13/cobra v0.0.5
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/stretchr/testify v1.6.1
|
||||
github.com/tidwall/gjson v1.6.3
|
||||
github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c // indirect
|
||||
github.com/zalando/go-keyring v0.1.0
|
||||
golang.org/x/crypto v0.0.0-20201124201722-c8d3bf9c5392 // indirect
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b // indirect
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 // indirect
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221
|
||||
gopkg.in/AlecAivazis/survey.v1 v1.8.0
|
||||
gopkg.in/segmentio/analytics-go.v3 v3.1.0
|
||||
gopkg.in/yaml.v2 v2.3.0
|
||||
k8s.io/api v0.19.0
|
||||
k8s.io/apimachinery v0.19.0
|
||||
|
||||
32
go.sum
32
go.sum
@@ -132,6 +132,7 @@ github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngE
|
||||
github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
|
||||
github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ=
|
||||
github.com/blang/semver v3.5.1+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/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
|
||||
github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
|
||||
@@ -217,12 +218,8 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
|
||||
github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd/go.mod h1:dv4zxwHi5C/8AeI+4gX4dCWOIvNi7I6JCSX0HvlKPgE=
|
||||
github.com/deislabs/oras v0.7.0/go.mod h1:sqMKPG3tMyIX9xwXUBRLhZ24o+uT4y6jgBD2RzUTKDM=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20190515213511-eb9f6a1743f3/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM=
|
||||
github.com/devfile/api v0.0.0-20201103130402-29b8738e196e h1:Ha6wyKs7VWqQTz2Fm1o4PAYpKX6SIiYjgWmGzNW8cBE=
|
||||
github.com/devfile/api v0.0.0-20201103130402-29b8738e196e/go.mod h1:hp5Lmob7ESmtSZXZ7xRN9o8vemsen9111+ASi2YuXs4=
|
||||
github.com/devfile/api/v2 v2.0.0-20210211160219-33a78aec06af h1:egbFAAS/CWJMAqa4zIm8Cik3+iCqTAfLPfCj6PLEG5Y=
|
||||
github.com/devfile/api/v2 v2.0.0-20210211160219-33a78aec06af/go.mod h1:Cot4snybn3qhIh48oIFi9McocnIx7zY5fFbjfrIpPvg=
|
||||
github.com/devfile/library v0.0.0-20201125155652-6eabeab3ee52 h1:crtWc9SVN0Qw4DkXxD84ChcOomgm0JC/nQ5fKYha4LU=
|
||||
github.com/devfile/library v0.0.0-20201125155652-6eabeab3ee52/go.mod h1:eQMM2+rxfAZzpG/Ujyoa5yQuezws/q0izcCkTUv0dG8=
|
||||
github.com/devfile/library v0.0.0-20210216162950-3066a892876c h1:NL9EpuPuFVxCqE00Bh1Uw3YsEqoMdwq4vx0OXSZRVnU=
|
||||
github.com/devfile/library v0.0.0-20210216162950-3066a892876c/go.mod h1:aGJSpcGrRiYwsQQJMQH1ChHuOptUf49n+j0RDBYyTIQ=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
|
||||
@@ -539,8 +536,6 @@ github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw=
|
||||
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/gosimple/slug v1.9.0 h1:r5vDcYrFz9BmfIAMC829un9hq7hKM4cHUrsv36LbEqs=
|
||||
github.com/gosimple/slug v1.9.0/go.mod h1:AMZ+sOVe65uByN3kgEyf9WEBKBCSS+dJjMX9x4vDJbg=
|
||||
github.com/gostaticanalysis/analysisutil v0.0.0-20190318220348-4088753ea4d3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE=
|
||||
github.com/gostaticanalysis/analysisutil v0.0.3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE=
|
||||
github.com/gosuri/uitable v0.0.1/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo=
|
||||
@@ -616,8 +611,6 @@ github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCV
|
||||
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.8 h1:QiWkFLKq0T7mpzwOTu6BzNDbfTE8OLrYhVKYMLF46Ok=
|
||||
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
|
||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
|
||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/jsonnet-bundler/jsonnet-bundler v0.1.0/go.mod h1:YKsSFc9VFhhLITkJS3X2PrRqWG9u2Jq99udTdDjQLfM=
|
||||
@@ -779,7 +772,6 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W
|
||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||
github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA=
|
||||
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
|
||||
@@ -790,7 +782,6 @@ github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1Cpa
|
||||
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
|
||||
github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE=
|
||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ=
|
||||
@@ -819,7 +810,6 @@ github.com/openshift/custom-resource-status v0.0.0-20200602122900-c002fd1547ca/g
|
||||
github.com/openshift/gssapi v0.0.0-20161010215902-5fb4217df13b h1:it0YPE/evO6/m8t8wxis9KFI2F/aleOKsI6d9uz0cEk=
|
||||
github.com/openshift/gssapi v0.0.0-20161010215902-5fb4217df13b/go.mod h1:tNrEB5k8SI+g5kOlsCmL2ELASfpqEofI0+FLBgBdN08=
|
||||
github.com/openshift/kubernetes v1.17.0-alpha.0.0.20191216151305-079984b0a154/go.mod h1:ypOpFo7ff7y/tpC3zDdQ5NonHlPDTJ6iKnOChMPfloQ=
|
||||
github.com/openshift/kubernetes-apimachinery v0.0.0-20190820100751-ac02f8882ef6 h1:KRSXk0YTtZ5b8Wwg0H+Pleie6dKjRj6Qnwx6OW398cQ=
|
||||
github.com/openshift/kubernetes-apimachinery v0.0.0-20191211181342-5a804e65bdc1 h1:pBVMoJWgY4x5R3ZL7U8yXjnIXjUqfv0x21WUU2de3+4=
|
||||
github.com/openshift/kubernetes-apimachinery v0.0.0-20191211181342-5a804e65bdc1/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg=
|
||||
github.com/openshift/kubernetes-cli-runtime v0.0.0-20200114162348-c8810ef308ee h1:Lq+Jnpe8ciNYRm1SyF50Uvk29zybO5g2IgpAi7XGBCI=
|
||||
@@ -859,6 +849,7 @@ github.com/otiai10/curr v0.0.0-20190513014714-f5a3d24e5776/go.mod h1:3HNVkVOU7vZ
|
||||
github.com/otiai10/mint v1.2.3/go.mod h1:YnfyPNhBvnY8bW4SGQHCs/aAFhkgySlMZbrF5U0bOVw=
|
||||
github.com/otiai10/mint v1.2.4/go.mod h1:d+b7n/0R3tdyUYYylALXpWQ/kTN+QobSq/4SRGBkR3M=
|
||||
github.com/pborman/uuid v0.0.0-20180906182336-adf5a7427709/go.mod h1:VyrYX9gd7irzKovcSS6BIIEwPRkP2Wm2m9ufcdFSJ34=
|
||||
github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g=
|
||||
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
|
||||
github.com/pelletier/go-toml v1.1.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
@@ -918,8 +909,6 @@ github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40T
|
||||
github.com/prometheus/tsdb v0.8.0/go.mod h1:fSI0j+IUQrDd7+ZtR9WKIGtoYAYAJUKcKhYLG25tN4g=
|
||||
github.com/quasilyte/go-consistent v0.0.0-20190521200055-c6f3937de18c/go.mod h1:5STLWrekHfjyYwxBRVRXNOSewLJ3PWfDJd1VyTS21fI=
|
||||
github.com/quobyte/api v0.1.2/go.mod h1:jL7lIHrmqQ7yh05OJ+eEEdHr0u/kmT1Ff9iHd+4H6VI=
|
||||
github.com/rainycape/unidecode v0.0.0-20150907023854-cb7f23ec59be h1:ta7tUOvsPHVHGom5hKW5VXNc2xZIkfCKP8iaqOyYtUQ=
|
||||
github.com/rainycape/unidecode v0.0.0-20150907023854-cb7f23ec59be/go.mod h1:MIDFMn7db1kT65GmV94GzpX9Qdi7N/pQlwb+AN8wh+Q=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||
github.com/redhat-developer/service-binding-operator v0.3.0 h1:79FuZinHtInpC5NYmDREiKK8DxmXV1L28OSzENtg8tA=
|
||||
github.com/redhat-developer/service-binding-operator v0.3.0/go.mod h1:FQgDVBuBvln4TRlPQcTxTnNuJSIhNv3Z/xsMvalLaqo=
|
||||
@@ -941,6 +930,8 @@ github.com/santhosh-tekuri/jsonschema v1.2.4/go.mod h1:TEAUOeZSmIxTTuHatJzrvARHi
|
||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||
github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U=
|
||||
github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo=
|
||||
github.com/segmentio/backo-go v0.0.0-20200129164019-23eae7c10bd3 h1:ZuhckGJ10ulaKkdvJtiAqsLTiPrLaXSdnVgXJKJkTxE=
|
||||
github.com/segmentio/backo-go v0.0.0-20200129164019-23eae7c10bd3/go.mod h1:9/Rh6yILuLysoQnZ2oNooD2g7aBnvM7r/fNVxRNWfBc=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
|
||||
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||
@@ -1042,6 +1033,8 @@ github.com/xenolf/lego v0.3.2-0.20160613233155-a9d8cec0e656/go.mod h1:fwiGnfsIjG
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
github.com/xlab/handysort v0.0.0-20150421192137-fb3537ed64a1/go.mod h1:QcJo0QPSfTONNIgpN5RA8prR7fF8nkF6cTWTcNerRO8=
|
||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c h1:3lbZUMbMiGUW/LMkfsEABsc5zNT9+b1CvsJx47JzJ8g=
|
||||
github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c/go.mod h1:UrdRz5enIKZ63MEE3IF9l2/ebyx59GyGgPi+tICQdmM=
|
||||
github.com/yvasiyarov/go-metrics v0.0.0-20150112132944-c25f46c4b940/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs=
|
||||
github.com/yvasiyarov/gorelic v0.0.6/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA=
|
||||
github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg=
|
||||
@@ -1150,9 +1143,7 @@ golang.org/x/net v0.0.0-20191028085509-fe3aa8a45271/go.mod h1:z5CRVTTTmAJ677TzLL
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2 h1:CCH4IOTTfewWjGOlSp+zGcjutRKlBEZQ6wTn8ozI/nI=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7 h1:AeiKBIuRw3UomYXSbLy0Mc2dDLfdtbT/IVn4keq83P0=
|
||||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b h1:uwuIcX0g4Yl1NC5XAz37xsr2lTtcqevgzYNVt49waME=
|
||||
@@ -1209,7 +1200,6 @@ golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -1219,10 +1209,8 @@ golang.org/x/sys v0.0.0-20191210023423-ac6580df4449/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299 h1:DYfZAGf2WMFjMxbgTjaC+2HC7NkNAQs+6Q8b9WEB/F4=
|
||||
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -1370,6 +1358,8 @@ gopkg.in/mcuadros/go-syslog.v2 v2.2.1/go.mod h1:l5LPIyOOyIdQquNg+oU6Z3524YwrcqEm
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
|
||||
gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473/go.mod h1:N1eN2tsCx0Ydtgjl4cqmbRCsY4/+z4cYDeqwZTk6zog=
|
||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||
gopkg.in/segmentio/analytics-go.v3 v3.1.0 h1:UzxH1uaGZRpMKDhJyBz0pexz6yUoBU3x8bJsRk/HV6U=
|
||||
gopkg.in/segmentio/analytics-go.v3 v3.1.0/go.mod h1:4QqqlTlSSpVlWA9/9nDcPw+FkM2yv1NQoYjUbL9/JAw=
|
||||
gopkg.in/square/go-jose.v1 v1.1.2/go.mod h1:QpYS+a4WhS+DTlyQIi6Ka7MS3SuR9a055rgXNEe6EiA=
|
||||
gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
@@ -1384,7 +1374,6 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||
@@ -1460,8 +1449,6 @@ k8s.io/utils v0.0.0-20190801114015-581e00157fb1/go.mod h1:sZAwmy6armz5eXlNoLmJcl
|
||||
k8s.io/utils v0.0.0-20191010214722-8d271d903fe4/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
|
||||
k8s.io/utils v0.0.0-20191114184206-e782cd3c129f h1:GiPwtSzdP43eI1hpPCbROQCCIgCuiMMNF8YUVLF3vJo=
|
||||
k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
|
||||
k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89 h1:d4vVOjXm687F1iLSP2q3lyPPuyvTUt3aVoBpi2DqRsU=
|
||||
k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
|
||||
k8s.io/utils v0.0.0-20200603063816-c1c6865ac451 h1:v8ud2Up6QK1lNOKFgiIVrZdMg7MpmSnvtrOieolJKoE=
|
||||
k8s.io/utils v0.0.0-20200603063816-c1c6865ac451/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
knative.dev/pkg v0.0.0-20191221032535-9fda5bd59a67/go.mod h1:pgODObA1dTyhNoFxPZTTjNWfx6F0aKsKzn+vaT9XO/Q=
|
||||
@@ -1478,9 +1465,6 @@ rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8
|
||||
rsc.io/letsencrypt v0.0.1/go.mod h1:buyQKZ6IXrRnB7TdkHP0RyEybLx18HHyOSoTyoOLqNY=
|
||||
sigs.k8s.io/controller-runtime v0.1.10/go.mod h1:HFAYoOh6XMV+jKF1UjFwrknPbowfyHEHHRdJMf2jMX8=
|
||||
sigs.k8s.io/controller-runtime v0.4.0/go.mod h1:ApC79lpY3PHW9xj/w9pj+lYkLgwAAUZwfXkME1Lajns=
|
||||
sigs.k8s.io/controller-runtime v0.5.2/go.mod h1:JZUwSMVbxDupo0lTJSSFP5pimEyxGynROImSsqIOx1A=
|
||||
sigs.k8s.io/controller-runtime v0.6.0 h1:Fzna3DY7c4BIP6KwfSlrfnj20DJ+SeMBK8HSFvOk9NM=
|
||||
sigs.k8s.io/controller-runtime v0.6.0/go.mod h1:CpYf5pdNY/B352A1TFLAS2JVSlnGQ5O2cftPHndTroo=
|
||||
sigs.k8s.io/controller-runtime v0.6.3 h1:SBbr+inLPEKhvlJtrvDcwIpm+uhDvp63Bl72xYJtoOE=
|
||||
sigs.k8s.io/controller-runtime v0.6.3/go.mod h1:WlZNXcM0++oyaQt4B7C2lEE5JYRs8vJUzRP4N4JpdAY=
|
||||
sigs.k8s.io/controller-tools v0.1.10/go.mod h1:6g08p9m9G/So3sBc1AOQifHfhxH/mb6Sc4z0LMI8XMw=
|
||||
|
||||
@@ -4,6 +4,15 @@ import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/openshift/odo/pkg/odo/cli/ui"
|
||||
"gopkg.in/AlecAivazis/survey.v1"
|
||||
|
||||
"github.com/openshift/odo/pkg/preference"
|
||||
"github.com/openshift/odo/pkg/segment"
|
||||
"k8s.io/klog"
|
||||
|
||||
"github.com/openshift/odo/pkg/log"
|
||||
"github.com/openshift/odo/pkg/odo/util"
|
||||
@@ -11,6 +20,10 @@ import (
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
var (
|
||||
segmentClient *segment.Client
|
||||
)
|
||||
|
||||
type Runnable interface {
|
||||
Complete(name string, cmd *cobra.Command, args []string) error
|
||||
Validate() error
|
||||
@@ -18,6 +31,33 @@ type Runnable interface {
|
||||
}
|
||||
|
||||
func GenericRun(o Runnable, cmd *cobra.Command, args []string) {
|
||||
var err error
|
||||
var startTime time.Time
|
||||
cfg, _ := preference.New()
|
||||
|
||||
// Prompt the user to consent for telemetry if a value is not set already
|
||||
// Skip prompting if the preference command is called
|
||||
// This prompt has been placed here so that it does not prompt the user when they call --help
|
||||
if !cfg.IsSet(preference.ConsentTelemetrySetting) && cmd.Parent().Name() != "preference" {
|
||||
var consentTelemetry bool
|
||||
prompt := &survey.Confirm{Message: "Help odo improve by allowing it to collect usage data. Read about our privacy statement: https://developers.redhat.com/article/tool-data-collection. You can change your preference later by changing the ConsentTelemetry preference.", Default: false}
|
||||
err = survey.AskOne(prompt, &consentTelemetry, nil)
|
||||
ui.HandleError(err)
|
||||
if err == nil {
|
||||
if err1 := cfg.SetConfiguration(preference.ConsentTelemetrySetting, strconv.FormatBool(consentTelemetry)); err1 != nil {
|
||||
klog.V(4).Info(err1.Error())
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
// Initiate the segment client if ConsentTelemetry preference is set to true
|
||||
if cfg.GetConsentTelemetry() {
|
||||
if segmentClient, err = segment.NewClient(cfg); err != nil {
|
||||
klog.V(4).Infof("Cannot create a segment client, will not send any data: %s", err.Error())
|
||||
}
|
||||
defer segmentClient.Close()
|
||||
startTime = time.Now()
|
||||
}
|
||||
|
||||
// CheckMachineReadableOutput
|
||||
// fixes / checks all related machine readable output functions
|
||||
@@ -26,9 +66,30 @@ func GenericRun(o Runnable, cmd *cobra.Command, args []string) {
|
||||
// LogErrorAndExit is used so that we get -o (jsonoutput) for cmds which have json output implemented
|
||||
util.LogErrorAndExit(checkConflictingFlags(cmd), "")
|
||||
// Run completion, validation and run.
|
||||
util.LogErrorAndExit(o.Complete(cmd.Name(), cmd, args), "")
|
||||
util.LogErrorAndExit(o.Validate(), "")
|
||||
util.LogErrorAndExit(o.Run(), "")
|
||||
// Only upload data to segment for completion and validation if a non-nil error is returned.
|
||||
err = o.Complete(cmd.Name(), cmd, args)
|
||||
if err != nil {
|
||||
uploadToSegmentAndLog(cmd, err, startTime)
|
||||
}
|
||||
err = o.Validate()
|
||||
if err != nil {
|
||||
uploadToSegmentAndLog(cmd, err, startTime)
|
||||
}
|
||||
uploadToSegmentAndLog(cmd, o.Run(), startTime)
|
||||
}
|
||||
|
||||
// uploadToSegmentAndLog uploads the data to segment and logs the error
|
||||
func uploadToSegmentAndLog(cmd *cobra.Command, err error, startTime time.Time) {
|
||||
if segmentClient != nil {
|
||||
if serr := segmentClient.Upload(cmd.CommandPath(), time.Since(startTime), err); serr != nil {
|
||||
klog.Errorf("Cannot send data to telemetry: %v", serr)
|
||||
}
|
||||
// If the error is not nil, client will be closed so that data can be sent before the program exits.
|
||||
if err != nil {
|
||||
segmentClient.Close()
|
||||
}
|
||||
}
|
||||
util.LogErrorAndExit(err, "")
|
||||
}
|
||||
|
||||
// checkConflictingFlags checks for conflicting flags. Currently --context cannot be provided
|
||||
|
||||
@@ -120,7 +120,7 @@ func TestGetBuildTimeout(t *testing.T) {
|
||||
|
||||
output := cfg.GetBuildTimeout()
|
||||
if output != tt.want {
|
||||
t.Errorf("GetBuildTimeout returned unexpected value expected \ngot: %d \nexpected: %d\n", output, tt.want)
|
||||
t.Errorf("GetBuildTimeout returned unexpected value\ngot: %d \nexpected: %d\n", output, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -176,7 +176,7 @@ func TestGetPushTimeout(t *testing.T) {
|
||||
|
||||
output := cfg.GetPushTimeout()
|
||||
if output != tt.want {
|
||||
t.Errorf("GetPushTimeout returned unexpected value expected \ngot: %d \nexpected: %d\n", output, tt.want)
|
||||
t.Errorf("GetPushTimeout returned unexpected value\ngot: %d \nexpected: %d\n", output, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -232,7 +232,7 @@ func TestGetTimeout(t *testing.T) {
|
||||
|
||||
output := cfg.GetTimeout()
|
||||
if output != tt.want {
|
||||
t.Errorf("GetTimeout returned unexpected value expected \ngot: %d \nexpected: %d\n", output, tt.want)
|
||||
t.Errorf("GetTimeout returned unexpected value\ngot: %d \nexpected: %d\n", output, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -491,6 +491,33 @@ func TestSetConfiguration(t *testing.T) {
|
||||
existingConfig: Preference{},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: fmt.Sprintf("Case 27: set %s to non bool value", ConsentTelemetrySetting),
|
||||
parameter: ConsentTelemetrySetting,
|
||||
value: "123",
|
||||
existingConfig: Preference{},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: fmt.Sprintf("Case 28: set %s from nil to true", ConsentTelemetrySetting),
|
||||
parameter: ConsentTelemetrySetting,
|
||||
value: "true",
|
||||
existingConfig: Preference{},
|
||||
wantErr: false,
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: fmt.Sprintf("Case 29: set %s from true to false", ConsentTelemetrySetting),
|
||||
parameter: ConsentTelemetrySetting,
|
||||
value: "false",
|
||||
existingConfig: Preference{
|
||||
OdoSettings: OdoSettings{
|
||||
ConsentTelemetry: &trueValue,
|
||||
},
|
||||
},
|
||||
wantErr: false,
|
||||
want: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
@@ -508,23 +535,23 @@ func TestSetConfiguration(t *testing.T) {
|
||||
switch tt.parameter {
|
||||
case "updatenotification":
|
||||
if *cfg.OdoSettings.UpdateNotification != tt.want {
|
||||
t.Errorf("unexpected value after execution of SetConfiguration \ngot: %t \nexpected: %t\n", *cfg.OdoSettings.UpdateNotification, tt.want)
|
||||
t.Errorf("unexpected value after execution of SetConfiguration\ngot: %t \nexpected: %t\n", *cfg.OdoSettings.UpdateNotification, tt.want)
|
||||
}
|
||||
case "timeout":
|
||||
if *cfg.OdoSettings.Timeout != tt.want {
|
||||
t.Errorf("unexpected value after execution of SetConfiguration \ngot: %v \nexpected: %d\n", cfg.OdoSettings.Timeout, tt.want)
|
||||
t.Errorf("unexpected value after execution of SetConfiguration\ngot: %v \nexpected: %d\n", cfg.OdoSettings.Timeout, tt.want)
|
||||
}
|
||||
case "experimental":
|
||||
if *cfg.OdoSettings.Experimental != tt.want {
|
||||
t.Errorf("unexpected value after execution of SetConfiguration \ngot: %v \nexpected: %d\n", cfg.OdoSettings.Experimental, tt.want)
|
||||
t.Errorf("unexpected value after execution of SetConfiguration\ngot: %v \nexpected: %d\n", cfg.OdoSettings.Experimental, tt.want)
|
||||
}
|
||||
case "pushtarget":
|
||||
if *cfg.OdoSettings.PushTarget != tt.want {
|
||||
t.Errorf("unexpected value after execution of SetConfiguration \ngot: %v \nexpected: %d\n", cfg.OdoSettings.PushTarget, tt.want)
|
||||
t.Errorf("unexpected value after execution of SetConfiguration\ngot: %v \nexpected: %d\n", cfg.OdoSettings.PushTarget, tt.want)
|
||||
}
|
||||
case "registrycachetime":
|
||||
if *cfg.OdoSettings.RegistryCacheTime != tt.want {
|
||||
t.Errorf("unexpected value after execution of SetConfiguration \ngot: %v \nexpected: %d\n", *cfg.OdoSettings.RegistryCacheTime, tt.want)
|
||||
t.Errorf("unexpected value after execution of SetConfiguration\ngot: %v \nexpected: %d\n", *cfg.OdoSettings.RegistryCacheTime, tt.want)
|
||||
}
|
||||
}
|
||||
} else if tt.wantErr && err != nil {
|
||||
@@ -547,6 +574,61 @@ func TestSetConfiguration(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestConsentTelemetry(t *testing.T) {
|
||||
tempConfigFile, err := ioutil.TempFile("", "odoconfig")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer tempConfigFile.Close()
|
||||
os.Setenv(GlobalConfigEnvName, tempConfigFile.Name())
|
||||
trueValue := true
|
||||
falseValue := false
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
existingConfig Preference
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
name: fmt.Sprintf("Case 1: %s nil", ConsentTelemetrySetting),
|
||||
existingConfig: Preference{},
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: fmt.Sprintf("Case 2: %s true", ConsentTelemetrySetting),
|
||||
existingConfig: Preference{
|
||||
OdoSettings: OdoSettings{
|
||||
ConsentTelemetry: &trueValue,
|
||||
},
|
||||
},
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: fmt.Sprintf("Case 3: %s false", ConsentTelemetrySetting),
|
||||
existingConfig: Preference{
|
||||
OdoSettings: OdoSettings{
|
||||
ConsentTelemetry: &falseValue,
|
||||
},
|
||||
},
|
||||
want: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
cfg := PreferenceInfo{
|
||||
Preference: tt.existingConfig,
|
||||
}
|
||||
output := cfg.GetConsentTelemetry()
|
||||
|
||||
if output != tt.want {
|
||||
t.Errorf("ConsentTelemetry returned unexpected value\ngot: %t \nexpected: %t\n", output, tt.want)
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetupdateNotification(t *testing.T) {
|
||||
|
||||
tempConfigFile, err := ioutil.TempFile("", "odoconfig")
|
||||
@@ -596,7 +678,7 @@ func TestGetupdateNotification(t *testing.T) {
|
||||
output := cfg.GetUpdateNotification()
|
||||
|
||||
if output != tt.want {
|
||||
t.Errorf("GetUpdateNotification returned unexpected value expected \ngot: %t \nexpected: %t\n", output, tt.want)
|
||||
t.Errorf("GetUpdateNotification returned unexpected value\ngot: %t \nexpected: %t\n", output, tt.want)
|
||||
}
|
||||
|
||||
})
|
||||
@@ -652,7 +734,7 @@ func TestGetExperimental(t *testing.T) {
|
||||
output := cfg.GetExperimental()
|
||||
|
||||
if output != tt.want {
|
||||
t.Errorf("GetExperimental returned unexpected value expected \ngot: %t \nexpected: %t\n", output, tt.want)
|
||||
t.Errorf("GetExperimental returned unexpected value\ngot: %t \nexpected: %t\n", output, tt.want)
|
||||
}
|
||||
|
||||
})
|
||||
@@ -708,7 +790,7 @@ func TestGetPushTarget(t *testing.T) {
|
||||
output := cfg.GetPushTarget()
|
||||
|
||||
if output != tt.want {
|
||||
t.Errorf("GetExperimental returned unexpected value expected \ngot: %s \nexpected: %s\n", output, tt.want)
|
||||
t.Errorf("GetExperimental returned unexpected value\ngot: %s \nexpected: %s\n", output, tt.want)
|
||||
}
|
||||
|
||||
})
|
||||
@@ -967,7 +1049,7 @@ func TestGetConsentTelemetry(t *testing.T) {
|
||||
output := cfg.GetConsentTelemetry()
|
||||
|
||||
if output != tt.want {
|
||||
t.Errorf("GetConsentTelemetry returned unexpected value expected \ngot: %t \nexpected: %t\n", output, tt.want)
|
||||
t.Errorf("GetConsentTelemetry returned unexpected value\ngot: %t \nexpected: %t\n", output, tt.want)
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
163
pkg/segment/segment.go
Normal file
163
pkg/segment/segment.go
Normal file
@@ -0,0 +1,163 @@
|
||||
package segment
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"os"
|
||||
"os/user"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/openshift/odo/pkg/preference"
|
||||
"github.com/openshift/odo/pkg/version"
|
||||
"github.com/pborman/uuid"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/term"
|
||||
"gopkg.in/segmentio/analytics-go.v3"
|
||||
)
|
||||
|
||||
// Writekey will be the API key used to send data to the correct source on Segment
|
||||
var WriteKey = "R1Z79HadJIrphLoeONZy5uqOjusljSwN"
|
||||
|
||||
type Client struct {
|
||||
// SegmentClient helps interact with the segment API
|
||||
SegmentClient analytics.Client
|
||||
// Preference points to the global odo config
|
||||
Preference *preference.PreferenceInfo
|
||||
// TelemetryFilePath points to the file containing anonymousID used for tracking odo commands executed by the user
|
||||
TelemetryFilePath string
|
||||
}
|
||||
|
||||
// NewClient returns a Client created with the default args
|
||||
func NewClient(preference *preference.PreferenceInfo) (*Client, error) {
|
||||
homeDir, _ := os.UserHomeDir()
|
||||
return newCustomClient(preference,
|
||||
filepath.Join(homeDir, ".redhat", "anonymousId"),
|
||||
analytics.DefaultEndpoint,
|
||||
)
|
||||
}
|
||||
|
||||
// newCustomClient returns a Client created with custom args
|
||||
func newCustomClient(preference *preference.PreferenceInfo, telemetryFilePath string, segmentEndpoint string) (*Client, error) {
|
||||
// DefaultContext has IP set to 0.0.0.0 so that it does not track user's IP, which it does in case no IP is set
|
||||
client, err := analytics.NewWithConfig(WriteKey, analytics.Config{
|
||||
Endpoint: segmentEndpoint,
|
||||
DefaultContext: &analytics.Context{
|
||||
IP: net.IPv4(0, 0, 0, 0),
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Client{
|
||||
SegmentClient: client,
|
||||
Preference: preference,
|
||||
TelemetryFilePath: telemetryFilePath,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Close client connection and send the data
|
||||
func (c *Client) Close() error {
|
||||
return c.SegmentClient.Close()
|
||||
}
|
||||
|
||||
// Upload prepares the data to be sent to segment and send it once the client connection closes
|
||||
func (c *Client) Upload(action string, duration time.Duration, err error) error {
|
||||
// if the user has not consented for telemetry, return
|
||||
if !c.Preference.GetConsentTelemetry() {
|
||||
return nil
|
||||
}
|
||||
|
||||
// obtain the anonymous ID
|
||||
anonymousID, uerr := getUserIdentity(c.TelemetryFilePath)
|
||||
if uerr != nil {
|
||||
return uerr
|
||||
}
|
||||
|
||||
// queue the data that helps identify the user on segment
|
||||
if err1 := c.SegmentClient.Enqueue(analytics.Identify{
|
||||
AnonymousId: anonymousID,
|
||||
Traits: addConfigTraits(),
|
||||
}); err1 != nil {
|
||||
return err1
|
||||
}
|
||||
|
||||
// add information to the data
|
||||
properties := analytics.NewProperties()
|
||||
// TODO: add other properties when required
|
||||
properties = properties.Set("version", fmt.Sprintf("odo %v (%v)", version.VERSION, version.GITCOMMIT)).
|
||||
Set("success", err == nil).
|
||||
Set("duration(ms)", duration.Milliseconds()).
|
||||
Set("tty", RunningInTerminal())
|
||||
// in case the command executed unsuccessfully, add information about the error in the data
|
||||
if err != nil {
|
||||
properties = properties.Set("error", SetError(err)).Set("error-type", errorType(err))
|
||||
}
|
||||
|
||||
// queue the data that has telemetry information
|
||||
return c.SegmentClient.Enqueue(analytics.Track{
|
||||
AnonymousId: anonymousID,
|
||||
Event: action,
|
||||
Properties: properties,
|
||||
})
|
||||
}
|
||||
|
||||
// addConfigTraits adds information about the system
|
||||
func addConfigTraits() analytics.Traits {
|
||||
traits := analytics.NewTraits().Set("os", runtime.GOOS)
|
||||
return traits
|
||||
}
|
||||
|
||||
// getUserIdentity returns the anonymous ID if it exists, else creates a new one
|
||||
func getUserIdentity(telemetryFilePath string) (string, error) {
|
||||
var id []byte
|
||||
|
||||
// Get-or-Create the '$HOME/.redhat' directory
|
||||
if err := os.MkdirAll(filepath.Dir(telemetryFilePath), 0750); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Get-or-Create the anonymousID file that contains a UUID
|
||||
if _, err := os.Stat(telemetryFilePath); !os.IsNotExist(err) {
|
||||
id, err = ioutil.ReadFile(telemetryFilePath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
// check if the id is a valid uuid, if not, nil is returned
|
||||
if uuid.Parse(strings.TrimSpace(string(id))) == nil {
|
||||
id = []byte(uuid.NewRandom().String())
|
||||
if err := ioutil.WriteFile(telemetryFilePath, id, 0600); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
return strings.TrimSpace(string(id)), nil
|
||||
}
|
||||
|
||||
// SetError sanitizes any PII(Personally Identifiable Information) from the error
|
||||
func SetError(err error) string {
|
||||
// Sanitize user information
|
||||
user1, err1 := user.Current()
|
||||
if err1 != nil {
|
||||
return errors.Wrapf(err1, err1.Error()).Error()
|
||||
}
|
||||
return strings.ReplaceAll(err.Error(), user1.Username, "XXXX")
|
||||
}
|
||||
|
||||
// errorType returns the type of error
|
||||
func errorType(err error) string {
|
||||
wrappedErr := errors.Unwrap(err)
|
||||
if wrappedErr != nil {
|
||||
return fmt.Sprintf("%T", wrappedErr)
|
||||
}
|
||||
return fmt.Sprintf("%T", err)
|
||||
}
|
||||
|
||||
// RunningInTerminal checks if odo was run from a terminal
|
||||
func RunningInTerminal() bool {
|
||||
return term.IsTerminal(int(os.Stdin.Fd()))
|
||||
}
|
||||
225
pkg/segment/segment_test.go
Normal file
225
pkg/segment/segment_test.go
Normal file
@@ -0,0 +1,225 @@
|
||||
package segment
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"os/user"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/openshift/odo/pkg/testingutil/filesystem"
|
||||
|
||||
"github.com/openshift/odo/pkg/log"
|
||||
"github.com/openshift/odo/pkg/preference"
|
||||
"github.com/openshift/odo/pkg/version"
|
||||
)
|
||||
|
||||
type segmentResponse struct {
|
||||
Batch []struct {
|
||||
AnonymousID string `json:"anonymousId"`
|
||||
MessageId string `json:"messageId"`
|
||||
Traits struct {
|
||||
OS string `json:"os"`
|
||||
} `json:"traits"`
|
||||
Properties struct {
|
||||
Error string `json:"error"`
|
||||
ErrorType string `json:"error-type"`
|
||||
Success bool `json:"success"`
|
||||
Version string `json:"version"`
|
||||
} `json:"properties"`
|
||||
Type string `json:"type"`
|
||||
} `json:"batch"`
|
||||
MessageID string `json:"messageId"`
|
||||
}
|
||||
|
||||
func mockServer() (chan []byte, *httptest.Server) {
|
||||
done := make(chan []byte, 1)
|
||||
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
defer r.Body.Close()
|
||||
bin, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return
|
||||
}
|
||||
done <- bin
|
||||
}))
|
||||
return done, server
|
||||
}
|
||||
|
||||
func TestClientUploadWithoutConsent(t *testing.T) {
|
||||
body, server := mockServer()
|
||||
defer server.Close()
|
||||
defer close(body)
|
||||
falseValue := false
|
||||
|
||||
cfg := &preference.PreferenceInfo{
|
||||
Preference: preference.Preference{
|
||||
OdoSettings: preference.OdoSettings{
|
||||
ConsentTelemetry: &falseValue,
|
||||
},
|
||||
},
|
||||
}
|
||||
c, err := newCustomClient(cfg, createConfigDir(t), server.URL)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
// run a command, odo preference view
|
||||
if err = c.Upload("odo preference view", time.Second, errors.New("an error occurred")); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if err = c.Close(); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
select {
|
||||
case <-body:
|
||||
t.Error("server should not receive data")
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
func TestClientUploadWithConsent(t *testing.T) {
|
||||
body, server := mockServer()
|
||||
defer server.Close()
|
||||
defer close(body)
|
||||
|
||||
trueValue := true
|
||||
|
||||
cfg := &preference.PreferenceInfo{
|
||||
Preference: preference.Preference{
|
||||
OdoSettings: preference.OdoSettings{
|
||||
ConsentTelemetry: &trueValue,
|
||||
},
|
||||
},
|
||||
}
|
||||
tests := []struct {
|
||||
cmd string
|
||||
testName string
|
||||
err error
|
||||
success bool
|
||||
errType string
|
||||
}{
|
||||
{
|
||||
testName: "command ran successfully",
|
||||
err: nil,
|
||||
success: true,
|
||||
errType: "",
|
||||
},
|
||||
{
|
||||
testName: "command failed",
|
||||
err: errors.New("some error occurred"),
|
||||
success: false,
|
||||
errType: "*errors.errorString",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Log("Running test: ", tt.testName)
|
||||
t.Run(tt.testName, func(t *testing.T) {
|
||||
c, err := newCustomClient(cfg, createConfigDir(t), server.URL)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
// upload the data to Segment
|
||||
if err := c.Upload("odo create", time.Second, tt.err); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if err := c.Close(); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
select {
|
||||
case x := <-body:
|
||||
s := segmentResponse{}
|
||||
if err := json.Unmarshal(x, &s); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
// Response returns 2 Batches in response - 1) identify - user's system information,
|
||||
// and 2) track - information about the fired command
|
||||
// This checks if both the responses were received
|
||||
if s.Batch[0].Type != "identify" && s.Batch[1].Type != "track" {
|
||||
t.Errorf("Missing Identify or Track information.\nIdentify: %v\nTrack:%v", s.Batch[0].Type, s.Batch[1].Type)
|
||||
}
|
||||
if s.Batch[0].Traits.OS != runtime.GOOS {
|
||||
t.Error("OS does not match")
|
||||
}
|
||||
if !tt.success {
|
||||
if s.Batch[1].Properties.Error != tt.err.Error() {
|
||||
t.Error("Error does not match")
|
||||
}
|
||||
} else {
|
||||
if s.Batch[1].Properties.Error != "" {
|
||||
t.Error("Error does not match")
|
||||
}
|
||||
}
|
||||
if s.Batch[1].Properties.Success != tt.success {
|
||||
t.Error("Success does not match")
|
||||
}
|
||||
if s.Batch[1].Properties.ErrorType != tt.errType {
|
||||
t.Error("Error Type does not match")
|
||||
}
|
||||
if !strings.Contains(s.Batch[1].Properties.Version, version.VERSION) {
|
||||
t.Error("Odo version does not match")
|
||||
}
|
||||
|
||||
default:
|
||||
t.Error("Server should receive data")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetError(t *testing.T) {
|
||||
user, err := user.Current()
|
||||
if err != nil {
|
||||
t.Error(err.Error())
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
err error
|
||||
hasPII bool
|
||||
}{
|
||||
{
|
||||
name: "error without PII information",
|
||||
err: errors.New("this is an error string"),
|
||||
hasPII: false,
|
||||
},
|
||||
{
|
||||
name: "error with PII information",
|
||||
err: fmt.Errorf("cannot access the preference file '/home/%s/.odo/preference.yaml'", user.Username),
|
||||
hasPII: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
got := SetError(tt.err)
|
||||
|
||||
// if error has PII, string returned by SetError must not be the same as the error since it was sanitized
|
||||
// else it will be the same.
|
||||
if (tt.hasPII && got == tt.err.Error()) || (!tt.hasPII && got != tt.err.Error()) {
|
||||
if tt.hasPII && strings.Contains(got, user.Username) {
|
||||
t.Error("PII was not sanitized properly.")
|
||||
} else {
|
||||
t.Errorf("got: %s, want: %s", got, tt.err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// createConfigDir creates a mock filesystem
|
||||
func createConfigDir(t *testing.T) string {
|
||||
fs := filesystem.NewFakeFs()
|
||||
configDir, err := fs.TempDir(os.TempDir(), "telemetry")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
return configDir
|
||||
}
|
||||
@@ -13,6 +13,8 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/openshift/odo/pkg/preference"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/onsi/gomega/gexec"
|
||||
@@ -294,7 +296,10 @@ func CommonBeforeEach() CommonVar {
|
||||
commonVar.Project = commonVar.CliRunner.CreateRandNamespaceProject()
|
||||
commonVar.OriginalWorkingDirectory = Getwd()
|
||||
os.Setenv("GLOBALODOCONFIG", filepath.Join(commonVar.Context, "preference.yaml"))
|
||||
|
||||
// Set ConsentTelemetry to false so that it does not prompt to set a preference value
|
||||
cfg, _ := preference.New()
|
||||
err := cfg.SetConfiguration(preference.ConsentTelemetrySetting, "false")
|
||||
Expect(err).To(BeNil())
|
||||
return commonVar
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,8 @@ import (
|
||||
"github.com/tidwall/gjson"
|
||||
)
|
||||
|
||||
const promtMessageSubString = "Help odo improve by allowing it to collect usage data."
|
||||
|
||||
var _ = Describe("odo preference and config command tests", func() {
|
||||
// TODO: A neater way to provide odo path. Currently we assume \
|
||||
// odo and oc in $PATH already.
|
||||
@@ -53,6 +55,17 @@ var _ = Describe("odo preference and config command tests", func() {
|
||||
})
|
||||
|
||||
Context("When viewing global config", func() {
|
||||
var newContext string
|
||||
// ConsentTelemetry is set to false in helper.CommonBeforeEach so that it does not prompt to set a value
|
||||
// during the tests, but we want to check preference values as they would be in real time and hence
|
||||
// we set the GLOBALODOCONFIG variable to a value in new context
|
||||
var _ = JustBeforeEach(func() {
|
||||
newContext = helper.CreateNewContext()
|
||||
os.Setenv("GLOBALODOCONFIG", filepath.Join(newContext, "preference.yaml"))
|
||||
})
|
||||
var _ = JustAfterEach(func() {
|
||||
helper.DeleteDir(newContext)
|
||||
})
|
||||
It("should get the default global config keys", func() {
|
||||
configOutput := helper.CmdShouldPass("odo", "preference", "view")
|
||||
preferences := []string{"UpdateNotification", "NamePrefix", "Timeout", "PushTarget", "BuildTimeout", "PushTimeout", "Experimental", "Ephemeral", "ConsentTelemetry"}
|
||||
@@ -325,4 +338,44 @@ var _ = Describe("odo preference and config command tests", func() {
|
||||
Expect(ok).To(BeFalse())
|
||||
})
|
||||
})
|
||||
|
||||
Context("When no ConsentTelemetry preference value is set", func() {
|
||||
var _ = JustBeforeEach(func() {
|
||||
// unset the preference in case it is already set
|
||||
helper.CmdShouldPass("odo", "preference", "unset", "ConsentTelemetry", "-f")
|
||||
})
|
||||
It("prompt should not appear when user calls for help", func() {
|
||||
output := helper.CmdShouldPass("odo", "create", "--help")
|
||||
Expect(output).ToNot(ContainSubstring(promtMessageSubString))
|
||||
})
|
||||
|
||||
It("prompt should not appear when preference command is run", func() {
|
||||
output := helper.CmdShouldPass("odo", "preference", "view")
|
||||
Expect(output).ToNot(ContainSubstring(promtMessageSubString))
|
||||
|
||||
output = helper.CmdShouldPass("odo", "preference", "set", "buildtimeout", "5", "-f")
|
||||
Expect(output).ToNot(ContainSubstring(promtMessageSubString))
|
||||
|
||||
output = helper.CmdShouldPass("odo", "preference", "unset", "buildtimeout", "-f")
|
||||
Expect(output).ToNot(ContainSubstring(promtMessageSubString))
|
||||
})
|
||||
It("prompt should appear when non-preference command is run", func() {
|
||||
output := helper.CmdShouldPass("odo", "create", "nodejs", "--context", commonVar.Context)
|
||||
Expect(output).To(ContainSubstring(promtMessageSubString))
|
||||
})
|
||||
})
|
||||
|
||||
Context("Prompt should not appear when", func() {
|
||||
It("ConsentTelemetry is set to true", func() {
|
||||
helper.CmdShouldPass("odo", "preference", "set", "ConsentTelemetry", "true", "-f")
|
||||
output := helper.CmdShouldPass("odo", "create", "nodejs", "--context", commonVar.Context)
|
||||
Expect(output).ToNot(ContainSubstring(promtMessageSubString))
|
||||
})
|
||||
It("ConsentTelemetry is set to false", func() {
|
||||
helper.CmdShouldPass("odo", "preference", "set", "ConsentTelemetry", "false", "-f")
|
||||
output := helper.CmdShouldPass("odo", "create", "nodejs", "--context", commonVar.Context)
|
||||
Expect(output).ToNot(ContainSubstring(promtMessageSubString))
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
@@ -1,40 +1,29 @@
|
||||
package devfile
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/openshift/odo/tests/helper"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
)
|
||||
|
||||
var _ = Describe("odo devfile app command tests", func() {
|
||||
|
||||
var namespace, context, currentWorkingDirectory, originalKubeconfig string
|
||||
|
||||
// Using program command according to cliRunner in devfile
|
||||
cliRunner := helper.GetCliRunner()
|
||||
var namespace string
|
||||
var commonVar helper.CommonVar
|
||||
|
||||
// This is run before every Spec (It)
|
||||
var _ = BeforeEach(func() {
|
||||
SetDefaultEventuallyTimeout(10 * time.Minute)
|
||||
context = helper.CreateNewContext()
|
||||
os.Setenv("GLOBALODOCONFIG", filepath.Join(context, "config.yaml"))
|
||||
originalKubeconfig = os.Getenv("KUBECONFIG")
|
||||
helper.LocalKubeconfigSet(context)
|
||||
namespace = cliRunner.CreateRandNamespaceProject()
|
||||
currentWorkingDirectory = helper.Getwd()
|
||||
commonVar = helper.CommonBeforeEach()
|
||||
helper.Chdir(commonVar.Context)
|
||||
namespace = commonVar.Project
|
||||
})
|
||||
|
||||
// This is run after every Spec (It)
|
||||
var _ = AfterEach(func() {
|
||||
cliRunner.DeleteNamespaceProject(namespace)
|
||||
helper.Chdir(currentWorkingDirectory)
|
||||
err := os.Setenv("KUBECONFIG", originalKubeconfig)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
helper.DeleteDir(context)
|
||||
os.Unsetenv("GLOBALODOCONFIG")
|
||||
helper.CommonAfterEach(commonVar)
|
||||
})
|
||||
|
||||
Context("listing apps", func() {
|
||||
|
||||
@@ -129,7 +129,7 @@ var _ = Describe("odo devfile create command tests", func() {
|
||||
It("should successfully create the devfile component and show json output for non connected cluster", func() {
|
||||
helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile.yaml"), filepath.Join(devfilePath))
|
||||
cmd := helper.Cmd("odo", "create", "nodejs", "--context", newContext, "-o", "json")
|
||||
output := cmd.WithEnv("KUBECONFIG=/no/such/path").ShouldPass().Out()
|
||||
output := cmd.WithEnv("KUBECONFIG=/no/such/path", "GLOBALODOCONFIG="+os.Getenv("GLOBALODOCONFIG")).ShouldPass().Out()
|
||||
values := gjson.GetMany(output, "kind", "metadata.name", "status.state")
|
||||
Expect(helper.GjsonMatcher(values, []string{"Component", "nodejs", "Unknown"})).To(Equal(true))
|
||||
})
|
||||
@@ -153,7 +153,7 @@ var _ = Describe("odo devfile create command tests", func() {
|
||||
|
||||
helper.CopyExampleDevFile(filepath.Join("source", "devfiles", "nodejs", "devfile.yaml"), filepath.Join(devfilePath))
|
||||
cmd := helper.Cmd("odo", "create", "nodejs", "--context", newContext, "-o", "json")
|
||||
output := cmd.WithEnv("KUBECONFIG=" + newKubeConfigPath).ShouldPass().Out()
|
||||
output := cmd.WithEnv("KUBECONFIG="+newKubeConfigPath, "GLOBALODOCONFIG="+os.Getenv("GLOBALODOCONFIG")).ShouldPass().Out()
|
||||
values := gjson.GetMany(output, "kind", "metadata.name", "status.state")
|
||||
Expect(helper.GjsonMatcher(values, []string{"Component", "nodejs", "Unknown"})).To(Equal(true))
|
||||
|
||||
|
||||
@@ -98,7 +98,7 @@ var _ = Describe("odo devfile describe command tests", func() {
|
||||
|
||||
It("should show json output for non connected cluster", func() {
|
||||
helper.CmdShouldPass("odo", "create", "nodejs", "--context", commonVar.Context)
|
||||
output := helper.Cmd("odo", "describe", "--context", commonVar.Context, "-o", "json").WithEnv("KUBECONFIG=/no/path").ShouldPass().Out()
|
||||
output := helper.Cmd("odo", "describe", "--context", commonVar.Context, "-o", "json").WithEnv("KUBECONFIG=/no/path", "GLOBALODOCONFIG="+os.Getenv("GLOBALODOCONFIG")).ShouldPass().Out()
|
||||
values := gjson.GetMany(output, "kind", "metadata.name", "status.state")
|
||||
Expect(helper.GjsonMatcher(values, []string{"Component", "nodejs", "Unknown"})).To(Equal(true))
|
||||
})
|
||||
|
||||
@@ -17,34 +17,25 @@ import (
|
||||
)
|
||||
|
||||
var _ = Describe("odo devfile status command tests", func() {
|
||||
var namespace, context, cmpName, currentWorkingDirectory, originalKubeconfig string
|
||||
|
||||
var namespace, context, cmpName string
|
||||
var commonVar helper.CommonVar
|
||||
// Using program commmand according to cliRunner in devfile
|
||||
cliRunner := helper.GetCliRunner()
|
||||
|
||||
// This is run after every Spec (It)
|
||||
var _ = BeforeEach(func() {
|
||||
commonVar = helper.CommonBeforeEach()
|
||||
SetDefaultEventuallyTimeout(5 * time.Minute)
|
||||
context = helper.CreateNewContext()
|
||||
os.Setenv("GLOBALODOCONFIG", filepath.Join(context, "config.yaml"))
|
||||
|
||||
originalKubeconfig = os.Getenv("KUBECONFIG")
|
||||
helper.LocalKubeconfigSet(context)
|
||||
namespace = cliRunner.CreateRandNamespaceProject()
|
||||
currentWorkingDirectory = helper.Getwd()
|
||||
cmpName = helper.RandString(6)
|
||||
helper.Chdir(context)
|
||||
namespace = commonVar.Project
|
||||
context = commonVar.Context
|
||||
helper.Chdir(commonVar.Context)
|
||||
})
|
||||
|
||||
// Clean up after the test
|
||||
// This is run after every Spec (It)
|
||||
var _ = AfterEach(func() {
|
||||
cliRunner.DeleteNamespaceProject(namespace)
|
||||
helper.Chdir(currentWorkingDirectory)
|
||||
err := os.Setenv("KUBECONFIG", originalKubeconfig)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
helper.DeleteDir(context)
|
||||
os.Unsetenv("GLOBALODOCONFIG")
|
||||
helper.CommonAfterEach(commonVar)
|
||||
})
|
||||
|
||||
Context("Verify devfile status works", func() {
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
@@ -16,17 +15,20 @@ import (
|
||||
|
||||
var _ = Describe("odo service command tests for OperatorHub", func() {
|
||||
|
||||
var commonVar helper.CommonVar
|
||||
var project string
|
||||
var oc helper.OcRunner
|
||||
|
||||
BeforeEach(func() {
|
||||
SetDefaultEventuallyTimeout(10 * time.Minute)
|
||||
SetDefaultConsistentlyDuration(30 * time.Second)
|
||||
// TODO: remove this when OperatorHub integration is fully baked into odo
|
||||
// helper.CmdShouldPass("odo", "preference", "set", "Experimental", "true")
|
||||
commonVar = helper.CommonBeforeEach()
|
||||
helper.Chdir(commonVar.Context)
|
||||
oc = helper.NewOcRunner("oc")
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
helper.CommonAfterEach(commonVar)
|
||||
})
|
||||
|
||||
preSetup := func() {
|
||||
project = helper.CreateRandProject()
|
||||
helper.CmdShouldPass("odo", "project", "set", project)
|
||||
|
||||
9
vendor/github.com/google/uuid/.travis.yml
generated
vendored
Normal file
9
vendor/github.com/google/uuid/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.4.3
|
||||
- 1.5.3
|
||||
- tip
|
||||
|
||||
script:
|
||||
- go test -v ./...
|
||||
10
vendor/github.com/google/uuid/CONTRIBUTING.md
generated
vendored
Normal file
10
vendor/github.com/google/uuid/CONTRIBUTING.md
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
# How to contribute
|
||||
|
||||
We definitely welcome patches and contribution to this project!
|
||||
|
||||
### Legal requirements
|
||||
|
||||
In order to protect both you and ourselves, you will need to sign the
|
||||
[Contributor License Agreement](https://cla.developers.google.com/clas).
|
||||
|
||||
You may have already signed it for other Google projects.
|
||||
9
vendor/github.com/google/uuid/CONTRIBUTORS
generated
vendored
Normal file
9
vendor/github.com/google/uuid/CONTRIBUTORS
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
Paul Borman <borman@google.com>
|
||||
bmatsuo
|
||||
shawnps
|
||||
theory
|
||||
jboverfelt
|
||||
dsymonds
|
||||
cd1
|
||||
wallclockbuilder
|
||||
dansouza
|
||||
27
vendor/github.com/google/uuid/LICENSE
generated
vendored
Normal file
27
vendor/github.com/google/uuid/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
Copyright (c) 2009,2014 Google Inc. 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.
|
||||
19
vendor/github.com/google/uuid/README.md
generated
vendored
Normal file
19
vendor/github.com/google/uuid/README.md
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
# uuid 
|
||||
The uuid package generates and inspects UUIDs based on
|
||||
[RFC 4122](http://tools.ietf.org/html/rfc4122)
|
||||
and DCE 1.1: Authentication and Security Services.
|
||||
|
||||
This package is based on the github.com/pborman/uuid package (previously named
|
||||
code.google.com/p/go-uuid). It differs from these earlier packages in that
|
||||
a UUID is a 16 byte array rather than a byte slice. One loss due to this
|
||||
change is the ability to represent an invalid UUID (vs a NIL UUID).
|
||||
|
||||
###### Install
|
||||
`go get github.com/google/uuid`
|
||||
|
||||
###### Documentation
|
||||
[](http://godoc.org/github.com/google/uuid)
|
||||
|
||||
Full `go doc` style documentation for the package can be viewed online without
|
||||
installing this package by using the GoDoc site here:
|
||||
http://godoc.org/github.com/google/uuid
|
||||
80
vendor/github.com/google/uuid/dce.go
generated
vendored
Normal file
80
vendor/github.com/google/uuid/dce.go
generated
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
// Copyright 2016 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
// A Domain represents a Version 2 domain
|
||||
type Domain byte
|
||||
|
||||
// Domain constants for DCE Security (Version 2) UUIDs.
|
||||
const (
|
||||
Person = Domain(0)
|
||||
Group = Domain(1)
|
||||
Org = Domain(2)
|
||||
)
|
||||
|
||||
// NewDCESecurity returns a DCE Security (Version 2) UUID.
|
||||
//
|
||||
// The domain should be one of Person, Group or Org.
|
||||
// On a POSIX system the id should be the users UID for the Person
|
||||
// domain and the users GID for the Group. The meaning of id for
|
||||
// the domain Org or on non-POSIX systems is site defined.
|
||||
//
|
||||
// For a given domain/id pair the same token may be returned for up to
|
||||
// 7 minutes and 10 seconds.
|
||||
func NewDCESecurity(domain Domain, id uint32) (UUID, error) {
|
||||
uuid, err := NewUUID()
|
||||
if err == nil {
|
||||
uuid[6] = (uuid[6] & 0x0f) | 0x20 // Version 2
|
||||
uuid[9] = byte(domain)
|
||||
binary.BigEndian.PutUint32(uuid[0:], id)
|
||||
}
|
||||
return uuid, err
|
||||
}
|
||||
|
||||
// NewDCEPerson returns a DCE Security (Version 2) UUID in the person
|
||||
// domain with the id returned by os.Getuid.
|
||||
//
|
||||
// NewDCESecurity(Person, uint32(os.Getuid()))
|
||||
func NewDCEPerson() (UUID, error) {
|
||||
return NewDCESecurity(Person, uint32(os.Getuid()))
|
||||
}
|
||||
|
||||
// NewDCEGroup returns a DCE Security (Version 2) UUID in the group
|
||||
// domain with the id returned by os.Getgid.
|
||||
//
|
||||
// NewDCESecurity(Group, uint32(os.Getgid()))
|
||||
func NewDCEGroup() (UUID, error) {
|
||||
return NewDCESecurity(Group, uint32(os.Getgid()))
|
||||
}
|
||||
|
||||
// Domain returns the domain for a Version 2 UUID. Domains are only defined
|
||||
// for Version 2 UUIDs.
|
||||
func (uuid UUID) Domain() Domain {
|
||||
return Domain(uuid[9])
|
||||
}
|
||||
|
||||
// ID returns the id for a Version 2 UUID. IDs are only defined for Version 2
|
||||
// UUIDs.
|
||||
func (uuid UUID) ID() uint32 {
|
||||
return binary.BigEndian.Uint32(uuid[0:4])
|
||||
}
|
||||
|
||||
func (d Domain) String() string {
|
||||
switch d {
|
||||
case Person:
|
||||
return "Person"
|
||||
case Group:
|
||||
return "Group"
|
||||
case Org:
|
||||
return "Org"
|
||||
}
|
||||
return fmt.Sprintf("Domain%d", int(d))
|
||||
}
|
||||
12
vendor/github.com/google/uuid/doc.go
generated
vendored
Normal file
12
vendor/github.com/google/uuid/doc.go
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
// Copyright 2016 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package uuid generates and inspects UUIDs.
|
||||
//
|
||||
// UUIDs are based on RFC 4122 and DCE 1.1: Authentication and Security
|
||||
// Services.
|
||||
//
|
||||
// A UUID is a 16 byte (128 bit) array. UUIDs may be used as keys to
|
||||
// maps or compared directly.
|
||||
package uuid
|
||||
1
vendor/github.com/google/uuid/go.mod
generated
vendored
Normal file
1
vendor/github.com/google/uuid/go.mod
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module github.com/google/uuid
|
||||
53
vendor/github.com/google/uuid/hash.go
generated
vendored
Normal file
53
vendor/github.com/google/uuid/hash.go
generated
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
// Copyright 2016 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"crypto/sha1"
|
||||
"hash"
|
||||
)
|
||||
|
||||
// Well known namespace IDs and UUIDs
|
||||
var (
|
||||
NameSpaceDNS = Must(Parse("6ba7b810-9dad-11d1-80b4-00c04fd430c8"))
|
||||
NameSpaceURL = Must(Parse("6ba7b811-9dad-11d1-80b4-00c04fd430c8"))
|
||||
NameSpaceOID = Must(Parse("6ba7b812-9dad-11d1-80b4-00c04fd430c8"))
|
||||
NameSpaceX500 = Must(Parse("6ba7b814-9dad-11d1-80b4-00c04fd430c8"))
|
||||
Nil UUID // empty UUID, all zeros
|
||||
)
|
||||
|
||||
// NewHash returns a new UUID derived from the hash of space concatenated with
|
||||
// data generated by h. The hash should be at least 16 byte in length. The
|
||||
// first 16 bytes of the hash are used to form the UUID. The version of the
|
||||
// UUID will be the lower 4 bits of version. NewHash is used to implement
|
||||
// NewMD5 and NewSHA1.
|
||||
func NewHash(h hash.Hash, space UUID, data []byte, version int) UUID {
|
||||
h.Reset()
|
||||
h.Write(space[:])
|
||||
h.Write(data)
|
||||
s := h.Sum(nil)
|
||||
var uuid UUID
|
||||
copy(uuid[:], s)
|
||||
uuid[6] = (uuid[6] & 0x0f) | uint8((version&0xf)<<4)
|
||||
uuid[8] = (uuid[8] & 0x3f) | 0x80 // RFC 4122 variant
|
||||
return uuid
|
||||
}
|
||||
|
||||
// NewMD5 returns a new MD5 (Version 3) UUID based on the
|
||||
// supplied name space and data. It is the same as calling:
|
||||
//
|
||||
// NewHash(md5.New(), space, data, 3)
|
||||
func NewMD5(space UUID, data []byte) UUID {
|
||||
return NewHash(md5.New(), space, data, 3)
|
||||
}
|
||||
|
||||
// NewSHA1 returns a new SHA1 (Version 5) UUID based on the
|
||||
// supplied name space and data. It is the same as calling:
|
||||
//
|
||||
// NewHash(sha1.New(), space, data, 5)
|
||||
func NewSHA1(space UUID, data []byte) UUID {
|
||||
return NewHash(sha1.New(), space, data, 5)
|
||||
}
|
||||
37
vendor/github.com/google/uuid/marshal.go
generated
vendored
Normal file
37
vendor/github.com/google/uuid/marshal.go
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
// Copyright 2016 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import "fmt"
|
||||
|
||||
// MarshalText implements encoding.TextMarshaler.
|
||||
func (uuid UUID) MarshalText() ([]byte, error) {
|
||||
var js [36]byte
|
||||
encodeHex(js[:], uuid)
|
||||
return js[:], nil
|
||||
}
|
||||
|
||||
// UnmarshalText implements encoding.TextUnmarshaler.
|
||||
func (uuid *UUID) UnmarshalText(data []byte) error {
|
||||
id, err := ParseBytes(data)
|
||||
if err == nil {
|
||||
*uuid = id
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// MarshalBinary implements encoding.BinaryMarshaler.
|
||||
func (uuid UUID) MarshalBinary() ([]byte, error) {
|
||||
return uuid[:], nil
|
||||
}
|
||||
|
||||
// UnmarshalBinary implements encoding.BinaryUnmarshaler.
|
||||
func (uuid *UUID) UnmarshalBinary(data []byte) error {
|
||||
if len(data) != 16 {
|
||||
return fmt.Errorf("invalid UUID (got %d bytes)", len(data))
|
||||
}
|
||||
copy(uuid[:], data)
|
||||
return nil
|
||||
}
|
||||
90
vendor/github.com/google/uuid/node.go
generated
vendored
Normal file
90
vendor/github.com/google/uuid/node.go
generated
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
// Copyright 2016 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
nodeMu sync.Mutex
|
||||
ifname string // name of interface being used
|
||||
nodeID [6]byte // hardware for version 1 UUIDs
|
||||
zeroID [6]byte // nodeID with only 0's
|
||||
)
|
||||
|
||||
// NodeInterface returns the name of the interface from which the NodeID was
|
||||
// derived. The interface "user" is returned if the NodeID was set by
|
||||
// SetNodeID.
|
||||
func NodeInterface() string {
|
||||
defer nodeMu.Unlock()
|
||||
nodeMu.Lock()
|
||||
return ifname
|
||||
}
|
||||
|
||||
// SetNodeInterface selects the hardware address to be used for Version 1 UUIDs.
|
||||
// If name is "" then the first usable interface found will be used or a random
|
||||
// Node ID will be generated. If a named interface cannot be found then false
|
||||
// is returned.
|
||||
//
|
||||
// SetNodeInterface never fails when name is "".
|
||||
func SetNodeInterface(name string) bool {
|
||||
defer nodeMu.Unlock()
|
||||
nodeMu.Lock()
|
||||
return setNodeInterface(name)
|
||||
}
|
||||
|
||||
func setNodeInterface(name string) bool {
|
||||
iname, addr := getHardwareInterface(name) // null implementation for js
|
||||
if iname != "" && addr != nil {
|
||||
ifname = iname
|
||||
copy(nodeID[:], addr)
|
||||
return true
|
||||
}
|
||||
|
||||
// We found no interfaces with a valid hardware address. If name
|
||||
// does not specify a specific interface generate a random Node ID
|
||||
// (section 4.1.6)
|
||||
if name == "" {
|
||||
ifname = "random"
|
||||
randomBits(nodeID[:])
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// NodeID returns a slice of a copy of the current Node ID, setting the Node ID
|
||||
// if not already set.
|
||||
func NodeID() []byte {
|
||||
defer nodeMu.Unlock()
|
||||
nodeMu.Lock()
|
||||
if nodeID == zeroID {
|
||||
setNodeInterface("")
|
||||
}
|
||||
nid := nodeID
|
||||
return nid[:]
|
||||
}
|
||||
|
||||
// SetNodeID sets the Node ID to be used for Version 1 UUIDs. The first 6 bytes
|
||||
// of id are used. If id is less than 6 bytes then false is returned and the
|
||||
// Node ID is not set.
|
||||
func SetNodeID(id []byte) bool {
|
||||
if len(id) < 6 {
|
||||
return false
|
||||
}
|
||||
defer nodeMu.Unlock()
|
||||
nodeMu.Lock()
|
||||
copy(nodeID[:], id)
|
||||
ifname = "user"
|
||||
return true
|
||||
}
|
||||
|
||||
// NodeID returns the 6 byte node id encoded in uuid. It returns nil if uuid is
|
||||
// not valid. The NodeID is only well defined for version 1 and 2 UUIDs.
|
||||
func (uuid UUID) NodeID() []byte {
|
||||
var node [6]byte
|
||||
copy(node[:], uuid[10:])
|
||||
return node[:]
|
||||
}
|
||||
12
vendor/github.com/google/uuid/node_js.go
generated
vendored
Normal file
12
vendor/github.com/google/uuid/node_js.go
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
// Copyright 2017 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build js
|
||||
|
||||
package uuid
|
||||
|
||||
// getHardwareInterface returns nil values for the JS version of the code.
|
||||
// This remvoves the "net" dependency, because it is not used in the browser.
|
||||
// Using the "net" library inflates the size of the transpiled JS code by 673k bytes.
|
||||
func getHardwareInterface(name string) (string, []byte) { return "", nil }
|
||||
33
vendor/github.com/google/uuid/node_net.go
generated
vendored
Normal file
33
vendor/github.com/google/uuid/node_net.go
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
// Copyright 2017 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !js
|
||||
|
||||
package uuid
|
||||
|
||||
import "net"
|
||||
|
||||
var interfaces []net.Interface // cached list of interfaces
|
||||
|
||||
// getHardwareInterface returns the name and hardware address of interface name.
|
||||
// If name is "" then the name and hardware address of one of the system's
|
||||
// interfaces is returned. If no interfaces are found (name does not exist or
|
||||
// there are no interfaces) then "", nil is returned.
|
||||
//
|
||||
// Only addresses of at least 6 bytes are returned.
|
||||
func getHardwareInterface(name string) (string, []byte) {
|
||||
if interfaces == nil {
|
||||
var err error
|
||||
interfaces, err = net.Interfaces()
|
||||
if err != nil {
|
||||
return "", nil
|
||||
}
|
||||
}
|
||||
for _, ifs := range interfaces {
|
||||
if len(ifs.HardwareAddr) >= 6 && (name == "" || name == ifs.Name) {
|
||||
return ifs.Name, ifs.HardwareAddr
|
||||
}
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
59
vendor/github.com/google/uuid/sql.go
generated
vendored
Normal file
59
vendor/github.com/google/uuid/sql.go
generated
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
// Copyright 2016 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Scan implements sql.Scanner so UUIDs can be read from databases transparently
|
||||
// Currently, database types that map to string and []byte are supported. Please
|
||||
// consult database-specific driver documentation for matching types.
|
||||
func (uuid *UUID) Scan(src interface{}) error {
|
||||
switch src := src.(type) {
|
||||
case nil:
|
||||
return nil
|
||||
|
||||
case string:
|
||||
// if an empty UUID comes from a table, we return a null UUID
|
||||
if src == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
// see Parse for required string format
|
||||
u, err := Parse(src)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Scan: %v", err)
|
||||
}
|
||||
|
||||
*uuid = u
|
||||
|
||||
case []byte:
|
||||
// if an empty UUID comes from a table, we return a null UUID
|
||||
if len(src) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// assumes a simple slice of bytes if 16 bytes
|
||||
// otherwise attempts to parse
|
||||
if len(src) != 16 {
|
||||
return uuid.Scan(string(src))
|
||||
}
|
||||
copy((*uuid)[:], src)
|
||||
|
||||
default:
|
||||
return fmt.Errorf("Scan: unable to scan type %T into UUID", src)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Value implements sql.Valuer so that UUIDs can be written to databases
|
||||
// transparently. Currently, UUIDs map to strings. Please consult
|
||||
// database-specific driver documentation for matching types.
|
||||
func (uuid UUID) Value() (driver.Value, error) {
|
||||
return uuid.String(), nil
|
||||
}
|
||||
123
vendor/github.com/google/uuid/time.go
generated
vendored
Normal file
123
vendor/github.com/google/uuid/time.go
generated
vendored
Normal file
@@ -0,0 +1,123 @@
|
||||
// Copyright 2016 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// A Time represents a time as the number of 100's of nanoseconds since 15 Oct
|
||||
// 1582.
|
||||
type Time int64
|
||||
|
||||
const (
|
||||
lillian = 2299160 // Julian day of 15 Oct 1582
|
||||
unix = 2440587 // Julian day of 1 Jan 1970
|
||||
epoch = unix - lillian // Days between epochs
|
||||
g1582 = epoch * 86400 // seconds between epochs
|
||||
g1582ns100 = g1582 * 10000000 // 100s of a nanoseconds between epochs
|
||||
)
|
||||
|
||||
var (
|
||||
timeMu sync.Mutex
|
||||
lasttime uint64 // last time we returned
|
||||
clockSeq uint16 // clock sequence for this run
|
||||
|
||||
timeNow = time.Now // for testing
|
||||
)
|
||||
|
||||
// UnixTime converts t the number of seconds and nanoseconds using the Unix
|
||||
// epoch of 1 Jan 1970.
|
||||
func (t Time) UnixTime() (sec, nsec int64) {
|
||||
sec = int64(t - g1582ns100)
|
||||
nsec = (sec % 10000000) * 100
|
||||
sec /= 10000000
|
||||
return sec, nsec
|
||||
}
|
||||
|
||||
// GetTime returns the current Time (100s of nanoseconds since 15 Oct 1582) and
|
||||
// clock sequence as well as adjusting the clock sequence as needed. An error
|
||||
// is returned if the current time cannot be determined.
|
||||
func GetTime() (Time, uint16, error) {
|
||||
defer timeMu.Unlock()
|
||||
timeMu.Lock()
|
||||
return getTime()
|
||||
}
|
||||
|
||||
func getTime() (Time, uint16, error) {
|
||||
t := timeNow()
|
||||
|
||||
// If we don't have a clock sequence already, set one.
|
||||
if clockSeq == 0 {
|
||||
setClockSequence(-1)
|
||||
}
|
||||
now := uint64(t.UnixNano()/100) + g1582ns100
|
||||
|
||||
// If time has gone backwards with this clock sequence then we
|
||||
// increment the clock sequence
|
||||
if now <= lasttime {
|
||||
clockSeq = ((clockSeq + 1) & 0x3fff) | 0x8000
|
||||
}
|
||||
lasttime = now
|
||||
return Time(now), clockSeq, nil
|
||||
}
|
||||
|
||||
// ClockSequence returns the current clock sequence, generating one if not
|
||||
// already set. The clock sequence is only used for Version 1 UUIDs.
|
||||
//
|
||||
// The uuid package does not use global static storage for the clock sequence or
|
||||
// the last time a UUID was generated. Unless SetClockSequence is used, a new
|
||||
// random clock sequence is generated the first time a clock sequence is
|
||||
// requested by ClockSequence, GetTime, or NewUUID. (section 4.2.1.1)
|
||||
func ClockSequence() int {
|
||||
defer timeMu.Unlock()
|
||||
timeMu.Lock()
|
||||
return clockSequence()
|
||||
}
|
||||
|
||||
func clockSequence() int {
|
||||
if clockSeq == 0 {
|
||||
setClockSequence(-1)
|
||||
}
|
||||
return int(clockSeq & 0x3fff)
|
||||
}
|
||||
|
||||
// SetClockSequence sets the clock sequence to the lower 14 bits of seq. Setting to
|
||||
// -1 causes a new sequence to be generated.
|
||||
func SetClockSequence(seq int) {
|
||||
defer timeMu.Unlock()
|
||||
timeMu.Lock()
|
||||
setClockSequence(seq)
|
||||
}
|
||||
|
||||
func setClockSequence(seq int) {
|
||||
if seq == -1 {
|
||||
var b [2]byte
|
||||
randomBits(b[:]) // clock sequence
|
||||
seq = int(b[0])<<8 | int(b[1])
|
||||
}
|
||||
oldSeq := clockSeq
|
||||
clockSeq = uint16(seq&0x3fff) | 0x8000 // Set our variant
|
||||
if oldSeq != clockSeq {
|
||||
lasttime = 0
|
||||
}
|
||||
}
|
||||
|
||||
// Time returns the time in 100s of nanoseconds since 15 Oct 1582 encoded in
|
||||
// uuid. The time is only defined for version 1 and 2 UUIDs.
|
||||
func (uuid UUID) Time() Time {
|
||||
time := int64(binary.BigEndian.Uint32(uuid[0:4]))
|
||||
time |= int64(binary.BigEndian.Uint16(uuid[4:6])) << 32
|
||||
time |= int64(binary.BigEndian.Uint16(uuid[6:8])&0xfff) << 48
|
||||
return Time(time)
|
||||
}
|
||||
|
||||
// ClockSequence returns the clock sequence encoded in uuid.
|
||||
// The clock sequence is only well defined for version 1 and 2 UUIDs.
|
||||
func (uuid UUID) ClockSequence() int {
|
||||
return int(binary.BigEndian.Uint16(uuid[8:10])) & 0x3fff
|
||||
}
|
||||
43
vendor/github.com/google/uuid/util.go
generated
vendored
Normal file
43
vendor/github.com/google/uuid/util.go
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
// Copyright 2016 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"io"
|
||||
)
|
||||
|
||||
// randomBits completely fills slice b with random data.
|
||||
func randomBits(b []byte) {
|
||||
if _, err := io.ReadFull(rander, b); err != nil {
|
||||
panic(err.Error()) // rand should never fail
|
||||
}
|
||||
}
|
||||
|
||||
// xvalues returns the value of a byte as a hexadecimal digit or 255.
|
||||
var xvalues = [256]byte{
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255,
|
||||
255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
}
|
||||
|
||||
// xtob converts hex characters x1 and x2 into a byte.
|
||||
func xtob(x1, x2 byte) (byte, bool) {
|
||||
b1 := xvalues[x1]
|
||||
b2 := xvalues[x2]
|
||||
return (b1 << 4) | b2, b1 != 255 && b2 != 255
|
||||
}
|
||||
245
vendor/github.com/google/uuid/uuid.go
generated
vendored
Normal file
245
vendor/github.com/google/uuid/uuid.go
generated
vendored
Normal file
@@ -0,0 +1,245 @@
|
||||
// Copyright 2018 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// A UUID is a 128 bit (16 byte) Universal Unique IDentifier as defined in RFC
|
||||
// 4122.
|
||||
type UUID [16]byte
|
||||
|
||||
// A Version represents a UUID's version.
|
||||
type Version byte
|
||||
|
||||
// A Variant represents a UUID's variant.
|
||||
type Variant byte
|
||||
|
||||
// Constants returned by Variant.
|
||||
const (
|
||||
Invalid = Variant(iota) // Invalid UUID
|
||||
RFC4122 // The variant specified in RFC4122
|
||||
Reserved // Reserved, NCS backward compatibility.
|
||||
Microsoft // Reserved, Microsoft Corporation backward compatibility.
|
||||
Future // Reserved for future definition.
|
||||
)
|
||||
|
||||
var rander = rand.Reader // random function
|
||||
|
||||
// Parse decodes s into a UUID or returns an error. Both the standard UUID
|
||||
// forms of xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and
|
||||
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx are decoded as well as the
|
||||
// Microsoft encoding {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} and the raw hex
|
||||
// encoding: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.
|
||||
func Parse(s string) (UUID, error) {
|
||||
var uuid UUID
|
||||
switch len(s) {
|
||||
// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||
case 36:
|
||||
|
||||
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||
case 36 + 9:
|
||||
if strings.ToLower(s[:9]) != "urn:uuid:" {
|
||||
return uuid, fmt.Errorf("invalid urn prefix: %q", s[:9])
|
||||
}
|
||||
s = s[9:]
|
||||
|
||||
// {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
|
||||
case 36 + 2:
|
||||
s = s[1:]
|
||||
|
||||
// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
case 32:
|
||||
var ok bool
|
||||
for i := range uuid {
|
||||
uuid[i], ok = xtob(s[i*2], s[i*2+1])
|
||||
if !ok {
|
||||
return uuid, errors.New("invalid UUID format")
|
||||
}
|
||||
}
|
||||
return uuid, nil
|
||||
default:
|
||||
return uuid, fmt.Errorf("invalid UUID length: %d", len(s))
|
||||
}
|
||||
// s is now at least 36 bytes long
|
||||
// it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||
if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' {
|
||||
return uuid, errors.New("invalid UUID format")
|
||||
}
|
||||
for i, x := range [16]int{
|
||||
0, 2, 4, 6,
|
||||
9, 11,
|
||||
14, 16,
|
||||
19, 21,
|
||||
24, 26, 28, 30, 32, 34} {
|
||||
v, ok := xtob(s[x], s[x+1])
|
||||
if !ok {
|
||||
return uuid, errors.New("invalid UUID format")
|
||||
}
|
||||
uuid[i] = v
|
||||
}
|
||||
return uuid, nil
|
||||
}
|
||||
|
||||
// ParseBytes is like Parse, except it parses a byte slice instead of a string.
|
||||
func ParseBytes(b []byte) (UUID, error) {
|
||||
var uuid UUID
|
||||
switch len(b) {
|
||||
case 36: // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||
case 36 + 9: // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||
if !bytes.Equal(bytes.ToLower(b[:9]), []byte("urn:uuid:")) {
|
||||
return uuid, fmt.Errorf("invalid urn prefix: %q", b[:9])
|
||||
}
|
||||
b = b[9:]
|
||||
case 36 + 2: // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
|
||||
b = b[1:]
|
||||
case 32: // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
var ok bool
|
||||
for i := 0; i < 32; i += 2 {
|
||||
uuid[i/2], ok = xtob(b[i], b[i+1])
|
||||
if !ok {
|
||||
return uuid, errors.New("invalid UUID format")
|
||||
}
|
||||
}
|
||||
return uuid, nil
|
||||
default:
|
||||
return uuid, fmt.Errorf("invalid UUID length: %d", len(b))
|
||||
}
|
||||
// s is now at least 36 bytes long
|
||||
// it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||
if b[8] != '-' || b[13] != '-' || b[18] != '-' || b[23] != '-' {
|
||||
return uuid, errors.New("invalid UUID format")
|
||||
}
|
||||
for i, x := range [16]int{
|
||||
0, 2, 4, 6,
|
||||
9, 11,
|
||||
14, 16,
|
||||
19, 21,
|
||||
24, 26, 28, 30, 32, 34} {
|
||||
v, ok := xtob(b[x], b[x+1])
|
||||
if !ok {
|
||||
return uuid, errors.New("invalid UUID format")
|
||||
}
|
||||
uuid[i] = v
|
||||
}
|
||||
return uuid, nil
|
||||
}
|
||||
|
||||
// MustParse is like Parse but panics if the string cannot be parsed.
|
||||
// It simplifies safe initialization of global variables holding compiled UUIDs.
|
||||
func MustParse(s string) UUID {
|
||||
uuid, err := Parse(s)
|
||||
if err != nil {
|
||||
panic(`uuid: Parse(` + s + `): ` + err.Error())
|
||||
}
|
||||
return uuid
|
||||
}
|
||||
|
||||
// FromBytes creates a new UUID from a byte slice. Returns an error if the slice
|
||||
// does not have a length of 16. The bytes are copied from the slice.
|
||||
func FromBytes(b []byte) (uuid UUID, err error) {
|
||||
err = uuid.UnmarshalBinary(b)
|
||||
return uuid, err
|
||||
}
|
||||
|
||||
// Must returns uuid if err is nil and panics otherwise.
|
||||
func Must(uuid UUID, err error) UUID {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return uuid
|
||||
}
|
||||
|
||||
// String returns the string form of uuid, xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||
// , or "" if uuid is invalid.
|
||||
func (uuid UUID) String() string {
|
||||
var buf [36]byte
|
||||
encodeHex(buf[:], uuid)
|
||||
return string(buf[:])
|
||||
}
|
||||
|
||||
// URN returns the RFC 2141 URN form of uuid,
|
||||
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, or "" if uuid is invalid.
|
||||
func (uuid UUID) URN() string {
|
||||
var buf [36 + 9]byte
|
||||
copy(buf[:], "urn:uuid:")
|
||||
encodeHex(buf[9:], uuid)
|
||||
return string(buf[:])
|
||||
}
|
||||
|
||||
func encodeHex(dst []byte, uuid UUID) {
|
||||
hex.Encode(dst, uuid[:4])
|
||||
dst[8] = '-'
|
||||
hex.Encode(dst[9:13], uuid[4:6])
|
||||
dst[13] = '-'
|
||||
hex.Encode(dst[14:18], uuid[6:8])
|
||||
dst[18] = '-'
|
||||
hex.Encode(dst[19:23], uuid[8:10])
|
||||
dst[23] = '-'
|
||||
hex.Encode(dst[24:], uuid[10:])
|
||||
}
|
||||
|
||||
// Variant returns the variant encoded in uuid.
|
||||
func (uuid UUID) Variant() Variant {
|
||||
switch {
|
||||
case (uuid[8] & 0xc0) == 0x80:
|
||||
return RFC4122
|
||||
case (uuid[8] & 0xe0) == 0xc0:
|
||||
return Microsoft
|
||||
case (uuid[8] & 0xe0) == 0xe0:
|
||||
return Future
|
||||
default:
|
||||
return Reserved
|
||||
}
|
||||
}
|
||||
|
||||
// Version returns the version of uuid.
|
||||
func (uuid UUID) Version() Version {
|
||||
return Version(uuid[6] >> 4)
|
||||
}
|
||||
|
||||
func (v Version) String() string {
|
||||
if v > 15 {
|
||||
return fmt.Sprintf("BAD_VERSION_%d", v)
|
||||
}
|
||||
return fmt.Sprintf("VERSION_%d", v)
|
||||
}
|
||||
|
||||
func (v Variant) String() string {
|
||||
switch v {
|
||||
case RFC4122:
|
||||
return "RFC4122"
|
||||
case Reserved:
|
||||
return "Reserved"
|
||||
case Microsoft:
|
||||
return "Microsoft"
|
||||
case Future:
|
||||
return "Future"
|
||||
case Invalid:
|
||||
return "Invalid"
|
||||
}
|
||||
return fmt.Sprintf("BadVariant%d", int(v))
|
||||
}
|
||||
|
||||
// SetRand sets the random number generator to r, which implements io.Reader.
|
||||
// If r.Read returns an error when the package requests random data then
|
||||
// a panic will be issued.
|
||||
//
|
||||
// Calling SetRand with nil sets the random number generator to the default
|
||||
// generator.
|
||||
func SetRand(r io.Reader) {
|
||||
if r == nil {
|
||||
rander = rand.Reader
|
||||
return
|
||||
}
|
||||
rander = r
|
||||
}
|
||||
44
vendor/github.com/google/uuid/version1.go
generated
vendored
Normal file
44
vendor/github.com/google/uuid/version1.go
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
// Copyright 2016 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
)
|
||||
|
||||
// NewUUID returns a Version 1 UUID based on the current NodeID and clock
|
||||
// sequence, and the current time. If the NodeID has not been set by SetNodeID
|
||||
// or SetNodeInterface then it will be set automatically. If the NodeID cannot
|
||||
// be set NewUUID returns nil. If clock sequence has not been set by
|
||||
// SetClockSequence then it will be set automatically. If GetTime fails to
|
||||
// return the current NewUUID returns nil and an error.
|
||||
//
|
||||
// In most cases, New should be used.
|
||||
func NewUUID() (UUID, error) {
|
||||
nodeMu.Lock()
|
||||
if nodeID == zeroID {
|
||||
setNodeInterface("")
|
||||
}
|
||||
nodeMu.Unlock()
|
||||
|
||||
var uuid UUID
|
||||
now, seq, err := GetTime()
|
||||
if err != nil {
|
||||
return uuid, err
|
||||
}
|
||||
|
||||
timeLow := uint32(now & 0xffffffff)
|
||||
timeMid := uint16((now >> 32) & 0xffff)
|
||||
timeHi := uint16((now >> 48) & 0x0fff)
|
||||
timeHi |= 0x1000 // Version 1
|
||||
|
||||
binary.BigEndian.PutUint32(uuid[0:], timeLow)
|
||||
binary.BigEndian.PutUint16(uuid[4:], timeMid)
|
||||
binary.BigEndian.PutUint16(uuid[6:], timeHi)
|
||||
binary.BigEndian.PutUint16(uuid[8:], seq)
|
||||
copy(uuid[10:], nodeID[:])
|
||||
|
||||
return uuid, nil
|
||||
}
|
||||
38
vendor/github.com/google/uuid/version4.go
generated
vendored
Normal file
38
vendor/github.com/google/uuid/version4.go
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
// Copyright 2016 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import "io"
|
||||
|
||||
// New creates a new random UUID or panics. New is equivalent to
|
||||
// the expression
|
||||
//
|
||||
// uuid.Must(uuid.NewRandom())
|
||||
func New() UUID {
|
||||
return Must(NewRandom())
|
||||
}
|
||||
|
||||
// NewRandom returns a Random (Version 4) UUID.
|
||||
//
|
||||
// The strength of the UUIDs is based on the strength of the crypto/rand
|
||||
// package.
|
||||
//
|
||||
// A note about uniqueness derived from the UUID Wikipedia entry:
|
||||
//
|
||||
// Randomly generated UUIDs have 122 random bits. One's annual risk of being
|
||||
// hit by a meteorite is estimated to be one chance in 17 billion, that
|
||||
// means the probability is about 0.00000000006 (6 × 10−11),
|
||||
// equivalent to the odds of creating a few tens of trillions of UUIDs in a
|
||||
// year and having one duplicate.
|
||||
func NewRandom() (UUID, error) {
|
||||
var uuid UUID
|
||||
_, err := io.ReadFull(rander, uuid[:])
|
||||
if err != nil {
|
||||
return Nil, err
|
||||
}
|
||||
uuid[6] = (uuid[6] & 0x0f) | 0x40 // Version 4
|
||||
uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10
|
||||
return uuid, nil
|
||||
}
|
||||
2
vendor/github.com/gosimple/slug/.gitignore
generated
vendored
2
vendor/github.com/gosimple/slug/.gitignore
generated
vendored
@@ -1,2 +0,0 @@
|
||||
_*
|
||||
cover*.out
|
||||
20
vendor/github.com/gosimple/slug/.travis.yml
generated
vendored
20
vendor/github.com/gosimple/slug/.travis.yml
generated
vendored
@@ -1,20 +0,0 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- "1.x"
|
||||
- master
|
||||
matrix:
|
||||
allow_failures:
|
||||
- go: master
|
||||
fast_finish: true
|
||||
|
||||
before_script:
|
||||
- go get -t -v ./...
|
||||
- go get -v golang.org/x/lint/golint
|
||||
- go get -v honnef.co/go/tools/cmd/staticcheck
|
||||
- go vet ./...
|
||||
script:
|
||||
# run all our tests with race detector
|
||||
- go test -v -race ./...
|
||||
# "go vet on steroids" + linter
|
||||
- staticcheck ./...
|
||||
373
vendor/github.com/gosimple/slug/LICENSE
generated
vendored
373
vendor/github.com/gosimple/slug/LICENSE
generated
vendored
@@ -1,373 +0,0 @@
|
||||
Mozilla Public License Version 2.0
|
||||
==================================
|
||||
|
||||
1. Definitions
|
||||
--------------
|
||||
|
||||
1.1. "Contributor"
|
||||
means each individual or legal entity that creates, contributes to
|
||||
the creation of, or owns Covered Software.
|
||||
|
||||
1.2. "Contributor Version"
|
||||
means the combination of the Contributions of others (if any) used
|
||||
by a Contributor and that particular Contributor's Contribution.
|
||||
|
||||
1.3. "Contribution"
|
||||
means Covered Software of a particular Contributor.
|
||||
|
||||
1.4. "Covered Software"
|
||||
means Source Code Form to which the initial Contributor has attached
|
||||
the notice in Exhibit A, the Executable Form of such Source Code
|
||||
Form, and Modifications of such Source Code Form, in each case
|
||||
including portions thereof.
|
||||
|
||||
1.5. "Incompatible With Secondary Licenses"
|
||||
means
|
||||
|
||||
(a) that the initial Contributor has attached the notice described
|
||||
in Exhibit B to the Covered Software; or
|
||||
|
||||
(b) that the Covered Software was made available under the terms of
|
||||
version 1.1 or earlier of the License, but not also under the
|
||||
terms of a Secondary License.
|
||||
|
||||
1.6. "Executable Form"
|
||||
means any form of the work other than Source Code Form.
|
||||
|
||||
1.7. "Larger Work"
|
||||
means a work that combines Covered Software with other material, in
|
||||
a separate file or files, that is not Covered Software.
|
||||
|
||||
1.8. "License"
|
||||
means this document.
|
||||
|
||||
1.9. "Licensable"
|
||||
means having the right to grant, to the maximum extent possible,
|
||||
whether at the time of the initial grant or subsequently, any and
|
||||
all of the rights conveyed by this License.
|
||||
|
||||
1.10. "Modifications"
|
||||
means any of the following:
|
||||
|
||||
(a) any file in Source Code Form that results from an addition to,
|
||||
deletion from, or modification of the contents of Covered
|
||||
Software; or
|
||||
|
||||
(b) any new file in Source Code Form that contains any Covered
|
||||
Software.
|
||||
|
||||
1.11. "Patent Claims" of a Contributor
|
||||
means any patent claim(s), including without limitation, method,
|
||||
process, and apparatus claims, in any patent Licensable by such
|
||||
Contributor that would be infringed, but for the grant of the
|
||||
License, by the making, using, selling, offering for sale, having
|
||||
made, import, or transfer of either its Contributions or its
|
||||
Contributor Version.
|
||||
|
||||
1.12. "Secondary License"
|
||||
means either the GNU General Public License, Version 2.0, the GNU
|
||||
Lesser General Public License, Version 2.1, the GNU Affero General
|
||||
Public License, Version 3.0, or any later versions of those
|
||||
licenses.
|
||||
|
||||
1.13. "Source Code Form"
|
||||
means the form of the work preferred for making modifications.
|
||||
|
||||
1.14. "You" (or "Your")
|
||||
means an individual or a legal entity exercising rights under this
|
||||
License. For legal entities, "You" includes any entity that
|
||||
controls, is controlled by, or is under common control with You. For
|
||||
purposes of this definition, "control" means (a) the power, direct
|
||||
or indirect, to cause the direction or management of such entity,
|
||||
whether by contract or otherwise, or (b) ownership of more than
|
||||
fifty percent (50%) of the outstanding shares or beneficial
|
||||
ownership of such entity.
|
||||
|
||||
2. License Grants and Conditions
|
||||
--------------------------------
|
||||
|
||||
2.1. Grants
|
||||
|
||||
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||
non-exclusive license:
|
||||
|
||||
(a) under intellectual property rights (other than patent or trademark)
|
||||
Licensable by such Contributor to use, reproduce, make available,
|
||||
modify, display, perform, distribute, and otherwise exploit its
|
||||
Contributions, either on an unmodified basis, with Modifications, or
|
||||
as part of a Larger Work; and
|
||||
|
||||
(b) under Patent Claims of such Contributor to make, use, sell, offer
|
||||
for sale, have made, import, and otherwise transfer either its
|
||||
Contributions or its Contributor Version.
|
||||
|
||||
2.2. Effective Date
|
||||
|
||||
The licenses granted in Section 2.1 with respect to any Contribution
|
||||
become effective for each Contribution on the date the Contributor first
|
||||
distributes such Contribution.
|
||||
|
||||
2.3. Limitations on Grant Scope
|
||||
|
||||
The licenses granted in this Section 2 are the only rights granted under
|
||||
this License. No additional rights or licenses will be implied from the
|
||||
distribution or licensing of Covered Software under this License.
|
||||
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||
Contributor:
|
||||
|
||||
(a) for any code that a Contributor has removed from Covered Software;
|
||||
or
|
||||
|
||||
(b) for infringements caused by: (i) Your and any other third party's
|
||||
modifications of Covered Software, or (ii) the combination of its
|
||||
Contributions with other software (except as part of its Contributor
|
||||
Version); or
|
||||
|
||||
(c) under Patent Claims infringed by Covered Software in the absence of
|
||||
its Contributions.
|
||||
|
||||
This License does not grant any rights in the trademarks, service marks,
|
||||
or logos of any Contributor (except as may be necessary to comply with
|
||||
the notice requirements in Section 3.4).
|
||||
|
||||
2.4. Subsequent Licenses
|
||||
|
||||
No Contributor makes additional grants as a result of Your choice to
|
||||
distribute the Covered Software under a subsequent version of this
|
||||
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||
permitted under the terms of Section 3.3).
|
||||
|
||||
2.5. Representation
|
||||
|
||||
Each Contributor represents that the Contributor believes its
|
||||
Contributions are its original creation(s) or it has sufficient rights
|
||||
to grant the rights to its Contributions conveyed by this License.
|
||||
|
||||
2.6. Fair Use
|
||||
|
||||
This License is not intended to limit any rights You have under
|
||||
applicable copyright doctrines of fair use, fair dealing, or other
|
||||
equivalents.
|
||||
|
||||
2.7. Conditions
|
||||
|
||||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
|
||||
in Section 2.1.
|
||||
|
||||
3. Responsibilities
|
||||
-------------------
|
||||
|
||||
3.1. Distribution of Source Form
|
||||
|
||||
All distribution of Covered Software in Source Code Form, including any
|
||||
Modifications that You create or to which You contribute, must be under
|
||||
the terms of this License. You must inform recipients that the Source
|
||||
Code Form of the Covered Software is governed by the terms of this
|
||||
License, and how they can obtain a copy of this License. You may not
|
||||
attempt to alter or restrict the recipients' rights in the Source Code
|
||||
Form.
|
||||
|
||||
3.2. Distribution of Executable Form
|
||||
|
||||
If You distribute Covered Software in Executable Form then:
|
||||
|
||||
(a) such Covered Software must also be made available in Source Code
|
||||
Form, as described in Section 3.1, and You must inform recipients of
|
||||
the Executable Form how they can obtain a copy of such Source Code
|
||||
Form by reasonable means in a timely manner, at a charge no more
|
||||
than the cost of distribution to the recipient; and
|
||||
|
||||
(b) You may distribute such Executable Form under the terms of this
|
||||
License, or sublicense it under different terms, provided that the
|
||||
license for the Executable Form does not attempt to limit or alter
|
||||
the recipients' rights in the Source Code Form under this License.
|
||||
|
||||
3.3. Distribution of a Larger Work
|
||||
|
||||
You may create and distribute a Larger Work under terms of Your choice,
|
||||
provided that You also comply with the requirements of this License for
|
||||
the Covered Software. If the Larger Work is a combination of Covered
|
||||
Software with a work governed by one or more Secondary Licenses, and the
|
||||
Covered Software is not Incompatible With Secondary Licenses, this
|
||||
License permits You to additionally distribute such Covered Software
|
||||
under the terms of such Secondary License(s), so that the recipient of
|
||||
the Larger Work may, at their option, further distribute the Covered
|
||||
Software under the terms of either this License or such Secondary
|
||||
License(s).
|
||||
|
||||
3.4. Notices
|
||||
|
||||
You may not remove or alter the substance of any license notices
|
||||
(including copyright notices, patent notices, disclaimers of warranty,
|
||||
or limitations of liability) contained within the Source Code Form of
|
||||
the Covered Software, except that You may alter any license notices to
|
||||
the extent required to remedy known factual inaccuracies.
|
||||
|
||||
3.5. Application of Additional Terms
|
||||
|
||||
You may choose to offer, and to charge a fee for, warranty, support,
|
||||
indemnity or liability obligations to one or more recipients of Covered
|
||||
Software. However, You may do so only on Your own behalf, and not on
|
||||
behalf of any Contributor. You must make it absolutely clear that any
|
||||
such warranty, support, indemnity, or liability obligation is offered by
|
||||
You alone, and You hereby agree to indemnify every Contributor for any
|
||||
liability incurred by such Contributor as a result of warranty, support,
|
||||
indemnity or liability terms You offer. You may include additional
|
||||
disclaimers of warranty and limitations of liability specific to any
|
||||
jurisdiction.
|
||||
|
||||
4. Inability to Comply Due to Statute or Regulation
|
||||
---------------------------------------------------
|
||||
|
||||
If it is impossible for You to comply with any of the terms of this
|
||||
License with respect to some or all of the Covered Software due to
|
||||
statute, judicial order, or regulation then You must: (a) comply with
|
||||
the terms of this License to the maximum extent possible; and (b)
|
||||
describe the limitations and the code they affect. Such description must
|
||||
be placed in a text file included with all distributions of the Covered
|
||||
Software under this License. Except to the extent prohibited by statute
|
||||
or regulation, such description must be sufficiently detailed for a
|
||||
recipient of ordinary skill to be able to understand it.
|
||||
|
||||
5. Termination
|
||||
--------------
|
||||
|
||||
5.1. The rights granted under this License will terminate automatically
|
||||
if You fail to comply with any of its terms. However, if You become
|
||||
compliant, then the rights granted under this License from a particular
|
||||
Contributor are reinstated (a) provisionally, unless and until such
|
||||
Contributor explicitly and finally terminates Your grants, and (b) on an
|
||||
ongoing basis, if such Contributor fails to notify You of the
|
||||
non-compliance by some reasonable means prior to 60 days after You have
|
||||
come back into compliance. Moreover, Your grants from a particular
|
||||
Contributor are reinstated on an ongoing basis if such Contributor
|
||||
notifies You of the non-compliance by some reasonable means, this is the
|
||||
first time You have received notice of non-compliance with this License
|
||||
from such Contributor, and You become compliant prior to 30 days after
|
||||
Your receipt of the notice.
|
||||
|
||||
5.2. If You initiate litigation against any entity by asserting a patent
|
||||
infringement claim (excluding declaratory judgment actions,
|
||||
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||
directly or indirectly infringes any patent, then the rights granted to
|
||||
You by any and all Contributors for the Covered Software under Section
|
||||
2.1 of this License shall terminate.
|
||||
|
||||
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
|
||||
end user license agreements (excluding distributors and resellers) which
|
||||
have been validly granted by You or Your distributors under this License
|
||||
prior to termination shall survive termination.
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 6. Disclaimer of Warranty *
|
||||
* ------------------------- *
|
||||
* *
|
||||
* Covered Software is provided under this License on an "as is" *
|
||||
* basis, without warranty of any kind, either expressed, implied, or *
|
||||
* statutory, including, without limitation, warranties that the *
|
||||
* Covered Software is free of defects, merchantable, fit for a *
|
||||
* particular purpose or non-infringing. The entire risk as to the *
|
||||
* quality and performance of the Covered Software is with You. *
|
||||
* Should any Covered Software prove defective in any respect, You *
|
||||
* (not any Contributor) assume the cost of any necessary servicing, *
|
||||
* repair, or correction. This disclaimer of warranty constitutes an *
|
||||
* essential part of this License. No use of any Covered Software is *
|
||||
* authorized under this License except under this disclaimer. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 7. Limitation of Liability *
|
||||
* -------------------------- *
|
||||
* *
|
||||
* Under no circumstances and under no legal theory, whether tort *
|
||||
* (including negligence), contract, or otherwise, shall any *
|
||||
* Contributor, or anyone who distributes Covered Software as *
|
||||
* permitted above, be liable to You for any direct, indirect, *
|
||||
* special, incidental, or consequential damages of any character *
|
||||
* including, without limitation, damages for lost profits, loss of *
|
||||
* goodwill, work stoppage, computer failure or malfunction, or any *
|
||||
* and all other commercial damages or losses, even if such party *
|
||||
* shall have been informed of the possibility of such damages. This *
|
||||
* limitation of liability shall not apply to liability for death or *
|
||||
* personal injury resulting from such party's negligence to the *
|
||||
* extent applicable law prohibits such limitation. Some *
|
||||
* jurisdictions do not allow the exclusion or limitation of *
|
||||
* incidental or consequential damages, so this exclusion and *
|
||||
* limitation may not apply to You. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
8. Litigation
|
||||
-------------
|
||||
|
||||
Any litigation relating to this License may be brought only in the
|
||||
courts of a jurisdiction where the defendant maintains its principal
|
||||
place of business and such litigation shall be governed by laws of that
|
||||
jurisdiction, without reference to its conflict-of-law provisions.
|
||||
Nothing in this Section shall prevent a party's ability to bring
|
||||
cross-claims or counter-claims.
|
||||
|
||||
9. Miscellaneous
|
||||
----------------
|
||||
|
||||
This License represents the complete agreement concerning the subject
|
||||
matter hereof. If any provision of this License is held to be
|
||||
unenforceable, such provision shall be reformed only to the extent
|
||||
necessary to make it enforceable. Any law or regulation which provides
|
||||
that the language of a contract shall be construed against the drafter
|
||||
shall not be used to construe this License against a Contributor.
|
||||
|
||||
10. Versions of the License
|
||||
---------------------------
|
||||
|
||||
10.1. New Versions
|
||||
|
||||
Mozilla Foundation is the license steward. Except as provided in Section
|
||||
10.3, no one other than the license steward has the right to modify or
|
||||
publish new versions of this License. Each version will be given a
|
||||
distinguishing version number.
|
||||
|
||||
10.2. Effect of New Versions
|
||||
|
||||
You may distribute the Covered Software under the terms of the version
|
||||
of the License under which You originally received the Covered Software,
|
||||
or under the terms of any subsequent version published by the license
|
||||
steward.
|
||||
|
||||
10.3. Modified Versions
|
||||
|
||||
If you create software not governed by this License, and you want to
|
||||
create a new license for such software, you may create and use a
|
||||
modified version of this License if you rename the license and remove
|
||||
any references to the name of the license steward (except to note that
|
||||
such modified license differs from this License).
|
||||
|
||||
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||
Licenses
|
||||
|
||||
If You choose to distribute Source Code Form that is Incompatible With
|
||||
Secondary Licenses under the terms of this version of the License, the
|
||||
notice described in Exhibit B of this License must be attached.
|
||||
|
||||
Exhibit A - Source Code Form License Notice
|
||||
-------------------------------------------
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular
|
||||
file, then You may include the notice in a location (such as a LICENSE
|
||||
file in a relevant directory) where a recipient would be likely to look
|
||||
for such a notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
|
||||
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||
---------------------------------------------------------
|
||||
|
||||
This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
defined by the Mozilla Public License, v. 2.0.
|
||||
62
vendor/github.com/gosimple/slug/README.md
generated
vendored
62
vendor/github.com/gosimple/slug/README.md
generated
vendored
@@ -1,62 +0,0 @@
|
||||
slug
|
||||
====
|
||||
|
||||
Package `slug` generate slug from unicode string, URL-friendly slugify with
|
||||
multiple languages support.
|
||||
|
||||
[](https://godoc.org/github.com/gosimple/slug)
|
||||
[](https://travis-ci.com/gosimple/slug)
|
||||
|
||||
[Documentation online](http://godoc.org/github.com/gosimple/slug)
|
||||
|
||||
## Example
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gosimple/slug"
|
||||
)
|
||||
|
||||
func main() {
|
||||
text := slug.Make("Hellö Wörld хелло ворлд")
|
||||
fmt.Println(text) // Will print: "hello-world-khello-vorld"
|
||||
|
||||
someText := slug.Make("影師")
|
||||
fmt.Println(someText) // Will print: "ying-shi"
|
||||
|
||||
enText := slug.MakeLang("This & that", "en")
|
||||
fmt.Println(enText) // Will print: "this-and-that"
|
||||
|
||||
deText := slug.MakeLang("Diese & Dass", "de")
|
||||
fmt.Println(deText) // Will print: "diese-und-dass"
|
||||
|
||||
slug.Lowercase = false // Keep uppercase characters
|
||||
deUppercaseText := slug.MakeLang("Diese & Dass", "de")
|
||||
fmt.Println(deUppercaseText) // Will print: "Diese-und-Dass"
|
||||
|
||||
slug.CustomSub = map[string]string{
|
||||
"water": "sand",
|
||||
}
|
||||
textSub := slug.Make("water is hot")
|
||||
fmt.Println(textSub) // Will print: "sand-is-hot"
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### Requests or bugs?
|
||||
<https://github.com/gosimple/slug/issues>
|
||||
|
||||
## Installation
|
||||
```sh
|
||||
go get -u github.com/gosimple/slug
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
The source files are distributed under the
|
||||
[Mozilla Public License, version 2.0](http://mozilla.org/MPL/2.0/),
|
||||
unless otherwise noted.
|
||||
Please read the [FAQ](http://www.mozilla.org/MPL/2.0/FAQ.html)
|
||||
if you have further questions regarding the license.
|
||||
47
vendor/github.com/gosimple/slug/doc.go
generated
vendored
47
vendor/github.com/gosimple/slug/doc.go
generated
vendored
@@ -1,47 +0,0 @@
|
||||
// Copyright 2013 by Dobrosław Żybort. All rights reserved.
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
/*
|
||||
Package slug generate slug from unicode string, URL-friendly slugify with
|
||||
multiple languages support.
|
||||
|
||||
Example:
|
||||
|
||||
package main
|
||||
|
||||
import(
|
||||
"github.com/gosimple/slug"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func main () {
|
||||
text := slug.Make("Hellö Wörld хелло ворлд")
|
||||
fmt.Println(text) // Will print: "hello-world-khello-vorld"
|
||||
|
||||
someText := slug.Make("影師")
|
||||
fmt.Println(someText) // Will print: "ying-shi"
|
||||
|
||||
enText := slug.MakeLang("This & that", "en")
|
||||
fmt.Println(enText) // Will print: "this-and-that"
|
||||
|
||||
deText := slug.MakeLang("Diese & Dass", "de")
|
||||
fmt.Println(deText) // Will print: "diese-und-dass"
|
||||
|
||||
slug.Lowercase = false // Keep uppercase characters
|
||||
deUppercaseText := slug.MakeLang("Diese & Dass", "de")
|
||||
fmt.Println(deUppercaseText) // Will print: "Diese-und-Dass"
|
||||
|
||||
slug.CustomSub = map[string]string{
|
||||
"water": "sand",
|
||||
}
|
||||
textSub := slug.Make("water is hot")
|
||||
fmt.Println(textSub) // Will print: "sand-is-hot"
|
||||
}
|
||||
|
||||
Requests or bugs?
|
||||
|
||||
https://github.com/gosimple/slug/issues
|
||||
*/
|
||||
package slug
|
||||
5
vendor/github.com/gosimple/slug/go.mod
generated
vendored
5
vendor/github.com/gosimple/slug/go.mod
generated
vendored
@@ -1,5 +0,0 @@
|
||||
module github.com/gosimple/slug
|
||||
|
||||
go 1.13
|
||||
|
||||
require github.com/rainycape/unidecode v0.0.0-20150907023854-cb7f23ec59be
|
||||
2
vendor/github.com/gosimple/slug/go.sum
generated
vendored
2
vendor/github.com/gosimple/slug/go.sum
generated
vendored
@@ -1,2 +0,0 @@
|
||||
github.com/rainycape/unidecode v0.0.0-20150907023854-cb7f23ec59be h1:ta7tUOvsPHVHGom5hKW5VXNc2xZIkfCKP8iaqOyYtUQ=
|
||||
github.com/rainycape/unidecode v0.0.0-20150907023854-cb7f23ec59be/go.mod h1:MIDFMn7db1kT65GmV94GzpX9Qdi7N/pQlwb+AN8wh+Q=
|
||||
120
vendor/github.com/gosimple/slug/languages_substitution.go
generated
vendored
120
vendor/github.com/gosimple/slug/languages_substitution.go
generated
vendored
@@ -1,120 +0,0 @@
|
||||
// Copyright 2013 by Dobrosław Żybort. All rights reserved.
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package slug
|
||||
|
||||
func init() {
|
||||
// Merge language subs with the default one.
|
||||
// TODO: Find better way so all langs are merged automatically and better
|
||||
// tested.
|
||||
for _, sub := range []*map[rune]string{
|
||||
&deSub, &enSub, &esSub, &fiSub, &grSub, &kkSub, &nlSub, &plSub, &svSub, &trSub,
|
||||
} {
|
||||
for key, value := range defaultSub {
|
||||
(*sub)[key] = value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var defaultSub = map[rune]string{
|
||||
'"': "",
|
||||
'\'': "",
|
||||
'’': "",
|
||||
'‒': "-", // figure dash
|
||||
'–': "-", // en dash
|
||||
'—': "-", // em dash
|
||||
'―': "-", // horizontal bar
|
||||
}
|
||||
|
||||
var deSub = map[rune]string{
|
||||
'&': "und",
|
||||
'@': "an",
|
||||
'ä': "ae",
|
||||
'Ä': "Ae",
|
||||
'ö': "oe",
|
||||
'Ö': "Oe",
|
||||
'ü': "ue",
|
||||
'Ü': "Ue",
|
||||
}
|
||||
|
||||
var enSub = map[rune]string{
|
||||
'&': "and",
|
||||
'@': "at",
|
||||
}
|
||||
|
||||
var esSub = map[rune]string{
|
||||
'&': "y",
|
||||
'@': "en",
|
||||
}
|
||||
|
||||
var fiSub = map[rune]string{
|
||||
'&': "ja",
|
||||
'@': "at",
|
||||
}
|
||||
|
||||
var grSub = map[rune]string{
|
||||
'&': "kai",
|
||||
'η': "i",
|
||||
'ή': "i",
|
||||
'Η': "i",
|
||||
'ι': "i",
|
||||
'ί': "i",
|
||||
'ϊ': "i",
|
||||
'Ι': "i",
|
||||
'χ': "x",
|
||||
'Χ': "x",
|
||||
'ω': "w",
|
||||
'ώ': "w",
|
||||
'Ω': "w",
|
||||
'ϋ': "u",
|
||||
}
|
||||
|
||||
var kkSub = map[rune]string{
|
||||
'&': "jane",
|
||||
'ә': "a",
|
||||
'ғ': "g",
|
||||
'қ': "q",
|
||||
'ң': "n",
|
||||
'ө': "o",
|
||||
'ұ': "u",
|
||||
'Ә': "A",
|
||||
'Ғ': "G",
|
||||
'Қ': "Q",
|
||||
'Ң': "N",
|
||||
'Ө': "O",
|
||||
'Ұ': "U",
|
||||
}
|
||||
|
||||
var nlSub = map[rune]string{
|
||||
'&': "en",
|
||||
'@': "at",
|
||||
}
|
||||
|
||||
var plSub = map[rune]string{
|
||||
'&': "i",
|
||||
'@': "na",
|
||||
}
|
||||
|
||||
var svSub = map[rune]string{
|
||||
'&': "och",
|
||||
'@': "snabel a",
|
||||
}
|
||||
|
||||
var trSub = map[rune]string{
|
||||
'&': "ve",
|
||||
'@': "et",
|
||||
'ş': "s",
|
||||
'Ş': "S",
|
||||
'ü': "u",
|
||||
'Ü': "U",
|
||||
'ö': "o",
|
||||
'Ö': "O",
|
||||
'İ': "I",
|
||||
'ı': "i",
|
||||
'ğ': "g",
|
||||
'Ğ': "G",
|
||||
'ç': "c",
|
||||
'Ç': "C",
|
||||
}
|
||||
174
vendor/github.com/gosimple/slug/slug.go
generated
vendored
174
vendor/github.com/gosimple/slug/slug.go
generated
vendored
@@ -1,174 +0,0 @@
|
||||
// Copyright 2013 by Dobrosław Żybort. All rights reserved.
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package slug
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/rainycape/unidecode"
|
||||
)
|
||||
|
||||
var (
|
||||
// CustomSub stores custom substitution map
|
||||
CustomSub map[string]string
|
||||
// CustomRuneSub stores custom rune substitution map
|
||||
CustomRuneSub map[rune]string
|
||||
|
||||
// MaxLength stores maximum slug length.
|
||||
// It's smart so it will cat slug after full word.
|
||||
// By default slugs aren't shortened.
|
||||
// If MaxLength is smaller than length of the first word, then returned
|
||||
// slug will contain only substring from the first word truncated
|
||||
// after MaxLength.
|
||||
MaxLength int
|
||||
|
||||
// Lowercase defines if the resulting slug is transformed to lowercase.
|
||||
// Default is true.
|
||||
Lowercase = true
|
||||
|
||||
regexpNonAuthorizedChars = regexp.MustCompile("[^a-zA-Z0-9-_]")
|
||||
regexpMultipleDashes = regexp.MustCompile("-+")
|
||||
)
|
||||
|
||||
//=============================================================================
|
||||
|
||||
// Make returns slug generated from provided string. Will use "en" as language
|
||||
// substitution.
|
||||
func Make(s string) (slug string) {
|
||||
return MakeLang(s, "en")
|
||||
}
|
||||
|
||||
// MakeLang returns slug generated from provided string and will use provided
|
||||
// language for chars substitution.
|
||||
func MakeLang(s string, lang string) (slug string) {
|
||||
slug = strings.TrimSpace(s)
|
||||
|
||||
// Custom substitutions
|
||||
// Always substitute runes first
|
||||
slug = SubstituteRune(slug, CustomRuneSub)
|
||||
slug = Substitute(slug, CustomSub)
|
||||
|
||||
// Process string with selected substitution language.
|
||||
// Catch ISO 3166-1, ISO 639-1:2002 and ISO 639-3:2007.
|
||||
switch strings.ToLower(lang) {
|
||||
case "de", "deu":
|
||||
slug = SubstituteRune(slug, deSub)
|
||||
case "en", "eng":
|
||||
slug = SubstituteRune(slug, enSub)
|
||||
case "es", "spa":
|
||||
slug = SubstituteRune(slug, esSub)
|
||||
case "fi", "fin":
|
||||
slug = SubstituteRune(slug, fiSub)
|
||||
case "gr", "el", "ell":
|
||||
slug = SubstituteRune(slug, grSub)
|
||||
case "kz", "kk", "kaz":
|
||||
slug = SubstituteRune(slug, kkSub)
|
||||
case "nl", "nld":
|
||||
slug = SubstituteRune(slug, nlSub)
|
||||
case "pl", "pol":
|
||||
slug = SubstituteRune(slug, plSub)
|
||||
case "sv", "swe":
|
||||
slug = SubstituteRune(slug, svSub)
|
||||
case "tr", "tur":
|
||||
slug = SubstituteRune(slug, trSub)
|
||||
default: // fallback to "en" if lang not found
|
||||
slug = SubstituteRune(slug, enSub)
|
||||
}
|
||||
|
||||
// Process all non ASCII symbols
|
||||
slug = unidecode.Unidecode(slug)
|
||||
|
||||
if Lowercase {
|
||||
slug = strings.ToLower(slug)
|
||||
}
|
||||
|
||||
// Process all remaining symbols
|
||||
slug = regexpNonAuthorizedChars.ReplaceAllString(slug, "-")
|
||||
slug = regexpMultipleDashes.ReplaceAllString(slug, "-")
|
||||
slug = strings.Trim(slug, "-_")
|
||||
|
||||
if MaxLength > 0 {
|
||||
slug = smartTruncate(slug)
|
||||
}
|
||||
|
||||
return slug
|
||||
}
|
||||
|
||||
// Substitute returns string with superseded all substrings from
|
||||
// provided substitution map. Substitution map will be applied in alphabetic
|
||||
// order. Many passes, on one substitution another one could apply.
|
||||
func Substitute(s string, sub map[string]string) (buf string) {
|
||||
buf = s
|
||||
var keys []string
|
||||
for k := range sub {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
for _, key := range keys {
|
||||
buf = strings.Replace(buf, key, sub[key], -1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// SubstituteRune substitutes string chars with provided rune
|
||||
// substitution map. One pass.
|
||||
func SubstituteRune(s string, sub map[rune]string) string {
|
||||
var buf bytes.Buffer
|
||||
for _, c := range s {
|
||||
if d, ok := sub[c]; ok {
|
||||
buf.WriteString(d)
|
||||
} else {
|
||||
buf.WriteRune(c)
|
||||
}
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func smartTruncate(text string) string {
|
||||
if len(text) < MaxLength {
|
||||
return text
|
||||
}
|
||||
|
||||
var truncated string
|
||||
words := strings.SplitAfter(text, "-")
|
||||
// If MaxLength is smaller than length of the first word return word
|
||||
// truncated after MaxLength.
|
||||
if len(words[0]) > MaxLength {
|
||||
return words[0][:MaxLength]
|
||||
}
|
||||
for _, word := range words {
|
||||
if len(truncated)+len(word)-1 <= MaxLength {
|
||||
truncated = truncated + word
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
return strings.Trim(truncated, "-")
|
||||
}
|
||||
|
||||
// IsSlug returns True if provided text does not contain white characters,
|
||||
// punctuation, all letters are lower case and only from ASCII range.
|
||||
// It could contain `-` and `_` but not at the beginning or end of the text.
|
||||
// It should be in range of the MaxLength var if specified.
|
||||
// All output from slug.Make(text) should pass this test.
|
||||
func IsSlug(text string) bool {
|
||||
if text == "" ||
|
||||
(MaxLength > 0 && len(text) > MaxLength) ||
|
||||
text[0] == '-' || text[0] == '_' ||
|
||||
text[len(text)-1] == '-' || text[len(text)-1] == '_' {
|
||||
return false
|
||||
}
|
||||
for _, c := range text {
|
||||
if (c < 'a' || c > 'z') && c != '-' && c != '_' && (c < '0' || c > '9') {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
10
vendor/github.com/pborman/uuid/.travis.yml
generated
vendored
Normal file
10
vendor/github.com/pborman/uuid/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- "1.9"
|
||||
- "1.10"
|
||||
- "1.11"
|
||||
- tip
|
||||
|
||||
script:
|
||||
- go test -v ./...
|
||||
10
vendor/github.com/pborman/uuid/CONTRIBUTING.md
generated
vendored
Normal file
10
vendor/github.com/pborman/uuid/CONTRIBUTING.md
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
# How to contribute
|
||||
|
||||
We definitely welcome patches and contribution to this project!
|
||||
|
||||
### Legal requirements
|
||||
|
||||
In order to protect both you and ourselves, you will need to sign the
|
||||
[Contributor License Agreement](https://cla.developers.google.com/clas).
|
||||
|
||||
You may have already signed it for other Google projects.
|
||||
1
vendor/github.com/pborman/uuid/CONTRIBUTORS
generated
vendored
Normal file
1
vendor/github.com/pborman/uuid/CONTRIBUTORS
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
Paul Borman <borman@google.com>
|
||||
27
vendor/github.com/pborman/uuid/LICENSE
generated
vendored
Normal file
27
vendor/github.com/pborman/uuid/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
Copyright (c) 2009,2014 Google Inc. 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.
|
||||
15
vendor/github.com/pborman/uuid/README.md
generated
vendored
Normal file
15
vendor/github.com/pborman/uuid/README.md
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
This project was automatically exported from code.google.com/p/go-uuid
|
||||
|
||||
# uuid 
|
||||
The uuid package generates and inspects UUIDs based on [RFC 4122](http://tools.ietf.org/html/rfc4122) and DCE 1.1: Authentication and Security Services.
|
||||
|
||||
This package now leverages the github.com/google/uuid package (which is based off an earlier version of this package).
|
||||
|
||||
###### Install
|
||||
`go get github.com/pborman/uuid`
|
||||
|
||||
###### Documentation
|
||||
[](http://godoc.org/github.com/pborman/uuid)
|
||||
|
||||
Full `go doc` style documentation for the package can be viewed online without installing this package by using the GoDoc site here:
|
||||
http://godoc.org/github.com/pborman/uuid
|
||||
84
vendor/github.com/pborman/uuid/dce.go
generated
vendored
Normal file
84
vendor/github.com/pborman/uuid/dce.go
generated
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
// Copyright 2011 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
// A Domain represents a Version 2 domain
|
||||
type Domain byte
|
||||
|
||||
// Domain constants for DCE Security (Version 2) UUIDs.
|
||||
const (
|
||||
Person = Domain(0)
|
||||
Group = Domain(1)
|
||||
Org = Domain(2)
|
||||
)
|
||||
|
||||
// NewDCESecurity returns a DCE Security (Version 2) UUID.
|
||||
//
|
||||
// The domain should be one of Person, Group or Org.
|
||||
// On a POSIX system the id should be the users UID for the Person
|
||||
// domain and the users GID for the Group. The meaning of id for
|
||||
// the domain Org or on non-POSIX systems is site defined.
|
||||
//
|
||||
// For a given domain/id pair the same token may be returned for up to
|
||||
// 7 minutes and 10 seconds.
|
||||
func NewDCESecurity(domain Domain, id uint32) UUID {
|
||||
uuid := NewUUID()
|
||||
if uuid != nil {
|
||||
uuid[6] = (uuid[6] & 0x0f) | 0x20 // Version 2
|
||||
uuid[9] = byte(domain)
|
||||
binary.BigEndian.PutUint32(uuid[0:], id)
|
||||
}
|
||||
return uuid
|
||||
}
|
||||
|
||||
// NewDCEPerson returns a DCE Security (Version 2) UUID in the person
|
||||
// domain with the id returned by os.Getuid.
|
||||
//
|
||||
// NewDCEPerson(Person, uint32(os.Getuid()))
|
||||
func NewDCEPerson() UUID {
|
||||
return NewDCESecurity(Person, uint32(os.Getuid()))
|
||||
}
|
||||
|
||||
// NewDCEGroup returns a DCE Security (Version 2) UUID in the group
|
||||
// domain with the id returned by os.Getgid.
|
||||
//
|
||||
// NewDCEGroup(Group, uint32(os.Getgid()))
|
||||
func NewDCEGroup() UUID {
|
||||
return NewDCESecurity(Group, uint32(os.Getgid()))
|
||||
}
|
||||
|
||||
// Domain returns the domain for a Version 2 UUID or false.
|
||||
func (uuid UUID) Domain() (Domain, bool) {
|
||||
if v, _ := uuid.Version(); v != 2 {
|
||||
return 0, false
|
||||
}
|
||||
return Domain(uuid[9]), true
|
||||
}
|
||||
|
||||
// Id returns the id for a Version 2 UUID or false.
|
||||
func (uuid UUID) Id() (uint32, bool) {
|
||||
if v, _ := uuid.Version(); v != 2 {
|
||||
return 0, false
|
||||
}
|
||||
return binary.BigEndian.Uint32(uuid[0:4]), true
|
||||
}
|
||||
|
||||
func (d Domain) String() string {
|
||||
switch d {
|
||||
case Person:
|
||||
return "Person"
|
||||
case Group:
|
||||
return "Group"
|
||||
case Org:
|
||||
return "Org"
|
||||
}
|
||||
return fmt.Sprintf("Domain%d", int(d))
|
||||
}
|
||||
13
vendor/github.com/pborman/uuid/doc.go
generated
vendored
Normal file
13
vendor/github.com/pborman/uuid/doc.go
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
// Copyright 2011 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// The uuid package generates and inspects UUIDs.
|
||||
//
|
||||
// UUIDs are based on RFC 4122 and DCE 1.1: Authentication and Security
|
||||
// Services.
|
||||
//
|
||||
// This package is a partial wrapper around the github.com/google/uuid package.
|
||||
// This package represents a UUID as []byte while github.com/google/uuid
|
||||
// represents a UUID as [16]byte.
|
||||
package uuid
|
||||
3
vendor/github.com/pborman/uuid/go.mod
generated
vendored
Normal file
3
vendor/github.com/pborman/uuid/go.mod
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
module github.com/pborman/uuid
|
||||
|
||||
require github.com/google/uuid v1.0.0
|
||||
2
vendor/github.com/pborman/uuid/go.sum
generated
vendored
Normal file
2
vendor/github.com/pborman/uuid/go.sum
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
github.com/google/uuid v1.0.0 h1:b4Gk+7WdP/d3HZH8EJsZpvV7EtDOgaZLtnaNGIu1adA=
|
||||
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
53
vendor/github.com/pborman/uuid/hash.go
generated
vendored
Normal file
53
vendor/github.com/pborman/uuid/hash.go
generated
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
// Copyright 2011 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"crypto/sha1"
|
||||
"hash"
|
||||
)
|
||||
|
||||
// Well known Name Space IDs and UUIDs
|
||||
var (
|
||||
NameSpace_DNS = Parse("6ba7b810-9dad-11d1-80b4-00c04fd430c8")
|
||||
NameSpace_URL = Parse("6ba7b811-9dad-11d1-80b4-00c04fd430c8")
|
||||
NameSpace_OID = Parse("6ba7b812-9dad-11d1-80b4-00c04fd430c8")
|
||||
NameSpace_X500 = Parse("6ba7b814-9dad-11d1-80b4-00c04fd430c8")
|
||||
NIL = Parse("00000000-0000-0000-0000-000000000000")
|
||||
)
|
||||
|
||||
// NewHash returns a new UUID derived from the hash of space concatenated with
|
||||
// data generated by h. The hash should be at least 16 byte in length. The
|
||||
// first 16 bytes of the hash are used to form the UUID. The version of the
|
||||
// UUID will be the lower 4 bits of version. NewHash is used to implement
|
||||
// NewMD5 and NewSHA1.
|
||||
func NewHash(h hash.Hash, space UUID, data []byte, version int) UUID {
|
||||
h.Reset()
|
||||
h.Write(space)
|
||||
h.Write([]byte(data))
|
||||
s := h.Sum(nil)
|
||||
uuid := make([]byte, 16)
|
||||
copy(uuid, s)
|
||||
uuid[6] = (uuid[6] & 0x0f) | uint8((version&0xf)<<4)
|
||||
uuid[8] = (uuid[8] & 0x3f) | 0x80 // RFC 4122 variant
|
||||
return uuid
|
||||
}
|
||||
|
||||
// NewMD5 returns a new MD5 (Version 3) UUID based on the
|
||||
// supplied name space and data.
|
||||
//
|
||||
// NewHash(md5.New(), space, data, 3)
|
||||
func NewMD5(space UUID, data []byte) UUID {
|
||||
return NewHash(md5.New(), space, data, 3)
|
||||
}
|
||||
|
||||
// NewSHA1 returns a new SHA1 (Version 5) UUID based on the
|
||||
// supplied name space and data.
|
||||
//
|
||||
// NewHash(sha1.New(), space, data, 5)
|
||||
func NewSHA1(space UUID, data []byte) UUID {
|
||||
return NewHash(sha1.New(), space, data, 5)
|
||||
}
|
||||
85
vendor/github.com/pborman/uuid/marshal.go
generated
vendored
Normal file
85
vendor/github.com/pborman/uuid/marshal.go
generated
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
// Copyright 2016 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
guuid "github.com/google/uuid"
|
||||
)
|
||||
|
||||
// MarshalText implements encoding.TextMarshaler.
|
||||
func (u UUID) MarshalText() ([]byte, error) {
|
||||
if len(u) != 16 {
|
||||
return nil, nil
|
||||
}
|
||||
var js [36]byte
|
||||
encodeHex(js[:], u)
|
||||
return js[:], nil
|
||||
}
|
||||
|
||||
// UnmarshalText implements encoding.TextUnmarshaler.
|
||||
func (u *UUID) UnmarshalText(data []byte) error {
|
||||
if len(data) == 0 {
|
||||
return nil
|
||||
}
|
||||
id := Parse(string(data))
|
||||
if id == nil {
|
||||
return errors.New("invalid UUID")
|
||||
}
|
||||
*u = id
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary implements encoding.BinaryMarshaler.
|
||||
func (u UUID) MarshalBinary() ([]byte, error) {
|
||||
return u[:], nil
|
||||
}
|
||||
|
||||
// UnmarshalBinary implements encoding.BinaryUnmarshaler.
|
||||
func (u *UUID) UnmarshalBinary(data []byte) error {
|
||||
if len(data) == 0 {
|
||||
return nil
|
||||
}
|
||||
if len(data) != 16 {
|
||||
return fmt.Errorf("invalid UUID (got %d bytes)", len(data))
|
||||
}
|
||||
var id [16]byte
|
||||
copy(id[:], data)
|
||||
*u = id[:]
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalText implements encoding.TextMarshaler.
|
||||
func (u Array) MarshalText() ([]byte, error) {
|
||||
var js [36]byte
|
||||
encodeHex(js[:], u[:])
|
||||
return js[:], nil
|
||||
}
|
||||
|
||||
// UnmarshalText implements encoding.TextUnmarshaler.
|
||||
func (u *Array) UnmarshalText(data []byte) error {
|
||||
id, err := guuid.ParseBytes(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*u = Array(id)
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary implements encoding.BinaryMarshaler.
|
||||
func (u Array) MarshalBinary() ([]byte, error) {
|
||||
return u[:], nil
|
||||
}
|
||||
|
||||
// UnmarshalBinary implements encoding.BinaryUnmarshaler.
|
||||
func (u *Array) UnmarshalBinary(data []byte) error {
|
||||
if len(data) != 16 {
|
||||
return fmt.Errorf("invalid UUID (got %d bytes)", len(data))
|
||||
}
|
||||
copy(u[:], data)
|
||||
return nil
|
||||
}
|
||||
50
vendor/github.com/pborman/uuid/node.go
generated
vendored
Normal file
50
vendor/github.com/pborman/uuid/node.go
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
// Copyright 2011 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import (
|
||||
guuid "github.com/google/uuid"
|
||||
)
|
||||
|
||||
// NodeInterface returns the name of the interface from which the NodeID was
|
||||
// derived. The interface "user" is returned if the NodeID was set by
|
||||
// SetNodeID.
|
||||
func NodeInterface() string {
|
||||
return guuid.NodeInterface()
|
||||
}
|
||||
|
||||
// SetNodeInterface selects the hardware address to be used for Version 1 UUIDs.
|
||||
// If name is "" then the first usable interface found will be used or a random
|
||||
// Node ID will be generated. If a named interface cannot be found then false
|
||||
// is returned.
|
||||
//
|
||||
// SetNodeInterface never fails when name is "".
|
||||
func SetNodeInterface(name string) bool {
|
||||
return guuid.SetNodeInterface(name)
|
||||
}
|
||||
|
||||
// NodeID returns a slice of a copy of the current Node ID, setting the Node ID
|
||||
// if not already set.
|
||||
func NodeID() []byte {
|
||||
return guuid.NodeID()
|
||||
}
|
||||
|
||||
// SetNodeID sets the Node ID to be used for Version 1 UUIDs. The first 6 bytes
|
||||
// of id are used. If id is less than 6 bytes then false is returned and the
|
||||
// Node ID is not set.
|
||||
func SetNodeID(id []byte) bool {
|
||||
return guuid.SetNodeID(id)
|
||||
}
|
||||
|
||||
// NodeID returns the 6 byte node id encoded in uuid. It returns nil if uuid is
|
||||
// not valid. The NodeID is only well defined for version 1 and 2 UUIDs.
|
||||
func (uuid UUID) NodeID() []byte {
|
||||
if len(uuid) != 16 {
|
||||
return nil
|
||||
}
|
||||
node := make([]byte, 6)
|
||||
copy(node, uuid[10:])
|
||||
return node
|
||||
}
|
||||
68
vendor/github.com/pborman/uuid/sql.go
generated
vendored
Normal file
68
vendor/github.com/pborman/uuid/sql.go
generated
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
// Copyright 2015 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Scan implements sql.Scanner so UUIDs can be read from databases transparently
|
||||
// Currently, database types that map to string and []byte are supported. Please
|
||||
// consult database-specific driver documentation for matching types.
|
||||
func (uuid *UUID) Scan(src interface{}) error {
|
||||
switch src.(type) {
|
||||
case string:
|
||||
// if an empty UUID comes from a table, we return a null UUID
|
||||
if src.(string) == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
// see uuid.Parse for required string format
|
||||
parsed := Parse(src.(string))
|
||||
|
||||
if parsed == nil {
|
||||
return errors.New("Scan: invalid UUID format")
|
||||
}
|
||||
|
||||
*uuid = parsed
|
||||
case []byte:
|
||||
b := src.([]byte)
|
||||
|
||||
// if an empty UUID comes from a table, we return a null UUID
|
||||
if len(b) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// assumes a simple slice of bytes if 16 bytes
|
||||
// otherwise attempts to parse
|
||||
if len(b) == 16 {
|
||||
parsed := make([]byte, 16)
|
||||
copy(parsed, b)
|
||||
*uuid = UUID(parsed)
|
||||
} else {
|
||||
u := Parse(string(b))
|
||||
|
||||
if u == nil {
|
||||
return errors.New("Scan: invalid UUID format")
|
||||
}
|
||||
|
||||
*uuid = u
|
||||
}
|
||||
|
||||
default:
|
||||
return fmt.Errorf("Scan: unable to scan type %T into UUID", src)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Value implements sql.Valuer so that UUIDs can be written to databases
|
||||
// transparently. Currently, UUIDs map to strings. Please consult
|
||||
// database-specific driver documentation for matching types.
|
||||
func (uuid UUID) Value() (driver.Value, error) {
|
||||
return uuid.String(), nil
|
||||
}
|
||||
57
vendor/github.com/pborman/uuid/time.go
generated
vendored
Normal file
57
vendor/github.com/pborman/uuid/time.go
generated
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
// Copyright 2014 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
|
||||
guuid "github.com/google/uuid"
|
||||
)
|
||||
|
||||
// A Time represents a time as the number of 100's of nanoseconds since 15 Oct
|
||||
// 1582.
|
||||
type Time = guuid.Time
|
||||
|
||||
// GetTime returns the current Time (100s of nanoseconds since 15 Oct 1582) and
|
||||
// clock sequence as well as adjusting the clock sequence as needed. An error
|
||||
// is returned if the current time cannot be determined.
|
||||
func GetTime() (Time, uint16, error) { return guuid.GetTime() }
|
||||
|
||||
// ClockSequence returns the current clock sequence, generating one if not
|
||||
// already set. The clock sequence is only used for Version 1 UUIDs.
|
||||
//
|
||||
// The uuid package does not use global static storage for the clock sequence or
|
||||
// the last time a UUID was generated. Unless SetClockSequence a new random
|
||||
// clock sequence is generated the first time a clock sequence is requested by
|
||||
// ClockSequence, GetTime, or NewUUID. (section 4.2.1.1) sequence is generated
|
||||
// for
|
||||
func ClockSequence() int { return guuid.ClockSequence() }
|
||||
|
||||
// SetClockSeq sets the clock sequence to the lower 14 bits of seq. Setting to
|
||||
// -1 causes a new sequence to be generated.
|
||||
func SetClockSequence(seq int) { guuid.SetClockSequence(seq) }
|
||||
|
||||
// Time returns the time in 100s of nanoseconds since 15 Oct 1582 encoded in
|
||||
// uuid. It returns false if uuid is not valid. The time is only well defined
|
||||
// for version 1 and 2 UUIDs.
|
||||
func (uuid UUID) Time() (Time, bool) {
|
||||
if len(uuid) != 16 {
|
||||
return 0, false
|
||||
}
|
||||
time := int64(binary.BigEndian.Uint32(uuid[0:4]))
|
||||
time |= int64(binary.BigEndian.Uint16(uuid[4:6])) << 32
|
||||
time |= int64(binary.BigEndian.Uint16(uuid[6:8])&0xfff) << 48
|
||||
return Time(time), true
|
||||
}
|
||||
|
||||
// ClockSequence returns the clock sequence encoded in uuid. It returns false
|
||||
// if uuid is not valid. The clock sequence is only well defined for version 1
|
||||
// and 2 UUIDs.
|
||||
func (uuid UUID) ClockSequence() (int, bool) {
|
||||
if len(uuid) != 16 {
|
||||
return 0, false
|
||||
}
|
||||
return int(binary.BigEndian.Uint16(uuid[8:10])) & 0x3fff, true
|
||||
}
|
||||
32
vendor/github.com/pborman/uuid/util.go
generated
vendored
Normal file
32
vendor/github.com/pborman/uuid/util.go
generated
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
// Copyright 2011 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
// xvalues returns the value of a byte as a hexadecimal digit or 255.
|
||||
var xvalues = [256]byte{
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255,
|
||||
255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
}
|
||||
|
||||
// xtob converts the the first two hex bytes of x into a byte.
|
||||
func xtob(x string) (byte, bool) {
|
||||
b1 := xvalues[x[0]]
|
||||
b2 := xvalues[x[1]]
|
||||
return (b1 << 4) | b2, b1 != 255 && b2 != 255
|
||||
}
|
||||
162
vendor/github.com/pborman/uuid/uuid.go
generated
vendored
Normal file
162
vendor/github.com/pborman/uuid/uuid.go
generated
vendored
Normal file
@@ -0,0 +1,162 @@
|
||||
// Copyright 2011 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"io"
|
||||
|
||||
guuid "github.com/google/uuid"
|
||||
)
|
||||
|
||||
// Array is a pass-by-value UUID that can be used as an effecient key in a map.
|
||||
type Array [16]byte
|
||||
|
||||
// UUID converts uuid into a slice.
|
||||
func (uuid Array) UUID() UUID {
|
||||
return uuid[:]
|
||||
}
|
||||
|
||||
// String returns the string representation of uuid,
|
||||
// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.
|
||||
func (uuid Array) String() string {
|
||||
return guuid.UUID(uuid).String()
|
||||
}
|
||||
|
||||
// A UUID is a 128 bit (16 byte) Universal Unique IDentifier as defined in RFC
|
||||
// 4122.
|
||||
type UUID []byte
|
||||
|
||||
// A Version represents a UUIDs version.
|
||||
type Version = guuid.Version
|
||||
|
||||
// A Variant represents a UUIDs variant.
|
||||
type Variant = guuid.Variant
|
||||
|
||||
// Constants returned by Variant.
|
||||
const (
|
||||
Invalid = guuid.Invalid // Invalid UUID
|
||||
RFC4122 = guuid.RFC4122 // The variant specified in RFC4122
|
||||
Reserved = guuid.Reserved // Reserved, NCS backward compatibility.
|
||||
Microsoft = guuid.Microsoft // Reserved, Microsoft Corporation backward compatibility.
|
||||
Future = guuid.Future // Reserved for future definition.
|
||||
)
|
||||
|
||||
var rander = rand.Reader // random function
|
||||
|
||||
// New returns a new random (version 4) UUID as a string. It is a convenience
|
||||
// function for NewRandom().String().
|
||||
func New() string {
|
||||
return NewRandom().String()
|
||||
}
|
||||
|
||||
// Parse decodes s into a UUID or returns nil. See github.com/google/uuid for
|
||||
// the formats parsed.
|
||||
func Parse(s string) UUID {
|
||||
gu, err := guuid.Parse(s)
|
||||
if err == nil {
|
||||
return gu[:]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ParseBytes is like Parse, except it parses a byte slice instead of a string.
|
||||
func ParseBytes(b []byte) (UUID, error) {
|
||||
gu, err := guuid.ParseBytes(b)
|
||||
if err == nil {
|
||||
return gu[:], nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Equal returns true if uuid1 and uuid2 are equal.
|
||||
func Equal(uuid1, uuid2 UUID) bool {
|
||||
return bytes.Equal(uuid1, uuid2)
|
||||
}
|
||||
|
||||
// Array returns an array representation of uuid that can be used as a map key.
|
||||
// Array panics if uuid is not valid.
|
||||
func (uuid UUID) Array() Array {
|
||||
if len(uuid) != 16 {
|
||||
panic("invalid uuid")
|
||||
}
|
||||
var a Array
|
||||
copy(a[:], uuid)
|
||||
return a
|
||||
}
|
||||
|
||||
// String returns the string form of uuid, xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||
// , or "" if uuid is invalid.
|
||||
func (uuid UUID) String() string {
|
||||
if len(uuid) != 16 {
|
||||
return ""
|
||||
}
|
||||
var buf [36]byte
|
||||
encodeHex(buf[:], uuid)
|
||||
return string(buf[:])
|
||||
}
|
||||
|
||||
// URN returns the RFC 2141 URN form of uuid,
|
||||
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, or "" if uuid is invalid.
|
||||
func (uuid UUID) URN() string {
|
||||
if len(uuid) != 16 {
|
||||
return ""
|
||||
}
|
||||
var buf [36 + 9]byte
|
||||
copy(buf[:], "urn:uuid:")
|
||||
encodeHex(buf[9:], uuid)
|
||||
return string(buf[:])
|
||||
}
|
||||
|
||||
func encodeHex(dst []byte, uuid UUID) {
|
||||
hex.Encode(dst[:], uuid[:4])
|
||||
dst[8] = '-'
|
||||
hex.Encode(dst[9:13], uuid[4:6])
|
||||
dst[13] = '-'
|
||||
hex.Encode(dst[14:18], uuid[6:8])
|
||||
dst[18] = '-'
|
||||
hex.Encode(dst[19:23], uuid[8:10])
|
||||
dst[23] = '-'
|
||||
hex.Encode(dst[24:], uuid[10:])
|
||||
}
|
||||
|
||||
// Variant returns the variant encoded in uuid. It returns Invalid if
|
||||
// uuid is invalid.
|
||||
func (uuid UUID) Variant() Variant {
|
||||
if len(uuid) != 16 {
|
||||
return Invalid
|
||||
}
|
||||
switch {
|
||||
case (uuid[8] & 0xc0) == 0x80:
|
||||
return RFC4122
|
||||
case (uuid[8] & 0xe0) == 0xc0:
|
||||
return Microsoft
|
||||
case (uuid[8] & 0xe0) == 0xe0:
|
||||
return Future
|
||||
default:
|
||||
return Reserved
|
||||
}
|
||||
}
|
||||
|
||||
// Version returns the version of uuid. It returns false if uuid is not
|
||||
// valid.
|
||||
func (uuid UUID) Version() (Version, bool) {
|
||||
if len(uuid) != 16 {
|
||||
return 0, false
|
||||
}
|
||||
return Version(uuid[6] >> 4), true
|
||||
}
|
||||
|
||||
// SetRand sets the random number generator to r, which implements io.Reader.
|
||||
// If r.Read returns an error when the package requests random data then
|
||||
// a panic will be issued.
|
||||
//
|
||||
// Calling SetRand with nil sets the random number generator to the default
|
||||
// generator.
|
||||
func SetRand(r io.Reader) {
|
||||
guuid.SetRand(r)
|
||||
}
|
||||
23
vendor/github.com/pborman/uuid/version1.go
generated
vendored
Normal file
23
vendor/github.com/pborman/uuid/version1.go
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
// Copyright 2011 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import (
|
||||
guuid "github.com/google/uuid"
|
||||
)
|
||||
|
||||
// NewUUID returns a Version 1 UUID based on the current NodeID and clock
|
||||
// sequence, and the current time. If the NodeID has not been set by SetNodeID
|
||||
// or SetNodeInterface then it will be set automatically. If the NodeID cannot
|
||||
// be set NewUUID returns nil. If clock sequence has not been set by
|
||||
// SetClockSequence then it will be set automatically. If GetTime fails to
|
||||
// return the current NewUUID returns nil.
|
||||
func NewUUID() UUID {
|
||||
gu, err := guuid.NewUUID()
|
||||
if err == nil {
|
||||
return UUID(gu[:])
|
||||
}
|
||||
return nil
|
||||
}
|
||||
26
vendor/github.com/pborman/uuid/version4.go
generated
vendored
Normal file
26
vendor/github.com/pborman/uuid/version4.go
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
// Copyright 2011 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import guuid "github.com/google/uuid"
|
||||
|
||||
// Random returns a Random (Version 4) UUID or panics.
|
||||
//
|
||||
// The strength of the UUIDs is based on the strength of the crypto/rand
|
||||
// package.
|
||||
//
|
||||
// A note about uniqueness derived from the UUID Wikipedia entry:
|
||||
//
|
||||
// Randomly generated UUIDs have 122 random bits. One's annual risk of being
|
||||
// hit by a meteorite is estimated to be one chance in 17 billion, that
|
||||
// means the probability is about 0.00000000006 (6 × 10−11),
|
||||
// equivalent to the odds of creating a few tens of trillions of UUIDs in a
|
||||
// year and having one duplicate.
|
||||
func NewRandom() UUID {
|
||||
if gu, err := guuid.NewRandom(); err == nil {
|
||||
return UUID(gu[:])
|
||||
}
|
||||
return nil
|
||||
}
|
||||
203
vendor/github.com/rainycape/unidecode/LICENSE
generated
vendored
203
vendor/github.com/rainycape/unidecode/LICENSE
generated
vendored
@@ -1,203 +0,0 @@
|
||||
Copyright 2014 Rainy Cape S.L. <hello@rainycape.com>
|
||||
|
||||
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.
|
||||
6
vendor/github.com/rainycape/unidecode/README.md
generated
vendored
6
vendor/github.com/rainycape/unidecode/README.md
generated
vendored
@@ -1,6 +0,0 @@
|
||||
unidecode
|
||||
=========
|
||||
|
||||
Unicode transliterator in Golang - Replaces non-ASCII characters with their ASCII approximations.
|
||||
|
||||
[](https://godoc.org/github.com/rainycape/unidecode)
|
||||
41
vendor/github.com/rainycape/unidecode/decode.go
generated
vendored
41
vendor/github.com/rainycape/unidecode/decode.go
generated
vendored
@@ -1,41 +0,0 @@
|
||||
package unidecode
|
||||
|
||||
import (
|
||||
"compress/zlib"
|
||||
"encoding/binary"
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
transliterations [65536][]rune
|
||||
transCount = rune(len(transliterations))
|
||||
getUint16 = binary.LittleEndian.Uint16
|
||||
)
|
||||
|
||||
func decodeTransliterations() {
|
||||
r, err := zlib.NewReader(strings.NewReader(tableData))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer r.Close()
|
||||
tmp1 := make([]byte, 2)
|
||||
tmp2 := tmp1[:1]
|
||||
for {
|
||||
if _, err := io.ReadAtLeast(r, tmp1, 2); err != nil {
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
chr := getUint16(tmp1)
|
||||
if _, err := io.ReadAtLeast(r, tmp2, 1); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
b := make([]byte, int(tmp2[0]))
|
||||
if _, err := io.ReadFull(r, b); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
transliterations[int(chr)] = []rune(string(b))
|
||||
}
|
||||
}
|
||||
71
vendor/github.com/rainycape/unidecode/make_table.go
generated
vendored
71
vendor/github.com/rainycape/unidecode/make_table.go
generated
vendored
@@ -1,71 +0,0 @@
|
||||
// +build none
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/zlib"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"go/format"
|
||||
"io/ioutil"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func main() {
|
||||
data, err := ioutil.ReadFile("table.txt")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
for _, line := range strings.Split(string(data), "\n") {
|
||||
if strings.HasPrefix(line, "/*") || line == "" {
|
||||
continue
|
||||
}
|
||||
sep := strings.IndexByte(line, ':')
|
||||
if sep == -1 {
|
||||
panic(line)
|
||||
}
|
||||
val, err := strconv.ParseInt(line[:sep], 0, 32)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
s, err := strconv.Unquote(line[sep+2:])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if s == "" {
|
||||
continue
|
||||
}
|
||||
if err := binary.Write(&buf, binary.LittleEndian, uint16(val)); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if err := binary.Write(&buf, binary.LittleEndian, uint8(len(s))); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
buf.WriteString(s)
|
||||
}
|
||||
var cbuf bytes.Buffer
|
||||
w, err := zlib.NewWriterLevel(&cbuf, zlib.BestCompression)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if _, err := w.Write(buf.Bytes()); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if err := w.Close(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
buf.Reset()
|
||||
buf.WriteString("package unidecode\n")
|
||||
buf.WriteString("// AUTOGENERATED - DO NOT EDIT!\n\n")
|
||||
fmt.Fprintf(&buf, "var tableData = %q;\n", cbuf.String())
|
||||
dst, err := format.Source(buf.Bytes())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if err := ioutil.WriteFile("table.go", dst, 0644); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
5
vendor/github.com/rainycape/unidecode/table.go
generated
vendored
5
vendor/github.com/rainycape/unidecode/table.go
generated
vendored
File diff suppressed because one or more lines are too long
46731
vendor/github.com/rainycape/unidecode/table.txt
generated
vendored
46731
vendor/github.com/rainycape/unidecode/table.txt
generated
vendored
File diff suppressed because it is too large
Load Diff
58
vendor/github.com/rainycape/unidecode/unidecode.go
generated
vendored
58
vendor/github.com/rainycape/unidecode/unidecode.go
generated
vendored
@@ -1,58 +0,0 @@
|
||||
// Package unidecode implements a unicode transliterator
|
||||
// which replaces non-ASCII characters with their ASCII
|
||||
// approximations.
|
||||
package unidecode
|
||||
|
||||
//go:generate go run make_table.go
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
const pooledCapacity = 64
|
||||
|
||||
var (
|
||||
slicePool sync.Pool
|
||||
decodingOnce sync.Once
|
||||
)
|
||||
|
||||
// Unidecode implements a unicode transliterator, which
|
||||
// replaces non-ASCII characters with their ASCII
|
||||
// counterparts.
|
||||
// Given an unicode encoded string, returns
|
||||
// another string with non-ASCII characters replaced
|
||||
// with their closest ASCII counterparts.
|
||||
// e.g. Unicode("áéíóú") => "aeiou"
|
||||
func Unidecode(s string) string {
|
||||
decodingOnce.Do(decodeTransliterations)
|
||||
l := len(s)
|
||||
var r []rune
|
||||
if l > pooledCapacity {
|
||||
r = make([]rune, 0, len(s))
|
||||
} else {
|
||||
if x := slicePool.Get(); x != nil {
|
||||
r = x.([]rune)[:0]
|
||||
} else {
|
||||
r = make([]rune, 0, pooledCapacity)
|
||||
}
|
||||
}
|
||||
for _, c := range s {
|
||||
if c <= unicode.MaxASCII {
|
||||
r = append(r, c)
|
||||
continue
|
||||
}
|
||||
if c > unicode.MaxRune || c > transCount {
|
||||
/* Ignore reserved chars */
|
||||
continue
|
||||
}
|
||||
if d := transliterations[c]; d != nil {
|
||||
r = append(r, d...)
|
||||
}
|
||||
}
|
||||
res := string(r)
|
||||
if l <= pooledCapacity {
|
||||
slicePool.Put(r)
|
||||
}
|
||||
return res
|
||||
}
|
||||
3
vendor/github.com/segmentio/backo-go/.gitmodules
generated
vendored
Normal file
3
vendor/github.com/segmentio/backo-go/.gitmodules
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
[submodule "vendor/github.com/bmizerany/assert"]
|
||||
path = vendor/github.com/bmizerany/assert
|
||||
url = https://github.com/bmizerany/assert
|
||||
21
vendor/github.com/segmentio/backo-go/LICENSE
generated
vendored
Normal file
21
vendor/github.com/segmentio/backo-go/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Segment, Inc.
|
||||
|
||||
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.
|
||||
80
vendor/github.com/segmentio/backo-go/README.md
generated
vendored
Normal file
80
vendor/github.com/segmentio/backo-go/README.md
generated
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
Backo [](http://godoc.org/github.com/segmentio/backo-go)
|
||||
-----
|
||||
|
||||
Exponential backoff for Go (Go port of segmentio/backo).
|
||||
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
```go
|
||||
import "github.com/segmentio/backo-go"
|
||||
|
||||
// Create a Backo instance.
|
||||
backo := backo.NewBacko(milliseconds(100), 2, 1, milliseconds(10*1000))
|
||||
// OR with defaults.
|
||||
backo := backo.DefaultBacko()
|
||||
|
||||
// Use the ticker API.
|
||||
ticker := b.NewTicker()
|
||||
for {
|
||||
timeout := time.After(5 * time.Minute)
|
||||
select {
|
||||
case <-ticker.C:
|
||||
fmt.Println("ticked")
|
||||
case <- timeout:
|
||||
fmt.Println("timed out")
|
||||
}
|
||||
}
|
||||
|
||||
// Or simply work with backoff intervals directly.
|
||||
for i := 0; i < n; i++ {
|
||||
// Sleep the current goroutine.
|
||||
backo.Sleep(i)
|
||||
// Retrieve the duration manually.
|
||||
duration := backo.Duration(i)
|
||||
}
|
||||
```
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
```
|
||||
WWWWWW||WWWWWW
|
||||
W W W||W W W
|
||||
||
|
||||
( OO )__________
|
||||
/ | \
|
||||
/o o| MIT \
|
||||
\___/||_||__||_|| *
|
||||
|| || || ||
|
||||
_||_|| _||_||
|
||||
(__|__|(__|__|
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Segment, Inc.
|
||||
|
||||
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.
|
||||
```
|
||||
|
||||
|
||||
|
||||
[1]: http://github.com/segmentio/backo-java
|
||||
[2]: http://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=com.segment.backo&a=backo&v=LATEST
|
||||
83
vendor/github.com/segmentio/backo-go/backo.go
generated
vendored
Normal file
83
vendor/github.com/segmentio/backo-go/backo.go
generated
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
package backo
|
||||
|
||||
import (
|
||||
"math"
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Backo struct {
|
||||
base time.Duration
|
||||
factor uint8
|
||||
jitter float64
|
||||
cap time.Duration
|
||||
}
|
||||
|
||||
// Creates a backo instance with the given parameters
|
||||
func NewBacko(base time.Duration, factor uint8, jitter float64, cap time.Duration) *Backo {
|
||||
return &Backo{base, factor, jitter, cap}
|
||||
}
|
||||
|
||||
// Creates a backo instance with the following defaults:
|
||||
// base: 100 milliseconds
|
||||
// factor: 2
|
||||
// jitter: 0
|
||||
// cap: 10 seconds
|
||||
func DefaultBacko() *Backo {
|
||||
return NewBacko(time.Millisecond*100, 2, 0, time.Second*10)
|
||||
}
|
||||
|
||||
// Duration returns the backoff interval for the given attempt.
|
||||
func (backo *Backo) Duration(attempt int) time.Duration {
|
||||
duration := float64(backo.base) * math.Pow(float64(backo.factor), float64(attempt))
|
||||
|
||||
if backo.jitter != 0 {
|
||||
random := rand.Float64()
|
||||
deviation := math.Floor(random * backo.jitter * duration)
|
||||
if (int(math.Floor(random*10)) & 1) == 0 {
|
||||
duration = duration - deviation
|
||||
} else {
|
||||
duration = duration + deviation
|
||||
}
|
||||
}
|
||||
|
||||
duration = math.Min(float64(duration), float64(backo.cap))
|
||||
return time.Duration(duration)
|
||||
}
|
||||
|
||||
// Sleep pauses the current goroutine for the backoff interval for the given attempt.
|
||||
func (backo *Backo) Sleep(attempt int) {
|
||||
duration := backo.Duration(attempt)
|
||||
time.Sleep(duration)
|
||||
}
|
||||
|
||||
type Ticker struct {
|
||||
done chan struct{}
|
||||
C <-chan time.Time
|
||||
}
|
||||
|
||||
func (b *Backo) NewTicker() *Ticker {
|
||||
c := make(chan time.Time, 1)
|
||||
ticker := &Ticker{
|
||||
done: make(chan struct{}, 1),
|
||||
C: c,
|
||||
}
|
||||
|
||||
go func() {
|
||||
for i := 0; ; i++ {
|
||||
select {
|
||||
case t := <-time.After(b.Duration(i)):
|
||||
c <- t
|
||||
case <-ticker.done:
|
||||
close(c)
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return ticker
|
||||
}
|
||||
|
||||
func (t *Ticker) Stop() {
|
||||
t.done <- struct{}{}
|
||||
}
|
||||
3
vendor/github.com/segmentio/backo-go/go.mod
generated
vendored
Normal file
3
vendor/github.com/segmentio/backo-go/go.mod
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
module github.com/segmentio/backo-go
|
||||
|
||||
go 1.13
|
||||
5
vendor/github.com/xtgo/uuid/AUTHORS
generated
vendored
Normal file
5
vendor/github.com/xtgo/uuid/AUTHORS
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
# This source file refers to The gocql Authors for copyright purposes.
|
||||
|
||||
Christoph Hack <christoph@tux21b.org>
|
||||
Jonathan Rudenberg <jonathan@titanous.com>
|
||||
Thorsten von Eicken <tve@rightscale.com>
|
||||
27
vendor/github.com/xtgo/uuid/LICENSE
generated
vendored
Normal file
27
vendor/github.com/xtgo/uuid/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
Copyright (c) 2012 The gocql 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.
|
||||
204
vendor/github.com/xtgo/uuid/uuid.go
generated
vendored
Normal file
204
vendor/github.com/xtgo/uuid/uuid.go
generated
vendored
Normal file
@@ -0,0 +1,204 @@
|
||||
// Copyright (c) 2012 The gocql 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 uuid can be used to generate and parse universally unique
|
||||
// identifiers, a standardized format in the form of a 128 bit number.
|
||||
//
|
||||
// http://tools.ietf.org/html/rfc4122
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"io"
|
||||
"net"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
type UUID [16]byte
|
||||
|
||||
var hardwareAddr []byte
|
||||
|
||||
const (
|
||||
VariantNCSCompat = 0
|
||||
VariantIETF = 2
|
||||
VariantMicrosoft = 6
|
||||
VariantFuture = 7
|
||||
)
|
||||
|
||||
func init() {
|
||||
if interfaces, err := net.Interfaces(); err == nil {
|
||||
for _, i := range interfaces {
|
||||
if i.Flags&net.FlagLoopback == 0 && len(i.HardwareAddr) > 0 {
|
||||
hardwareAddr = i.HardwareAddr
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if hardwareAddr == nil {
|
||||
// If we failed to obtain the MAC address of the current computer,
|
||||
// we will use a randomly generated 6 byte sequence instead and set
|
||||
// the multicast bit as recommended in RFC 4122.
|
||||
hardwareAddr = make([]byte, 6)
|
||||
_, err := io.ReadFull(rand.Reader, hardwareAddr)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
hardwareAddr[0] = hardwareAddr[0] | 0x01
|
||||
}
|
||||
}
|
||||
|
||||
// Parse parses a 32 digit hexadecimal number (that might contain hyphens)
|
||||
// representing an UUID.
|
||||
func Parse(input string) (UUID, error) {
|
||||
var u UUID
|
||||
j := 0
|
||||
for i := 0; i < len(input); i++ {
|
||||
b := input[i]
|
||||
switch {
|
||||
default:
|
||||
fallthrough
|
||||
case j == 32:
|
||||
goto err
|
||||
case b == '-':
|
||||
continue
|
||||
case '0' <= b && b <= '9':
|
||||
b -= '0'
|
||||
case 'a' <= b && b <= 'f':
|
||||
b -= 'a' - 10
|
||||
case 'A' <= b && b <= 'F':
|
||||
b -= 'A' - 10
|
||||
}
|
||||
u[j/2] |= b << byte(^j&1<<2)
|
||||
j++
|
||||
}
|
||||
if j == 32 {
|
||||
return u, nil
|
||||
}
|
||||
err:
|
||||
return UUID{}, errors.New("invalid UUID " + strconv.Quote(input))
|
||||
}
|
||||
|
||||
// FromBytes converts a raw byte slice to an UUID. It will panic if the slice
|
||||
// isn't exactly 16 bytes long.
|
||||
func FromBytes(input []byte) UUID {
|
||||
var u UUID
|
||||
if len(input) != 16 {
|
||||
panic("UUIDs must be exactly 16 bytes long")
|
||||
}
|
||||
copy(u[:], input)
|
||||
return u
|
||||
}
|
||||
|
||||
// NewRandom generates a totally random UUID (version 4) as described in
|
||||
// RFC 4122.
|
||||
func NewRandom() UUID {
|
||||
var u UUID
|
||||
io.ReadFull(rand.Reader, u[:])
|
||||
u[6] &= 0x0F // clear version
|
||||
u[6] |= 0x40 // set version to 4 (random uuid)
|
||||
u[8] &= 0x3F // clear variant
|
||||
u[8] |= 0x80 // set to IETF variant
|
||||
return u
|
||||
}
|
||||
|
||||
var timeBase = time.Date(1582, time.October, 15, 0, 0, 0, 0, time.UTC).Unix()
|
||||
|
||||
// NewTime generates a new time based UUID (version 1) as described in RFC
|
||||
// 4122. This UUID contains the MAC address of the node that generated the
|
||||
// UUID, a timestamp and a sequence number.
|
||||
func NewTime() UUID {
|
||||
var u UUID
|
||||
|
||||
now := time.Now().In(time.UTC)
|
||||
t := uint64(now.Unix()-timeBase)*10000000 + uint64(now.Nanosecond()/100)
|
||||
u[0], u[1], u[2], u[3] = byte(t>>24), byte(t>>16), byte(t>>8), byte(t)
|
||||
u[4], u[5] = byte(t>>40), byte(t>>32)
|
||||
u[6], u[7] = byte(t>>56)&0x0F, byte(t>>48)
|
||||
|
||||
var clockSeq [2]byte
|
||||
io.ReadFull(rand.Reader, clockSeq[:])
|
||||
u[8] = clockSeq[1]
|
||||
u[9] = clockSeq[0]
|
||||
|
||||
copy(u[10:], hardwareAddr)
|
||||
|
||||
u[6] |= 0x10 // set version to 1 (time based uuid)
|
||||
u[8] &= 0x3F // clear variant
|
||||
u[8] |= 0x80 // set to IETF variant
|
||||
|
||||
return u
|
||||
}
|
||||
|
||||
// String returns the UUID in it's canonical form, a 32 digit hexadecimal
|
||||
// number in the form of xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.
|
||||
func (u UUID) String() string {
|
||||
buf := [36]byte{8: '-', 13: '-', 18: '-', 23: '-'}
|
||||
hex.Encode(buf[0:], u[0:4])
|
||||
hex.Encode(buf[9:], u[4:6])
|
||||
hex.Encode(buf[14:], u[6:8])
|
||||
hex.Encode(buf[19:], u[8:10])
|
||||
hex.Encode(buf[24:], u[10:])
|
||||
return string(buf[:])
|
||||
}
|
||||
|
||||
// Bytes returns the raw byte slice for this UUID. A UUID is always 128 bits
|
||||
// (16 bytes) long.
|
||||
func (u UUID) Bytes() []byte {
|
||||
return u[:]
|
||||
}
|
||||
|
||||
// Variant returns the variant of this UUID. This package will only generate
|
||||
// UUIDs in the IETF variant.
|
||||
func (u UUID) Variant() int {
|
||||
x := u[8]
|
||||
switch byte(0) {
|
||||
case x & 0x80:
|
||||
return VariantNCSCompat
|
||||
case x & 0x40:
|
||||
return VariantIETF
|
||||
case x & 0x20:
|
||||
return VariantMicrosoft
|
||||
}
|
||||
return VariantFuture
|
||||
}
|
||||
|
||||
// Version extracts the version of this UUID variant. The RFC 4122 describes
|
||||
// five kinds of UUIDs.
|
||||
func (u UUID) Version() int {
|
||||
return int(u[6] & 0xF0 >> 4)
|
||||
}
|
||||
|
||||
// Node extracts the MAC address of the node who generated this UUID. It will
|
||||
// return nil if the UUID is not a time based UUID (version 1).
|
||||
func (u UUID) Node() []byte {
|
||||
if u.Version() != 1 {
|
||||
return nil
|
||||
}
|
||||
return u[10:]
|
||||
}
|
||||
|
||||
// Timestamp extracts the timestamp information from a time based UUID
|
||||
// (version 1).
|
||||
func (u UUID) Timestamp() uint64 {
|
||||
if u.Version() != 1 {
|
||||
return 0
|
||||
}
|
||||
return uint64(u[0])<<24 + uint64(u[1])<<16 + uint64(u[2])<<8 +
|
||||
uint64(u[3]) + uint64(u[4])<<40 + uint64(u[5])<<32 +
|
||||
uint64(u[7])<<48 + uint64(u[6]&0x0F)<<56
|
||||
}
|
||||
|
||||
// Time is like Timestamp, except that it returns a time.Time.
|
||||
func (u UUID) Time() time.Time {
|
||||
t := u.Timestamp()
|
||||
if t == 0 {
|
||||
return time.Time{}
|
||||
}
|
||||
sec := t / 10000000
|
||||
nsec := t - sec
|
||||
return time.Unix(int64(sec)+timeBase, int64(nsec))
|
||||
}
|
||||
@@ -21,3 +21,12 @@ _testmain.go
|
||||
|
||||
*.exe
|
||||
*.test
|
||||
*.prof
|
||||
|
||||
# Emacs
|
||||
*~
|
||||
\#*
|
||||
.\#*
|
||||
|
||||
# Artifacts
|
||||
tmp/*
|
||||
6
vendor/gopkg.in/segmentio/analytics-go.v3/.gitmodules
generated
vendored
Normal file
6
vendor/gopkg.in/segmentio/analytics-go.v3/.gitmodules
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
[submodule "vendor/github.com/segmentio/backo-go"]
|
||||
path = vendor/github.com/segmentio/backo-go
|
||||
url = https://github.com/segmentio/backo-go
|
||||
[submodule "vendor/github.com/xtgo/uuid"]
|
||||
path = vendor/github.com/xtgo/uuid
|
||||
url = https://github.com/xtgo/uuid
|
||||
88
vendor/gopkg.in/segmentio/analytics-go.v3/History.md
generated
vendored
Normal file
88
vendor/gopkg.in/segmentio/analytics-go.v3/History.md
generated
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
|
||||
v3.1.0 / 2019-09-20
|
||||
===================
|
||||
|
||||
* add consistent panic error message
|
||||
* Expose the Message interface Validate method
|
||||
* return error if a custom type is enqueued
|
||||
* Handle pointer types in Enqueue()
|
||||
* message: update maxMessageBytes to 32KB
|
||||
|
||||
v3.0.1 / 2018-10-02
|
||||
===================
|
||||
|
||||
* Migrate from Circle V1 format to Circle V2
|
||||
* Adds CLI for sending segment events
|
||||
* Vendor packages back-go and uuid instead of using gitsubmodules
|
||||
|
||||
|
||||
v3.0.0 / 2016-06-02
|
||||
===================
|
||||
|
||||
* 3.0 is a significant rewrite with multiple breaking changes.
|
||||
* [Quickstart](https://segment.com/docs/sources/server/go/quickstart/).
|
||||
* [Documentation](https://segment.com/docs/sources/server/go/).
|
||||
* [GoDocs](https://godoc.org/gopkg.in/segmentio/analytics-go.v3).
|
||||
* [What's New in v3](https://segment.com/docs/sources/server/go/#what-s-new-in-v3).
|
||||
|
||||
|
||||
v2.1.0 / 2015-12-28
|
||||
===================
|
||||
|
||||
* Add ability to set custom timestamps for messages.
|
||||
* Add ability to set a custom `net/http` client.
|
||||
* Add ability to set a custom logger.
|
||||
* Fix edge case when client would try to upload no messages.
|
||||
* Properly upload in-flight messages when client is asked to shutdown.
|
||||
* Add ability to set `.integrations` field on messages.
|
||||
* Fix resource leak with interval ticker after shutdown.
|
||||
* Add retries and back-off when uploading messages.
|
||||
* Add ability to set custom flush interval.
|
||||
|
||||
v2.0.0 / 2015-02-03
|
||||
===================
|
||||
|
||||
* rewrite with breaking API changes
|
||||
|
||||
v1.2.0 / 2014-09-03
|
||||
==================
|
||||
|
||||
* add public .Flush() method
|
||||
* rename .Stop() to .Close()
|
||||
|
||||
v1.1.0 / 2014-09-02
|
||||
==================
|
||||
|
||||
* add client.Stop() to flash/wait. Closes #7
|
||||
|
||||
v1.0.0 / 2014-08-26
|
||||
==================
|
||||
|
||||
* fix response close
|
||||
* change comments to be more go-like
|
||||
* change uuid libraries
|
||||
|
||||
0.1.2 / 2014-06-11
|
||||
==================
|
||||
|
||||
* add runnable example
|
||||
* fix: close body
|
||||
|
||||
0.1.1 / 2014-05-31
|
||||
==================
|
||||
|
||||
* refactor locking
|
||||
|
||||
0.1.0 / 2014-05-22
|
||||
==================
|
||||
|
||||
* replace Debug option with debug package
|
||||
|
||||
0.0.2 / 2014-05-20
|
||||
==================
|
||||
|
||||
* add .Start()
|
||||
* add mutexes
|
||||
* rename BufferSize to FlushAt and FlushInterval to FlushAfter
|
||||
* lower FlushInterval to 5 seconds
|
||||
* lower BufferSize to 20 to match other clients
|
||||
21
vendor/gopkg.in/segmentio/analytics-go.v3/License.md
generated
vendored
Normal file
21
vendor/gopkg.in/segmentio/analytics-go.v3/License.md
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Segment, Inc.
|
||||
|
||||
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.
|
||||
31
vendor/gopkg.in/segmentio/analytics-go.v3/Makefile
generated
vendored
Normal file
31
vendor/gopkg.in/segmentio/analytics-go.v3/Makefile
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
ifndef CIRCLE_ARTIFACTS
|
||||
CIRCLE_ARTIFACTS=tmp
|
||||
endif
|
||||
|
||||
bootstrap:
|
||||
.buildscript/bootstrap.sh
|
||||
|
||||
dependencies:
|
||||
@go get -v -t ./...
|
||||
|
||||
vet:
|
||||
@go vet ./...
|
||||
|
||||
test: vet
|
||||
@mkdir -p ${CIRCLE_ARTIFACTS}
|
||||
@go test -race -coverprofile=${CIRCLE_ARTIFACTS}/cover.out .
|
||||
@go tool cover -func ${CIRCLE_ARTIFACTS}/cover.out -o ${CIRCLE_ARTIFACTS}/cover.txt
|
||||
@go tool cover -html ${CIRCLE_ARTIFACTS}/cover.out -o ${CIRCLE_ARTIFACTS}/cover.html
|
||||
|
||||
build: test
|
||||
@go build ./...
|
||||
|
||||
e2e:
|
||||
@if [ "$(RUN_E2E_TESTS)" != "true" ]; then \
|
||||
echo "Skipping end to end tests."; else \
|
||||
go get github.com/segmentio/library-e2e-tester/cmd/tester; \
|
||||
tester -segment-write-key=$(SEGMENT_WRITE_KEY) -webhook-auth-username=$(WEBHOOK_AUTH_USERNAME) -webhook-bucket=$(WEBHOOK_BUCKET) -path='cli' -concurrency=2 -skip='advance|alias'; fi
|
||||
|
||||
ci: dependencies test e2e
|
||||
|
||||
.PHONY: bootstrap dependencies vet test e2e ci
|
||||
55
vendor/gopkg.in/segmentio/analytics-go.v3/Readme.md
generated
vendored
Normal file
55
vendor/gopkg.in/segmentio/analytics-go.v3/Readme.md
generated
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
# analytics-go [](https://circleci.com/gh/segmentio/analytics-go/tree/master) [](https://godoc.org/github.com/segmentio/analytics-go)
|
||||
|
||||
Segment analytics client for Go.
|
||||
|
||||
## Installation
|
||||
|
||||
The package can be simply installed via go get, we recommend that you use a
|
||||
package version management system like the Go vendor directory or a tool like
|
||||
Godep to avoid issues related to API breaking changes introduced between major
|
||||
versions of the library.
|
||||
|
||||
To install it in the GOPATH:
|
||||
```
|
||||
go get https://github.com/segmentio/analytics-go
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
The links bellow should provide all the documentation needed to make the best
|
||||
use of the library and the Segment API:
|
||||
|
||||
- [Documentation](https://segment.com/docs/libraries/go/)
|
||||
- [godoc](https://godoc.org/gopkg.in/segmentio/analytics-go.v3)
|
||||
- [API](https://segment.com/docs/libraries/http/)
|
||||
- [Specs](https://segment.com/docs/spec/)
|
||||
|
||||
## Usage
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/segmentio/analytics-go"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Instantiates a client to use send messages to the segment API.
|
||||
client := analytics.New(os.Getenv("SEGMENT_WRITE_KEY"))
|
||||
|
||||
// Enqueues a track event that will be sent asynchronously.
|
||||
client.Enqueue(analytics.Track{
|
||||
UserId: "test-user",
|
||||
Event: "test-snippet",
|
||||
})
|
||||
|
||||
// Flushes any queued messages and closes the client.
|
||||
client.Close()
|
||||
}
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
The library is released under the [MIT license](License.md).
|
||||
44
vendor/gopkg.in/segmentio/analytics-go.v3/alias.go
generated
vendored
Normal file
44
vendor/gopkg.in/segmentio/analytics-go.v3/alias.go
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
package analytics
|
||||
|
||||
import "time"
|
||||
|
||||
var _ Message = (*Alias)(nil)
|
||||
|
||||
// This type represents object sent in a alias call as described in
|
||||
// https://segment.com/docs/libraries/http/#alias
|
||||
type Alias struct {
|
||||
// This field is exported for serialization purposes and shouldn't be set by
|
||||
// the application, its value is always overwritten by the library.
|
||||
Type string `json:"type,omitempty"`
|
||||
|
||||
MessageId string `json:"messageId,omitempty"`
|
||||
PreviousId string `json:"previousId"`
|
||||
UserId string `json:"userId"`
|
||||
Timestamp time.Time `json:"timestamp,omitempty"`
|
||||
Context *Context `json:"context,omitempty"`
|
||||
Integrations Integrations `json:"integrations,omitempty"`
|
||||
}
|
||||
|
||||
func (msg Alias) internal() {
|
||||
panic(unimplementedError)
|
||||
}
|
||||
|
||||
func (msg Alias) Validate() error {
|
||||
if len(msg.UserId) == 0 {
|
||||
return FieldError{
|
||||
Type: "analytics.Alias",
|
||||
Name: "UserId",
|
||||
Value: msg.UserId,
|
||||
}
|
||||
}
|
||||
|
||||
if len(msg.PreviousId) == 0 {
|
||||
return FieldError{
|
||||
Type: "analytics.Alias",
|
||||
Name: "PreviousId",
|
||||
Value: msg.PreviousId,
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
431
vendor/gopkg.in/segmentio/analytics-go.v3/analytics.go
generated
vendored
Normal file
431
vendor/gopkg.in/segmentio/analytics-go.v3/analytics.go
generated
vendored
Normal file
@@ -0,0 +1,431 @@
|
||||
package analytics
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"sync"
|
||||
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Version of the client.
|
||||
const Version = "3.0.0"
|
||||
const unimplementedError = "not implemented"
|
||||
|
||||
// This interface is the main API exposed by the analytics package.
|
||||
// Values that satsify this interface are returned by the client constructors
|
||||
// provided by the package and provide a way to send messages via the HTTP API.
|
||||
type Client interface {
|
||||
io.Closer
|
||||
|
||||
// Queues a message to be sent by the client when the conditions for a batch
|
||||
// upload are met.
|
||||
// This is the main method you'll be using, a typical flow would look like
|
||||
// this:
|
||||
//
|
||||
// client := analytics.New(writeKey)
|
||||
// ...
|
||||
// client.Enqueue(analytics.Track{ ... })
|
||||
// ...
|
||||
// client.Close()
|
||||
//
|
||||
// The method returns an error if the message queue not be queued, which
|
||||
// happens if the client was already closed at the time the method was
|
||||
// called or if the message was malformed.
|
||||
Enqueue(Message) error
|
||||
}
|
||||
|
||||
type client struct {
|
||||
Config
|
||||
key string
|
||||
|
||||
// This channel is where the `Enqueue` method writes messages so they can be
|
||||
// picked up and pushed by the backend goroutine taking care of applying the
|
||||
// batching rules.
|
||||
msgs chan Message
|
||||
|
||||
// These two channels are used to synchronize the client shutting down when
|
||||
// `Close` is called.
|
||||
// The first channel is closed to signal the backend goroutine that it has
|
||||
// to stop, then the second one is closed by the backend goroutine to signal
|
||||
// that it has finished flushing all queued messages.
|
||||
quit chan struct{}
|
||||
shutdown chan struct{}
|
||||
|
||||
// This HTTP client is used to send requests to the backend, it uses the
|
||||
// HTTP transport provided in the configuration.
|
||||
http http.Client
|
||||
}
|
||||
|
||||
// Instantiate a new client that uses the write key passed as first argument to
|
||||
// send messages to the backend.
|
||||
// The client is created with the default configuration.
|
||||
func New(writeKey string) Client {
|
||||
// Here we can ignore the error because the default config is always valid.
|
||||
c, _ := NewWithConfig(writeKey, Config{})
|
||||
return c
|
||||
}
|
||||
|
||||
// Instantiate a new client that uses the write key and configuration passed as
|
||||
// arguments to send messages to the backend.
|
||||
// The function will return an error if the configuration contained impossible
|
||||
// values (like a negative flush interval for example).
|
||||
// When the function returns an error the returned client will always be nil.
|
||||
func NewWithConfig(writeKey string, config Config) (cli Client, err error) {
|
||||
if err = config.validate(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
c := &client{
|
||||
Config: makeConfig(config),
|
||||
key: writeKey,
|
||||
msgs: make(chan Message, 100),
|
||||
quit: make(chan struct{}),
|
||||
shutdown: make(chan struct{}),
|
||||
http: makeHttpClient(config.Transport),
|
||||
}
|
||||
|
||||
go c.loop()
|
||||
|
||||
cli = c
|
||||
return
|
||||
}
|
||||
|
||||
func makeHttpClient(transport http.RoundTripper) http.Client {
|
||||
httpClient := http.Client{
|
||||
Transport: transport,
|
||||
}
|
||||
if supportsTimeout(transport) {
|
||||
httpClient.Timeout = 10 * time.Second
|
||||
}
|
||||
return httpClient
|
||||
}
|
||||
|
||||
func dereferenceMessage(msg Message) Message {
|
||||
switch m := msg.(type) {
|
||||
case *Alias:
|
||||
if m == nil {
|
||||
return nil
|
||||
}
|
||||
return *m
|
||||
case *Group:
|
||||
if m == nil {
|
||||
return nil
|
||||
}
|
||||
return *m
|
||||
case *Identify:
|
||||
if m == nil {
|
||||
return nil
|
||||
}
|
||||
return *m
|
||||
case *Page:
|
||||
if m == nil {
|
||||
return nil
|
||||
}
|
||||
return *m
|
||||
case *Screen:
|
||||
if m == nil {
|
||||
return nil
|
||||
}
|
||||
return *m
|
||||
case *Track:
|
||||
if m == nil {
|
||||
return nil
|
||||
}
|
||||
return *m
|
||||
}
|
||||
|
||||
return msg
|
||||
}
|
||||
|
||||
func (c *client) Enqueue(msg Message) (err error) {
|
||||
msg = dereferenceMessage(msg)
|
||||
if err = msg.Validate(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var id = c.uid()
|
||||
var ts = c.now()
|
||||
|
||||
switch m := msg.(type) {
|
||||
case Alias:
|
||||
m.Type = "alias"
|
||||
m.MessageId = makeMessageId(m.MessageId, id)
|
||||
m.Timestamp = makeTimestamp(m.Timestamp, ts)
|
||||
msg = m
|
||||
|
||||
case Group:
|
||||
m.Type = "group"
|
||||
m.MessageId = makeMessageId(m.MessageId, id)
|
||||
m.Timestamp = makeTimestamp(m.Timestamp, ts)
|
||||
msg = m
|
||||
|
||||
case Identify:
|
||||
m.Type = "identify"
|
||||
m.MessageId = makeMessageId(m.MessageId, id)
|
||||
m.Timestamp = makeTimestamp(m.Timestamp, ts)
|
||||
msg = m
|
||||
|
||||
case Page:
|
||||
m.Type = "page"
|
||||
m.MessageId = makeMessageId(m.MessageId, id)
|
||||
m.Timestamp = makeTimestamp(m.Timestamp, ts)
|
||||
msg = m
|
||||
|
||||
case Screen:
|
||||
m.Type = "screen"
|
||||
m.MessageId = makeMessageId(m.MessageId, id)
|
||||
m.Timestamp = makeTimestamp(m.Timestamp, ts)
|
||||
msg = m
|
||||
|
||||
case Track:
|
||||
m.Type = "track"
|
||||
m.MessageId = makeMessageId(m.MessageId, id)
|
||||
m.Timestamp = makeTimestamp(m.Timestamp, ts)
|
||||
msg = m
|
||||
|
||||
default:
|
||||
err = fmt.Errorf("messages with custom types cannot be enqueued: %T", msg)
|
||||
return
|
||||
}
|
||||
|
||||
defer func() {
|
||||
// When the `msgs` channel is closed writing to it will trigger a panic.
|
||||
// To avoid letting the panic propagate to the caller we recover from it
|
||||
// and instead report that the client has been closed and shouldn't be
|
||||
// used anymore.
|
||||
if recover() != nil {
|
||||
err = ErrClosed
|
||||
}
|
||||
}()
|
||||
|
||||
c.msgs <- msg
|
||||
return
|
||||
}
|
||||
|
||||
// Close and flush metrics.
|
||||
func (c *client) Close() (err error) {
|
||||
defer func() {
|
||||
// Always recover, a panic could be raised if `c`.quit was closed which
|
||||
// means the method was called more than once.
|
||||
if recover() != nil {
|
||||
err = ErrClosed
|
||||
}
|
||||
}()
|
||||
close(c.quit)
|
||||
<-c.shutdown
|
||||
return
|
||||
}
|
||||
|
||||
// Asychronously send a batched requests.
|
||||
func (c *client) sendAsync(msgs []message, wg *sync.WaitGroup, ex *executor) {
|
||||
wg.Add(1)
|
||||
|
||||
if !ex.do(func() {
|
||||
defer wg.Done()
|
||||
defer func() {
|
||||
// In case a bug is introduced in the send function that triggers
|
||||
// a panic, we don't want this to ever crash the application so we
|
||||
// catch it here and log it instead.
|
||||
if err := recover(); err != nil {
|
||||
c.errorf("panic - %s", err)
|
||||
}
|
||||
}()
|
||||
c.send(msgs)
|
||||
}) {
|
||||
wg.Done()
|
||||
c.errorf("sending messages failed - %s", ErrTooManyRequests)
|
||||
c.notifyFailure(msgs, ErrTooManyRequests)
|
||||
}
|
||||
}
|
||||
|
||||
// Send batch request.
|
||||
func (c *client) send(msgs []message) {
|
||||
const attempts = 10
|
||||
|
||||
b, err := json.Marshal(batch{
|
||||
MessageId: c.uid(),
|
||||
SentAt: c.now(),
|
||||
Messages: msgs,
|
||||
Context: c.DefaultContext,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
c.errorf("marshalling messages - %s", err)
|
||||
c.notifyFailure(msgs, err)
|
||||
return
|
||||
}
|
||||
|
||||
for i := 0; i != attempts; i++ {
|
||||
if err = c.upload(b); err == nil {
|
||||
c.notifySuccess(msgs)
|
||||
return
|
||||
}
|
||||
|
||||
// Wait for either a retry timeout or the client to be closed.
|
||||
select {
|
||||
case <-time.After(c.RetryAfter(i)):
|
||||
case <-c.quit:
|
||||
c.errorf("%d messages dropped because they failed to be sent and the client was closed", len(msgs))
|
||||
c.notifyFailure(msgs, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
c.errorf("%d messages dropped because they failed to be sent after %d attempts", len(msgs), attempts)
|
||||
c.notifyFailure(msgs, err)
|
||||
}
|
||||
|
||||
// Upload serialized batch message.
|
||||
func (c *client) upload(b []byte) error {
|
||||
url := c.Endpoint + "/v1/batch"
|
||||
req, err := http.NewRequest("POST", url, bytes.NewReader(b))
|
||||
if err != nil {
|
||||
c.errorf("creating request - %s", err)
|
||||
return err
|
||||
}
|
||||
|
||||
req.Header.Add("User-Agent", "analytics-go (version: "+Version+")")
|
||||
req.Header.Add("Content-Type", "application/json")
|
||||
req.Header.Add("Content-Length", string(len(b)))
|
||||
req.SetBasicAuth(c.key, "")
|
||||
|
||||
res, err := c.http.Do(req)
|
||||
|
||||
if err != nil {
|
||||
c.errorf("sending request - %s", err)
|
||||
return err
|
||||
}
|
||||
|
||||
defer res.Body.Close()
|
||||
return c.report(res)
|
||||
}
|
||||
|
||||
// Report on response body.
|
||||
func (c *client) report(res *http.Response) (err error) {
|
||||
var body []byte
|
||||
|
||||
if res.StatusCode < 300 {
|
||||
c.debugf("response %s", res.Status)
|
||||
return
|
||||
}
|
||||
|
||||
if body, err = ioutil.ReadAll(res.Body); err != nil {
|
||||
c.errorf("response %d %s - %s", res.StatusCode, res.Status, err)
|
||||
return
|
||||
}
|
||||
|
||||
c.logf("response %d %s – %s", res.StatusCode, res.Status, string(body))
|
||||
return fmt.Errorf("%d %s", res.StatusCode, res.Status)
|
||||
}
|
||||
|
||||
// Batch loop.
|
||||
func (c *client) loop() {
|
||||
defer close(c.shutdown)
|
||||
|
||||
wg := &sync.WaitGroup{}
|
||||
defer wg.Wait()
|
||||
|
||||
tick := time.NewTicker(c.Interval)
|
||||
defer tick.Stop()
|
||||
|
||||
ex := newExecutor(c.maxConcurrentRequests)
|
||||
defer ex.close()
|
||||
|
||||
mq := messageQueue{
|
||||
maxBatchSize: c.BatchSize,
|
||||
maxBatchBytes: c.maxBatchBytes(),
|
||||
}
|
||||
|
||||
for {
|
||||
select {
|
||||
case msg := <-c.msgs:
|
||||
c.push(&mq, msg, wg, ex)
|
||||
|
||||
case <-tick.C:
|
||||
c.flush(&mq, wg, ex)
|
||||
|
||||
case <-c.quit:
|
||||
c.debugf("exit requested – draining messages")
|
||||
|
||||
// Drain the msg channel, we have to close it first so no more
|
||||
// messages can be pushed and otherwise the loop would never end.
|
||||
close(c.msgs)
|
||||
for msg := range c.msgs {
|
||||
c.push(&mq, msg, wg, ex)
|
||||
}
|
||||
|
||||
c.flush(&mq, wg, ex)
|
||||
c.debugf("exit")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *client) push(q *messageQueue, m Message, wg *sync.WaitGroup, ex *executor) {
|
||||
var msg message
|
||||
var err error
|
||||
|
||||
if msg, err = makeMessage(m, maxMessageBytes); err != nil {
|
||||
c.errorf("%s - %v", err, m)
|
||||
c.notifyFailure([]message{{m, nil}}, err)
|
||||
return
|
||||
}
|
||||
|
||||
c.debugf("buffer (%d/%d) %v", len(q.pending), c.BatchSize, m)
|
||||
|
||||
if msgs := q.push(msg); msgs != nil {
|
||||
c.debugf("exceeded messages batch limit with batch of %d messages – flushing", len(msgs))
|
||||
c.sendAsync(msgs, wg, ex)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *client) flush(q *messageQueue, wg *sync.WaitGroup, ex *executor) {
|
||||
if msgs := q.flush(); msgs != nil {
|
||||
c.debugf("flushing %d messages", len(msgs))
|
||||
c.sendAsync(msgs, wg, ex)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *client) debugf(format string, args ...interface{}) {
|
||||
if c.Verbose {
|
||||
c.logf(format, args...)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *client) logf(format string, args ...interface{}) {
|
||||
c.Logger.Logf(format, args...)
|
||||
}
|
||||
|
||||
func (c *client) errorf(format string, args ...interface{}) {
|
||||
c.Logger.Errorf(format, args...)
|
||||
}
|
||||
|
||||
func (c *client) maxBatchBytes() int {
|
||||
b, _ := json.Marshal(batch{
|
||||
MessageId: c.uid(),
|
||||
SentAt: c.now(),
|
||||
Context: c.DefaultContext,
|
||||
})
|
||||
return maxBatchBytes - len(b)
|
||||
}
|
||||
|
||||
func (c *client) notifySuccess(msgs []message) {
|
||||
if c.Callback != nil {
|
||||
for _, m := range msgs {
|
||||
c.Callback.Success(m.msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *client) notifyFailure(msgs []message, err error) {
|
||||
if c.Callback != nil {
|
||||
for _, m := range msgs {
|
||||
c.Callback.Failure(m.msg, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
173
vendor/gopkg.in/segmentio/analytics-go.v3/config.go
generated
vendored
Normal file
173
vendor/gopkg.in/segmentio/analytics-go.v3/config.go
generated
vendored
Normal file
@@ -0,0 +1,173 @@
|
||||
package analytics
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/segmentio/backo-go"
|
||||
"github.com/xtgo/uuid"
|
||||
)
|
||||
|
||||
// Instances of this type carry the different configuration options that may
|
||||
// be set when instantiating a client.
|
||||
//
|
||||
// Each field's zero-value is either meaningful or interpreted as using the
|
||||
// default value defined by the library.
|
||||
type Config struct {
|
||||
|
||||
// The endpoint to which the client connect and send their messages, set to
|
||||
// `DefaultEndpoint` by default.
|
||||
Endpoint string
|
||||
|
||||
// The flushing interval of the client. Messages will be sent when they've
|
||||
// been queued up to the maximum batch size or when the flushing interval
|
||||
// timer triggers.
|
||||
Interval time.Duration
|
||||
|
||||
// The HTTP transport used by the client, this allows an application to
|
||||
// redefine how requests are being sent at the HTTP level (for example,
|
||||
// to change the connection pooling policy).
|
||||
// If none is specified the client uses `http.DefaultTransport`.
|
||||
Transport http.RoundTripper
|
||||
|
||||
// The logger used by the client to output info or error messages when that
|
||||
// are generated by background operations.
|
||||
// If none is specified the client uses a standard logger that outputs to
|
||||
// `os.Stderr`.
|
||||
Logger Logger
|
||||
|
||||
// The callback object that will be used by the client to notify the
|
||||
// application when messages sends to the backend API succeeded or failed.
|
||||
Callback Callback
|
||||
|
||||
// The maximum number of messages that will be sent in one API call.
|
||||
// Messages will be sent when they've been queued up to the maximum batch
|
||||
// size or when the flushing interval timer triggers.
|
||||
// Note that the API will still enforce a 500KB limit on each HTTP request
|
||||
// which is independent from the number of embedded messages.
|
||||
BatchSize int
|
||||
|
||||
// When set to true the client will send more frequent and detailed messages
|
||||
// to its logger.
|
||||
Verbose bool
|
||||
|
||||
// The default context set on each message sent by the client.
|
||||
DefaultContext *Context
|
||||
|
||||
// The retry policy used by the client to resend requests that have failed.
|
||||
// The function is called with how many times the operation has been retried
|
||||
// and is expected to return how long the client should wait before trying
|
||||
// again.
|
||||
// If not set the client will fallback to use a default retry policy.
|
||||
RetryAfter func(int) time.Duration
|
||||
|
||||
// A function called by the client to generate unique message identifiers.
|
||||
// The client uses a UUID generator if none is provided.
|
||||
// This field is not exported and only exposed internally to let unit tests
|
||||
// mock the id generation.
|
||||
uid func() string
|
||||
|
||||
// A function called by the client to get the current time, `time.Now` is
|
||||
// used by default.
|
||||
// This field is not exported and only exposed internally to let unit tests
|
||||
// mock the current time.
|
||||
now func() time.Time
|
||||
|
||||
// The maximum number of goroutines that will be spawned by a client to send
|
||||
// requests to the backend API.
|
||||
// This field is not exported and only exposed internally to let unit tests
|
||||
// mock the current time.
|
||||
maxConcurrentRequests int
|
||||
}
|
||||
|
||||
// This constant sets the default endpoint to which client instances send
|
||||
// messages if none was explictly set.
|
||||
const DefaultEndpoint = "https://api.segment.io"
|
||||
|
||||
// This constant sets the default flush interval used by client instances if
|
||||
// none was explicitly set.
|
||||
const DefaultInterval = 5 * time.Second
|
||||
|
||||
// This constant sets the default batch size used by client instances if none
|
||||
// was explicitly set.
|
||||
const DefaultBatchSize = 250
|
||||
|
||||
// Verifies that fields that don't have zero-values are set to valid values,
|
||||
// returns an error describing the problem if a field was invalid.
|
||||
func (c *Config) validate() error {
|
||||
if c.Interval < 0 {
|
||||
return ConfigError{
|
||||
Reason: "negative time intervals are not supported",
|
||||
Field: "Interval",
|
||||
Value: c.Interval,
|
||||
}
|
||||
}
|
||||
|
||||
if c.BatchSize < 0 {
|
||||
return ConfigError{
|
||||
Reason: "negative batch sizes are not supported",
|
||||
Field: "BatchSize",
|
||||
Value: c.BatchSize,
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Given a config object as argument the function will set all zero-values to
|
||||
// their defaults and return the modified object.
|
||||
func makeConfig(c Config) Config {
|
||||
if len(c.Endpoint) == 0 {
|
||||
c.Endpoint = DefaultEndpoint
|
||||
}
|
||||
|
||||
if c.Interval == 0 {
|
||||
c.Interval = DefaultInterval
|
||||
}
|
||||
|
||||
if c.Transport == nil {
|
||||
c.Transport = http.DefaultTransport
|
||||
}
|
||||
|
||||
if c.Logger == nil {
|
||||
c.Logger = newDefaultLogger()
|
||||
}
|
||||
|
||||
if c.BatchSize == 0 {
|
||||
c.BatchSize = DefaultBatchSize
|
||||
}
|
||||
|
||||
if c.DefaultContext == nil {
|
||||
c.DefaultContext = &Context{}
|
||||
}
|
||||
|
||||
if c.RetryAfter == nil {
|
||||
c.RetryAfter = backo.DefaultBacko().Duration
|
||||
}
|
||||
|
||||
if c.uid == nil {
|
||||
c.uid = uid
|
||||
}
|
||||
|
||||
if c.now == nil {
|
||||
c.now = time.Now
|
||||
}
|
||||
|
||||
if c.maxConcurrentRequests == 0 {
|
||||
c.maxConcurrentRequests = 1000
|
||||
}
|
||||
|
||||
// We always overwrite the 'library' field of the default context set on the
|
||||
// client because we want this information to be accurate.
|
||||
c.DefaultContext.Library = LibraryInfo{
|
||||
Name: "analytics-go",
|
||||
Version: Version,
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// This function returns a string representation of a UUID, it's the default
|
||||
// function used for generating unique IDs.
|
||||
func uid() string {
|
||||
return uuid.NewRandom().String()
|
||||
}
|
||||
148
vendor/gopkg.in/segmentio/analytics-go.v3/context.go
generated
vendored
Normal file
148
vendor/gopkg.in/segmentio/analytics-go.v3/context.go
generated
vendored
Normal file
@@ -0,0 +1,148 @@
|
||||
package analytics
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// This type provides the representation of the `context` object as defined in
|
||||
// https://segment.com/docs/spec/common/#context
|
||||
type Context struct {
|
||||
App AppInfo `json:"app,omitempty"`
|
||||
Campaign CampaignInfo `json:"campaign,omitempty"`
|
||||
Device DeviceInfo `json:"device,omitempty"`
|
||||
Library LibraryInfo `json:"library,omitempty"`
|
||||
Location LocationInfo `json:"location,omitempty"`
|
||||
Network NetworkInfo `json:"network,omitempty"`
|
||||
OS OSInfo `json:"os,omitempty"`
|
||||
Page PageInfo `json:"page,omitempty"`
|
||||
Referrer ReferrerInfo `json:"referrer,omitempty"`
|
||||
Screen ScreenInfo `json:"screen,omitempty"`
|
||||
IP net.IP `json:"ip,omitempty"`
|
||||
Locale string `json:"locale,omitempty"`
|
||||
Timezone string `json:"timezone,omitempty"`
|
||||
UserAgent string `json:"userAgent,omitempty"`
|
||||
Traits Traits `json:"traits,omitempty"`
|
||||
|
||||
// This map is used to allow extensions to the context specifications that
|
||||
// may not be documented or could be introduced in the future.
|
||||
// The fields of this map are inlined in the serialized context object,
|
||||
// there is no actual "extra" field in the JSON representation.
|
||||
Extra map[string]interface{} `json:"-"`
|
||||
}
|
||||
|
||||
// This type provides the representation of the `context.app` object as defined
|
||||
// in https://segment.com/docs/spec/common/#context
|
||||
type AppInfo struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Version string `json:"version,omitempty"`
|
||||
Build string `json:"build,omitempty"`
|
||||
Namespace string `json:"namespace,omitempty"`
|
||||
}
|
||||
|
||||
// This type provides the representation of the `context.campaign` object as
|
||||
// defined in https://segment.com/docs/spec/common/#context
|
||||
type CampaignInfo struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Source string `json:"source,omitempty"`
|
||||
Medium string `json:"medium,omitempty"`
|
||||
Term string `json:"term,omitempty"`
|
||||
Content string `json:"content,omitempty"`
|
||||
}
|
||||
|
||||
// This type provides the representation of the `context.device` object as
|
||||
// defined in https://segment.com/docs/spec/common/#context
|
||||
type DeviceInfo struct {
|
||||
Id string `json:"id,omitempty"`
|
||||
Manufacturer string `json:"manufacturer,omitempty"`
|
||||
Model string `json:"model,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Type string `json:"type,omitempty"`
|
||||
Version string `json:"version,omitempty"`
|
||||
AdvertisingID string `json:"advertisingId,omitempty"`
|
||||
}
|
||||
|
||||
// This type provides the representation of the `context.library` object as
|
||||
// defined in https://segment.com/docs/spec/common/#context
|
||||
type LibraryInfo struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Version string `json:"version,omitempty"`
|
||||
}
|
||||
|
||||
// This type provides the representation of the `context.location` object as
|
||||
// defined in https://segment.com/docs/spec/common/#context
|
||||
type LocationInfo struct {
|
||||
City string `json:"city,omitempty"`
|
||||
Country string `json:"country,omitempty"`
|
||||
Region string `json:"region,omitempty"`
|
||||
Latitude float64 `json:"latitude,omitempty"`
|
||||
Longitude float64 `json:"longitude,omitempty"`
|
||||
Speed float64 `json:"speed,omitempty"`
|
||||
}
|
||||
|
||||
// This type provides the representation of the `context.network` object as
|
||||
// defined in https://segment.com/docs/spec/common/#context
|
||||
type NetworkInfo struct {
|
||||
Bluetooth bool `json:"bluetooth,omitempty"`
|
||||
Cellular bool `json:"cellular,omitempty"`
|
||||
WIFI bool `json:"wifi,omitempty"`
|
||||
Carrier string `json:"carrier,omitempty"`
|
||||
}
|
||||
|
||||
// This type provides the representation of the `context.os` object as defined
|
||||
// in https://segment.com/docs/spec/common/#context
|
||||
type OSInfo struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Version string `json:"version,omitempty"`
|
||||
}
|
||||
|
||||
// This type provides the representation of the `context.page` object as
|
||||
// defined in https://segment.com/docs/spec/common/#context
|
||||
type PageInfo struct {
|
||||
Hash string `json:"hash,omitempty"`
|
||||
Path string `json:"path,omitempty"`
|
||||
Referrer string `json:"referrer,omitempty"`
|
||||
Search string `json:"search,omitempty"`
|
||||
Title string `json:"title,omitempty"`
|
||||
URL string `json:"url,omitempty"`
|
||||
}
|
||||
|
||||
// This type provides the representation of the `context.referrer` object as
|
||||
// defined in https://segment.com/docs/spec/common/#context
|
||||
type ReferrerInfo struct {
|
||||
Type string `json:"type,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
URL string `json:"url,omitempty"`
|
||||
Link string `json:"link,omitempty"`
|
||||
}
|
||||
|
||||
// This type provides the representation of the `context.screen` object as
|
||||
// defined in https://segment.com/docs/spec/common/#context
|
||||
type ScreenInfo struct {
|
||||
Density int `json:"density,omitempty"`
|
||||
Width int `json:"width,omitempty"`
|
||||
Height int `json:"height,omitempty"`
|
||||
}
|
||||
|
||||
// Satisfy the `json.Marshaler` interface. We have to flatten out the `Extra`
|
||||
// field but the standard json package doesn't support it yet.
|
||||
// Implementing this interface allows us to override the default marshaling of
|
||||
// the context object and to the inlining ourselves.
|
||||
//
|
||||
// Related discussion: https://github.com/golang/go/issues/6213
|
||||
func (ctx Context) MarshalJSON() ([]byte, error) {
|
||||
v := reflect.ValueOf(ctx)
|
||||
n := v.NumField()
|
||||
m := make(map[string]interface{}, n+len(ctx.Extra))
|
||||
|
||||
// Copy the `Extra` map into the map representation of the context, it is
|
||||
// important to do this operation before going through the actual struct
|
||||
// fields so the latter take precendence and override duplicated values
|
||||
// that would be set in the extensions.
|
||||
for name, value := range ctx.Extra {
|
||||
m[name] = value
|
||||
}
|
||||
|
||||
return json.Marshal(structToMap(v, m))
|
||||
}
|
||||
60
vendor/gopkg.in/segmentio/analytics-go.v3/error.go
generated
vendored
Normal file
60
vendor/gopkg.in/segmentio/analytics-go.v3/error.go
generated
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
package analytics
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Returned by the `NewWithConfig` function when the one of the configuration
|
||||
// fields was set to an impossible value (like a negative duration).
|
||||
type ConfigError struct {
|
||||
|
||||
// A human-readable message explaining why the configuration field's value
|
||||
// is invalid.
|
||||
Reason string
|
||||
|
||||
// The name of the configuration field that was carrying an invalid value.
|
||||
Field string
|
||||
|
||||
// The value of the configuration field that caused the error.
|
||||
Value interface{}
|
||||
}
|
||||
|
||||
func (e ConfigError) Error() string {
|
||||
return fmt.Sprintf("analytics.NewWithConfig: %s (analytics.Config.%s: %#v)", e.Reason, e.Field, e.Value)
|
||||
}
|
||||
|
||||
// Instances of this type are used to represent errors returned when a field was
|
||||
// no initialize properly in a structure passed as argument to one of the
|
||||
// functions of this package.
|
||||
type FieldError struct {
|
||||
|
||||
// The human-readable representation of the type of structure that wasn't
|
||||
// initialized properly.
|
||||
Type string
|
||||
|
||||
// The name of the field that wasn't properly initialized.
|
||||
Name string
|
||||
|
||||
// The value of the field that wasn't properly initialized.
|
||||
Value interface{}
|
||||
}
|
||||
|
||||
func (e FieldError) Error() string {
|
||||
return fmt.Sprintf("%s.%s: invalid field value: %#v", e.Type, e.Name, e.Value)
|
||||
}
|
||||
|
||||
var (
|
||||
// This error is returned by methods of the `Client` interface when they are
|
||||
// called after the client was already closed.
|
||||
ErrClosed = errors.New("the client was already closed")
|
||||
|
||||
// This error is used to notify the application that too many requests are
|
||||
// already being sent and no more messages can be accepted.
|
||||
ErrTooManyRequests = errors.New("too many requests are already in-flight")
|
||||
|
||||
// This error is used to notify the client callbacks that a message send
|
||||
// failed because the JSON representation of a message exceeded the upper
|
||||
// limit.
|
||||
ErrMessageTooBig = errors.New("the message exceeds the maximum allowed size")
|
||||
)
|
||||
53
vendor/gopkg.in/segmentio/analytics-go.v3/executor.go
generated
vendored
Normal file
53
vendor/gopkg.in/segmentio/analytics-go.v3/executor.go
generated
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
package analytics
|
||||
|
||||
import "sync"
|
||||
|
||||
type executor struct {
|
||||
queue chan func()
|
||||
mutex sync.Mutex
|
||||
size int
|
||||
cap int
|
||||
}
|
||||
|
||||
func newExecutor(cap int) *executor {
|
||||
e := &executor{
|
||||
queue: make(chan func(), 1),
|
||||
cap: cap,
|
||||
}
|
||||
go e.loop()
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *executor) do(task func()) (ok bool) {
|
||||
e.mutex.Lock()
|
||||
|
||||
if e.size != e.cap {
|
||||
e.queue <- task
|
||||
e.size++
|
||||
ok = true
|
||||
}
|
||||
|
||||
e.mutex.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
func (e *executor) close() {
|
||||
close(e.queue)
|
||||
}
|
||||
|
||||
func (e *executor) loop() {
|
||||
for task := range e.queue {
|
||||
go e.run(task)
|
||||
}
|
||||
}
|
||||
|
||||
func (e *executor) run(task func()) {
|
||||
defer e.done()
|
||||
task()
|
||||
}
|
||||
|
||||
func (e *executor) done() {
|
||||
e.mutex.Lock()
|
||||
e.size--
|
||||
e.mutex.Unlock()
|
||||
}
|
||||
46
vendor/gopkg.in/segmentio/analytics-go.v3/group.go
generated
vendored
Normal file
46
vendor/gopkg.in/segmentio/analytics-go.v3/group.go
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
package analytics
|
||||
|
||||
import "time"
|
||||
|
||||
var _ Message = (*Group)(nil)
|
||||
|
||||
// This type represents object sent in a group call as described in
|
||||
// https://segment.com/docs/libraries/http/#group
|
||||
type Group struct {
|
||||
// This field is exported for serialization purposes and shouldn't be set by
|
||||
// the application, its value is always overwritten by the library.
|
||||
Type string `json:"type,omitempty"`
|
||||
|
||||
MessageId string `json:"messageId,omitempty"`
|
||||
AnonymousId string `json:"anonymousId,omitempty"`
|
||||
UserId string `json:"userId,omitempty"`
|
||||
GroupId string `json:"groupId"`
|
||||
Timestamp time.Time `json:"timestamp,omitempty"`
|
||||
Context *Context `json:"context,omitempty"`
|
||||
Traits Traits `json:"traits,omitempty"`
|
||||
Integrations Integrations `json:"integrations,omitempty"`
|
||||
}
|
||||
|
||||
func (msg Group) internal() {
|
||||
panic(unimplementedError)
|
||||
}
|
||||
|
||||
func (msg Group) Validate() error {
|
||||
if len(msg.GroupId) == 0 {
|
||||
return FieldError{
|
||||
Type: "analytics.Group",
|
||||
Name: "GroupId",
|
||||
Value: msg.GroupId,
|
||||
}
|
||||
}
|
||||
|
||||
if len(msg.UserId) == 0 && len(msg.AnonymousId) == 0 {
|
||||
return FieldError{
|
||||
Type: "analytics.Group",
|
||||
Name: "UserId",
|
||||
Value: msg.UserId,
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
37
vendor/gopkg.in/segmentio/analytics-go.v3/identify.go
generated
vendored
Normal file
37
vendor/gopkg.in/segmentio/analytics-go.v3/identify.go
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
package analytics
|
||||
|
||||
import "time"
|
||||
|
||||
var _ Message = (*Identify)(nil)
|
||||
|
||||
// This type represents object sent in an identify call as described in
|
||||
// https://segment.com/docs/libraries/http/#identify
|
||||
type Identify struct {
|
||||
// This field is exported for serialization purposes and shouldn't be set by
|
||||
// the application, its value is always overwritten by the library.
|
||||
Type string `json:"type,omitempty"`
|
||||
|
||||
MessageId string `json:"messageId,omitempty"`
|
||||
AnonymousId string `json:"anonymousId,omitempty"`
|
||||
UserId string `json:"userId,omitempty"`
|
||||
Timestamp time.Time `json:"timestamp,omitempty"`
|
||||
Context *Context `json:"context,omitempty"`
|
||||
Traits Traits `json:"traits,omitempty"`
|
||||
Integrations Integrations `json:"integrations,omitempty"`
|
||||
}
|
||||
|
||||
func (msg Identify) internal() {
|
||||
panic(unimplementedError)
|
||||
}
|
||||
|
||||
func (msg Identify) Validate() error {
|
||||
if len(msg.UserId) == 0 && len(msg.AnonymousId) == 0 {
|
||||
return FieldError{
|
||||
Type: "analytics.Identify",
|
||||
Name: "UserId",
|
||||
Value: msg.UserId,
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
44
vendor/gopkg.in/segmentio/analytics-go.v3/integrations.go
generated
vendored
Normal file
44
vendor/gopkg.in/segmentio/analytics-go.v3/integrations.go
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
package analytics
|
||||
|
||||
// This type is used to represent integrations in messages that support it.
|
||||
// It is a free-form where values are most often booleans that enable or
|
||||
// disable integrations.
|
||||
// Here's a quick example of how this type is meant to be used:
|
||||
//
|
||||
// analytics.Track{
|
||||
// UserId: "0123456789",
|
||||
// Integrations: analytics.NewIntegrations()
|
||||
// .EnableAll()
|
||||
// .Disable("Salesforce")
|
||||
// .Disable("Marketo"),
|
||||
// }
|
||||
//
|
||||
// The specifications can be found at https://segment.com/docs/spec/common/#integrations
|
||||
type Integrations map[string]interface{}
|
||||
|
||||
func NewIntegrations() Integrations {
|
||||
return make(Integrations, 10)
|
||||
}
|
||||
|
||||
func (i Integrations) EnableAll() Integrations {
|
||||
return i.Enable("all")
|
||||
}
|
||||
|
||||
func (i Integrations) DisableAll() Integrations {
|
||||
return i.Disable("all")
|
||||
}
|
||||
|
||||
func (i Integrations) Enable(name string) Integrations {
|
||||
return i.Set(name, true)
|
||||
}
|
||||
|
||||
func (i Integrations) Disable(name string) Integrations {
|
||||
return i.Set(name, false)
|
||||
}
|
||||
|
||||
// Sets an integration named by the first argument to the specified value, any
|
||||
// value other than `false` will be interpreted as enabling the integration.
|
||||
func (i Integrations) Set(name string, value interface{}) Integrations {
|
||||
i[name] = value
|
||||
return i
|
||||
}
|
||||
87
vendor/gopkg.in/segmentio/analytics-go.v3/json.go
generated
vendored
Normal file
87
vendor/gopkg.in/segmentio/analytics-go.v3/json.go
generated
vendored
Normal file
@@ -0,0 +1,87 @@
|
||||
package analytics
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Imitate what what the JSON package would do when serializing a struct value,
|
||||
// the only difference is we we don't serialize zero-value struct fields as well.
|
||||
// Note that this function doesn't recursively convert structures to maps, only
|
||||
// the value passed as argument is transformed.
|
||||
func structToMap(v reflect.Value, m map[string]interface{}) map[string]interface{} {
|
||||
t := v.Type()
|
||||
n := t.NumField()
|
||||
|
||||
if m == nil {
|
||||
m = make(map[string]interface{}, n)
|
||||
}
|
||||
|
||||
for i := 0; i != n; i++ {
|
||||
field := t.Field(i)
|
||||
value := v.Field(i)
|
||||
name, omitempty := parseJsonTag(field.Tag.Get("json"), field.Name)
|
||||
|
||||
if name != "-" && !(omitempty && isZeroValue(value)) {
|
||||
m[name] = value.Interface()
|
||||
}
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
// Parses a JSON tag the way the json package would do it, returing the expected
|
||||
// name of the field once serialized and if empty values should be omitted.
|
||||
func parseJsonTag(tag string, defName string) (name string, omitempty bool) {
|
||||
args := strings.Split(tag, ",")
|
||||
|
||||
if len(args) == 0 || len(args[0]) == 0 {
|
||||
name = defName
|
||||
} else {
|
||||
name = args[0]
|
||||
}
|
||||
|
||||
if len(args) > 1 && args[1] == "omitempty" {
|
||||
omitempty = true
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Checks if the value given as argument is a zero-value, it is based on the
|
||||
// isEmptyValue function in https://golang.org/src/encoding/json/encode.go
|
||||
// but also checks struct types recursively.
|
||||
func isZeroValue(v reflect.Value) bool {
|
||||
switch v.Kind() {
|
||||
case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
|
||||
return v.Len() == 0
|
||||
|
||||
case reflect.Bool:
|
||||
return !v.Bool()
|
||||
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
return v.Int() == 0
|
||||
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
return v.Uint() == 0
|
||||
|
||||
case reflect.Float32, reflect.Float64:
|
||||
return v.Float() == 0
|
||||
|
||||
case reflect.Interface, reflect.Ptr:
|
||||
return v.IsNil()
|
||||
|
||||
case reflect.Struct:
|
||||
for i, n := 0, v.NumField(); i != n; i++ {
|
||||
if !isZeroValue(v.Field(i)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
|
||||
case reflect.Invalid:
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
47
vendor/gopkg.in/segmentio/analytics-go.v3/logger.go
generated
vendored
Normal file
47
vendor/gopkg.in/segmentio/analytics-go.v3/logger.go
generated
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
package analytics
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
// Instances of types implementing this interface can be used to define where
|
||||
// the analytics client logs are written.
|
||||
type Logger interface {
|
||||
|
||||
// Analytics clients call this method to log regular messages about the
|
||||
// operations they perform.
|
||||
// Messages logged by this method are usually tagged with an `INFO` log
|
||||
// level in common logging libraries.
|
||||
Logf(format string, args ...interface{})
|
||||
|
||||
// Analytics clients call this method to log errors they encounter while
|
||||
// sending events to the backend servers.
|
||||
// Messages logged by this method are usually tagged with an `ERROR` log
|
||||
// level in common logging libraries.
|
||||
Errorf(format string, args ...interface{})
|
||||
}
|
||||
|
||||
// This function instantiate an object that statisfies the analytics.Logger
|
||||
// interface and send logs to standard logger passed as argument.
|
||||
func StdLogger(logger *log.Logger) Logger {
|
||||
return stdLogger{
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
type stdLogger struct {
|
||||
logger *log.Logger
|
||||
}
|
||||
|
||||
func (l stdLogger) Logf(format string, args ...interface{}) {
|
||||
l.logger.Printf("INFO: "+format, args...)
|
||||
}
|
||||
|
||||
func (l stdLogger) Errorf(format string, args ...interface{}) {
|
||||
l.logger.Printf("ERROR: "+format, args...)
|
||||
}
|
||||
|
||||
func newDefaultLogger() Logger {
|
||||
return StdLogger(log.New(os.Stderr, "segment ", log.LstdFlags))
|
||||
}
|
||||
131
vendor/gopkg.in/segmentio/analytics-go.v3/message.go
generated
vendored
Normal file
131
vendor/gopkg.in/segmentio/analytics-go.v3/message.go
generated
vendored
Normal file
@@ -0,0 +1,131 @@
|
||||
package analytics
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Values implementing this interface are used by analytics clients to notify
|
||||
// the application when a message send succeeded or failed.
|
||||
//
|
||||
// Callback methods are called by a client's internal goroutines, there are no
|
||||
// guarantees on which goroutine will trigger the callbacks, the calls can be
|
||||
// made sequentially or in parallel, the order doesn't depend on the order of
|
||||
// messages were queued to the client.
|
||||
//
|
||||
// Callback methods must return quickly and not cause long blocking operations
|
||||
// to avoid interferring with the client's internal work flow.
|
||||
type Callback interface {
|
||||
|
||||
// This method is called for every message that was successfully sent to
|
||||
// the API.
|
||||
Success(Message)
|
||||
|
||||
// This method is called for every message that failed to be sent to the
|
||||
// API and will be discarded by the client.
|
||||
Failure(Message, error)
|
||||
}
|
||||
|
||||
// This interface is used to represent analytics objects that can be sent via
|
||||
// a client.
|
||||
//
|
||||
// Types like analytics.Track, analytics.Page, etc... implement this interface
|
||||
// and therefore can be passed to the analytics.Client.Send method.
|
||||
type Message interface {
|
||||
|
||||
// Validate validates the internal structure of the message, the method must return
|
||||
// nil if the message is valid, or an error describing what went wrong.
|
||||
Validate() error
|
||||
|
||||
// internal is an unexposed interface function to ensure only types defined within this package can satisfy the Message interface. Invoking this method will panic.
|
||||
internal()
|
||||
}
|
||||
|
||||
// Takes a message id as first argument and returns it, unless it's the zero-
|
||||
// value, in that case the default id passed as second argument is returned.
|
||||
func makeMessageId(id string, def string) string {
|
||||
if len(id) == 0 {
|
||||
return def
|
||||
}
|
||||
return id
|
||||
}
|
||||
|
||||
// Returns the time value passed as first argument, unless it's the zero-value,
|
||||
// in that case the default value passed as second argument is returned.
|
||||
func makeTimestamp(t time.Time, def time.Time) time.Time {
|
||||
if t == (time.Time{}) {
|
||||
return def
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
// This structure represents objects sent to the /v1/batch endpoint. We don't
|
||||
// export this type because it's only meant to be used internally to send groups
|
||||
// of messages in one API call.
|
||||
type batch struct {
|
||||
MessageId string `json:"messageId"`
|
||||
SentAt time.Time `json:"sentAt"`
|
||||
Messages []message `json:"batch"`
|
||||
Context *Context `json:"context"`
|
||||
}
|
||||
|
||||
type message struct {
|
||||
msg Message
|
||||
json []byte
|
||||
}
|
||||
|
||||
func makeMessage(m Message, maxBytes int) (msg message, err error) {
|
||||
if msg.json, err = json.Marshal(m); err == nil {
|
||||
if len(msg.json) > maxBytes {
|
||||
err = ErrMessageTooBig
|
||||
} else {
|
||||
msg.msg = m
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (m message) MarshalJSON() ([]byte, error) {
|
||||
return m.json, nil
|
||||
}
|
||||
|
||||
func (m message) size() int {
|
||||
// The `+ 1` is for the comma that sits between each items of a JSON array.
|
||||
return len(m.json) + 1
|
||||
}
|
||||
|
||||
type messageQueue struct {
|
||||
pending []message
|
||||
bytes int
|
||||
maxBatchSize int
|
||||
maxBatchBytes int
|
||||
}
|
||||
|
||||
func (q *messageQueue) push(m message) (b []message) {
|
||||
if (q.bytes + m.size()) > q.maxBatchBytes {
|
||||
b = q.flush()
|
||||
}
|
||||
|
||||
if q.pending == nil {
|
||||
q.pending = make([]message, 0, q.maxBatchSize)
|
||||
}
|
||||
|
||||
q.pending = append(q.pending, m)
|
||||
q.bytes += len(m.json)
|
||||
|
||||
if b == nil && len(q.pending) == q.maxBatchSize {
|
||||
b = q.flush()
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (q *messageQueue) flush() (msgs []message) {
|
||||
msgs, q.pending, q.bytes = q.pending, nil, 0
|
||||
return
|
||||
}
|
||||
|
||||
const (
|
||||
maxBatchBytes = 500000
|
||||
maxMessageBytes = 32000
|
||||
)
|
||||
38
vendor/gopkg.in/segmentio/analytics-go.v3/page.go
generated
vendored
Normal file
38
vendor/gopkg.in/segmentio/analytics-go.v3/page.go
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
package analytics
|
||||
|
||||
import "time"
|
||||
|
||||
var _ Message = (*Page)(nil)
|
||||
|
||||
// This type represents object sent in a page call as described in
|
||||
// https://segment.com/docs/libraries/http/#page
|
||||
type Page struct {
|
||||
// This field is exported for serialization purposes and shouldn't be set by
|
||||
// the application, its value is always overwritten by the library.
|
||||
Type string `json:"type,omitempty"`
|
||||
|
||||
MessageId string `json:"messageId,omitempty"`
|
||||
AnonymousId string `json:"anonymousId,omitempty"`
|
||||
UserId string `json:"userId,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Timestamp time.Time `json:"timestamp,omitempty"`
|
||||
Context *Context `json:"context,omitempty"`
|
||||
Properties Properties `json:"properties,omitempty"`
|
||||
Integrations Integrations `json:"integrations,omitempty"`
|
||||
}
|
||||
|
||||
func (msg Page) internal() {
|
||||
panic(unimplementedError)
|
||||
}
|
||||
|
||||
func (msg Page) Validate() error {
|
||||
if len(msg.UserId) == 0 && len(msg.AnonymousId) == 0 {
|
||||
return FieldError{
|
||||
Type: "analytics.Page",
|
||||
Name: "UserId",
|
||||
Value: msg.UserId,
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
117
vendor/gopkg.in/segmentio/analytics-go.v3/properties.go
generated
vendored
Normal file
117
vendor/gopkg.in/segmentio/analytics-go.v3/properties.go
generated
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
package analytics
|
||||
|
||||
// This type is used to represent properties in messages that support it.
|
||||
// It is a free-form object so the application can set any value it sees fit but
|
||||
// a few helper method are defined to make it easier to instantiate properties with
|
||||
// common fields.
|
||||
// Here's a quick example of how this type is meant to be used:
|
||||
//
|
||||
// analytics.Page{
|
||||
// UserId: "0123456789",
|
||||
// Properties: analytics.NewProperties()
|
||||
// .SetRevenue(10.0)
|
||||
// .SetCurrency("USD"),
|
||||
// }
|
||||
//
|
||||
type Properties map[string]interface{}
|
||||
|
||||
func NewProperties() Properties {
|
||||
return make(Properties, 10)
|
||||
}
|
||||
|
||||
func (p Properties) SetRevenue(revenue float64) Properties {
|
||||
return p.Set("revenue", revenue)
|
||||
}
|
||||
|
||||
func (p Properties) SetCurrency(currency string) Properties {
|
||||
return p.Set("currency", currency)
|
||||
}
|
||||
|
||||
func (p Properties) SetValue(value float64) Properties {
|
||||
return p.Set("value", value)
|
||||
}
|
||||
|
||||
func (p Properties) SetPath(path string) Properties {
|
||||
return p.Set("path", path)
|
||||
}
|
||||
|
||||
func (p Properties) SetReferrer(referrer string) Properties {
|
||||
return p.Set("referrer", referrer)
|
||||
}
|
||||
|
||||
func (p Properties) SetTitle(title string) Properties {
|
||||
return p.Set("title", title)
|
||||
}
|
||||
|
||||
func (p Properties) SetURL(url string) Properties {
|
||||
return p.Set("url", url)
|
||||
}
|
||||
|
||||
func (p Properties) SetName(name string) Properties {
|
||||
return p.Set("name", name)
|
||||
}
|
||||
|
||||
func (p Properties) SetCategory(category string) Properties {
|
||||
return p.Set("category", category)
|
||||
}
|
||||
|
||||
func (p Properties) SetSKU(sku string) Properties {
|
||||
return p.Set("sku", sku)
|
||||
}
|
||||
|
||||
func (p Properties) SetPrice(price float64) Properties {
|
||||
return p.Set("price", price)
|
||||
}
|
||||
|
||||
func (p Properties) SetProductId(id string) Properties {
|
||||
return p.Set("id", id)
|
||||
}
|
||||
|
||||
func (p Properties) SetOrderId(id string) Properties {
|
||||
return p.Set("orderId", id)
|
||||
}
|
||||
|
||||
func (p Properties) SetTotal(total float64) Properties {
|
||||
return p.Set("total", total)
|
||||
}
|
||||
|
||||
func (p Properties) SetSubtotal(subtotal float64) Properties {
|
||||
return p.Set("subtotal", subtotal)
|
||||
}
|
||||
|
||||
func (p Properties) SetShipping(shipping float64) Properties {
|
||||
return p.Set("shipping", shipping)
|
||||
}
|
||||
|
||||
func (p Properties) SetTax(tax float64) Properties {
|
||||
return p.Set("tax", tax)
|
||||
}
|
||||
|
||||
func (p Properties) SetDiscount(discount float64) Properties {
|
||||
return p.Set("discount", discount)
|
||||
}
|
||||
|
||||
func (p Properties) SetCoupon(coupon string) Properties {
|
||||
return p.Set("coupon", coupon)
|
||||
}
|
||||
|
||||
func (p Properties) SetProducts(products ...Product) Properties {
|
||||
return p.Set("products", products)
|
||||
}
|
||||
|
||||
func (p Properties) SetRepeat(repeat bool) Properties {
|
||||
return p.Set("repeat", repeat)
|
||||
}
|
||||
|
||||
func (p Properties) Set(name string, value interface{}) Properties {
|
||||
p[name] = value
|
||||
return p
|
||||
}
|
||||
|
||||
// This type represents products in the E-commerce API.
|
||||
type Product struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
SKU string `json:"sky,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Price float64 `json:"price"`
|
||||
}
|
||||
38
vendor/gopkg.in/segmentio/analytics-go.v3/screen.go
generated
vendored
Normal file
38
vendor/gopkg.in/segmentio/analytics-go.v3/screen.go
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
package analytics
|
||||
|
||||
import "time"
|
||||
|
||||
var _ Message = (*Screen)(nil)
|
||||
|
||||
// This type represents object sent in a screen call as described in
|
||||
// https://segment.com/docs/libraries/http/#screen
|
||||
type Screen struct {
|
||||
// This field is exported for serialization purposes and shouldn't be set by
|
||||
// the application, its value is always overwritten by the library.
|
||||
Type string `json:"type,omitempty"`
|
||||
|
||||
MessageId string `json:"messageId,omitempty"`
|
||||
AnonymousId string `json:"anonymousId,omitempty"`
|
||||
UserId string `json:"userId,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Timestamp time.Time `json:"timestamp,omitempty"`
|
||||
Context *Context `json:"context,omitempty"`
|
||||
Properties Properties `json:"properties,omitempty"`
|
||||
Integrations Integrations `json:"integrations,omitempty"`
|
||||
}
|
||||
|
||||
func (msg Screen) internal() {
|
||||
panic(unimplementedError)
|
||||
}
|
||||
|
||||
func (msg Screen) Validate() error {
|
||||
if len(msg.UserId) == 0 && len(msg.AnonymousId) == 0 {
|
||||
return FieldError{
|
||||
Type: "analytics.Screen",
|
||||
Name: "UserId",
|
||||
Value: msg.UserId,
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
16
vendor/gopkg.in/segmentio/analytics-go.v3/timeout_15.go
generated
vendored
Normal file
16
vendor/gopkg.in/segmentio/analytics-go.v3/timeout_15.go
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
// +build !go1.6
|
||||
|
||||
package analytics
|
||||
|
||||
import "net/http"
|
||||
|
||||
// http clients on versions of go before 1.6 only support timeout if the
|
||||
// transport implements the `CancelRequest` method.
|
||||
func supportsTimeout(transport http.RoundTripper) bool {
|
||||
_, ok := transport.(requestCanceler)
|
||||
return ok
|
||||
}
|
||||
|
||||
type requestCanceler interface {
|
||||
CancelRequest(*http.Request)
|
||||
}
|
||||
10
vendor/gopkg.in/segmentio/analytics-go.v3/timeout_16.go
generated
vendored
Normal file
10
vendor/gopkg.in/segmentio/analytics-go.v3/timeout_16.go
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
// +build go1.6
|
||||
|
||||
package analytics
|
||||
|
||||
import "net/http"
|
||||
|
||||
// http clients on versions of go after 1.6 always support timeout.
|
||||
func supportsTimeout(transport http.RoundTripper) bool {
|
||||
return true
|
||||
}
|
||||
46
vendor/gopkg.in/segmentio/analytics-go.v3/track.go
generated
vendored
Normal file
46
vendor/gopkg.in/segmentio/analytics-go.v3/track.go
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
package analytics
|
||||
|
||||
import "time"
|
||||
|
||||
var _ Message = (*Track)(nil)
|
||||
|
||||
// This type represents object sent in a track call as described in
|
||||
// https://segment.com/docs/libraries/http/#track
|
||||
type Track struct {
|
||||
// This field is exported for serialization purposes and shouldn't be set by
|
||||
// the application, its value is always overwritten by the library.
|
||||
Type string `json:"type,omitempty"`
|
||||
|
||||
MessageId string `json:"messageId,omitempty"`
|
||||
AnonymousId string `json:"anonymousId,omitempty"`
|
||||
UserId string `json:"userId,omitempty"`
|
||||
Event string `json:"event"`
|
||||
Timestamp time.Time `json:"timestamp,omitempty"`
|
||||
Context *Context `json:"context,omitempty"`
|
||||
Properties Properties `json:"properties,omitempty"`
|
||||
Integrations Integrations `json:"integrations,omitempty"`
|
||||
}
|
||||
|
||||
func (msg Track) internal() {
|
||||
panic(unimplementedError)
|
||||
}
|
||||
|
||||
func (msg Track) Validate() error {
|
||||
if len(msg.Event) == 0 {
|
||||
return FieldError{
|
||||
Type: "analytics.Track",
|
||||
Name: "Event",
|
||||
Value: msg.Event,
|
||||
}
|
||||
}
|
||||
|
||||
if len(msg.UserId) == 0 && len(msg.AnonymousId) == 0 {
|
||||
return FieldError{
|
||||
Type: "analytics.Track",
|
||||
Name: "UserId",
|
||||
Value: msg.UserId,
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user