worker: use openapi spec and generated code
Write an openapi spec for the worker API and use `deepmap/oapi-codegen`
to generate scaffolding for the server-side using the `labstack/echo`
server.
Incidentally, echo by default returns the errors in the same format that
worker API always has:
{ "message": "..." }
The API itself is unchanged to make this change easier to understand. It
will be changed to better suit our needs in future commits.
This commit is contained in:
parent
396c2cedce
commit
ad11ceecf4
112 changed files with 13721 additions and 389 deletions
4
go.mod
4
go.mod
|
|
@ -13,14 +13,16 @@ require (
|
|||
github.com/aws/aws-sdk-go v1.25.37
|
||||
github.com/coreos/go-semver v0.3.0
|
||||
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f
|
||||
github.com/deepmap/oapi-codegen v1.3.12
|
||||
github.com/gobwas/glob v0.2.3
|
||||
github.com/google/go-cmp v0.3.1
|
||||
github.com/google/uuid v1.1.1
|
||||
github.com/gophercloud/gophercloud v0.11.0
|
||||
github.com/julienschmidt/httprouter v1.2.0
|
||||
github.com/kolo/xmlrpc v0.0.0-20190909154602-56d5ec7c422e
|
||||
github.com/labstack/echo/v4 v4.1.11
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/stretchr/testify v1.4.0
|
||||
github.com/stretchr/testify v1.5.1
|
||||
github.com/ubccr/kerby v0.0.0-20170626144437-201a958fc453
|
||||
github.com/vmware/govmomi v0.23.0
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2 // indirect
|
||||
|
|
|
|||
41
go.sum
41
go.sum
|
|
@ -42,15 +42,26 @@ github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmf
|
|||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f h1:JOrtw2xFKzlg+cbHpyrpLDmnN1HqhBfnX7WDiW7eG2c=
|
||||
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4=
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-xdr v0.0.0-20161123171359-e6a2ba005892/go.mod h1:CTDl0pzVzE5DEzZhPfvhY/9sPFMQIxaJ9VAMs9AagrE=
|
||||
github.com/deepmap/oapi-codegen v1.3.12 h1:HiWZO0qMhSmqZH9VdbtsBK7lOSYYJ7jsa26DpydbEEw=
|
||||
github.com/deepmap/oapi-codegen v1.3.12/go.mod h1:suMvK7+rKlx3+tpa8ByptmvoXbAV70wERKTOGH3hLp0=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dimchansky/utfbom v1.1.0 h1:FcM3g+nofKgUteL8dm/UpdRXNC9KmADgTpLKsu0TRo4=
|
||||
github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8=
|
||||
github.com/getkin/kin-openapi v0.13.0 h1:03fqBEEgivp4MVK2ElB140B56hjO9ZFvFTHBsvFsSro=
|
||||
github.com/getkin/kin-openapi v0.13.0/go.mod h1:WGRs2ZMM1Q8LR1QBEwUxC6RJEfaBcD0s+pcEVXFuAjw=
|
||||
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/go-chi/chi v4.0.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
|
||||
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
||||
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
||||
github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGSh1pIozq4ZwCfxS0WA5JGXguxk94ar/4c87Y=
|
||||
github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/uuid v0.0.0-20170306145142-6a5e28554805/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
|
|
@ -69,10 +80,23 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
|
|||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/labstack/echo/v4 v4.1.11 h1:z0BZoArY4FqdpUEl+wlHp4hnr/oSR6MTmQmv8OHSoww=
|
||||
github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g=
|
||||
github.com/labstack/gommon v0.3.0 h1:JEeO0bvc78PKdyHxloTKiF8BD5iGrH8T6MSeGvSgob0=
|
||||
github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
|
||||
github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ=
|
||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
|
||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149 h1:HfxbT6/JcvIljmERptWhwa8XzP7H3T+Z2N26gTsaDaA=
|
||||
github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
|
||||
github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10=
|
||||
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
|
|
@ -81,24 +105,38 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
|
|||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/ubccr/kerby v0.0.0-20170626144437-201a958fc453 h1:rN0NwUFS6oK9ESlk2QyKfucb/gL4opUutNlCS2bBlvA=
|
||||
github.com/ubccr/kerby v0.0.0-20170626144437-201a958fc453/go.mod h1:s59e1aOY3F3KNsRx5W8cMdbtbt49aSKL7alLp6EKn48=
|
||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
|
||||
github.com/valyala/fasttemplate v1.1.0 h1:RZqt0yGBsps8NGvLSGW804QQqCUYYLsaOjTVHy1Ocw4=
|
||||
github.com/valyala/fasttemplate v1.1.0/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
|
||||
github.com/vmware/govmomi v0.23.0 h1:DC97v1FdSr3cPfq3eBKD5C1O4JtYxo+NTcbGTKe2k48=
|
||||
github.com/vmware/govmomi v0.23.0/go.mod h1:Y+Wq4lst78L85Ge/F8+ORXIWiKYqaro1vhAulACy9Lc=
|
||||
github.com/vmware/vmw-guestinfo v0.0.0-20170707015358-25eff159a728/go.mod h1:x9oS4Wk2s2u4tS29nEaDLdzvuHdB19CvSGJjPgkZJNk=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191112222119-e1110fd1c708/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20191202143827-86a70503ff7e/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413 h1:ULYEB3JvPRE/IfO+9uO7vKV/xzVTO7XPAwm8xbf4w2g=
|
||||
golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191112182307-2180aed22343/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191126235420-ef20fe5d7933/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/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4 h1:sfkvUWPNGwSV+8/fNqctR5lS2AqCSqYwXdrjCxp/dXo=
|
||||
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
|
@ -107,6 +145,7 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
|||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191203134012-c197fd4bf371/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
|
@ -119,3 +158,5 @@ gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
|||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
|
||||
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
|
|
|
|||
|
|
@ -35,8 +35,10 @@ BuildRequires: golang(github.com/Azure/azure-storage-blob-go/azblob)
|
|||
BuildRequires: golang(github.com/BurntSushi/toml)
|
||||
BuildRequires: golang(github.com/coreos/go-semver/semver)
|
||||
BuildRequires: golang(github.com/coreos/go-systemd/activation)
|
||||
BuildRequires: golang(github.com/deepmap/oapi-codegen/pkg/codegen)
|
||||
BuildRequires: golang(github.com/google/uuid)
|
||||
BuildRequires: golang(github.com/julienschmidt/httprouter)
|
||||
BuildRequires: golang(github.com/labstack/echo/v4)
|
||||
BuildRequires: golang(github.com/gobwas/glob)
|
||||
BuildRequires: golang(github.com/google/go-cmp/cmp)
|
||||
BuildRequires: golang(github.com/gophercloud/gophercloud)
|
||||
|
|
|
|||
154
internal/worker/api/api.gen.go
Normal file
154
internal/worker/api/api.gen.go
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
// Package api provides primitives to interact the openapi HTTP API.
|
||||
//
|
||||
// Code generated by github.com/deepmap/oapi-codegen DO NOT EDIT.
|
||||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/deepmap/oapi-codegen/pkg/runtime"
|
||||
"github.com/labstack/echo/v4"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// PostJobQueueV1JobsJSONBody defines parameters for PostJobQueueV1Jobs.
|
||||
type PostJobQueueV1JobsJSONBody map[string]interface{}
|
||||
|
||||
// PatchJobQueueV1JobsJobIdJSONBody defines parameters for PatchJobQueueV1JobsJobId.
|
||||
type PatchJobQueueV1JobsJobIdJSONBody struct {
|
||||
Result interface{} `json:"result"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
// PostJobQueueV1JobsRequestBody defines body for PostJobQueueV1Jobs for application/json ContentType.
|
||||
type PostJobQueueV1JobsJSONRequestBody PostJobQueueV1JobsJSONBody
|
||||
|
||||
// PatchJobQueueV1JobsJobIdRequestBody defines body for PatchJobQueueV1JobsJobId for application/json ContentType.
|
||||
type PatchJobQueueV1JobsJobIdJSONRequestBody PatchJobQueueV1JobsJobIdJSONBody
|
||||
|
||||
// ServerInterface represents all server handlers.
|
||||
type ServerInterface interface {
|
||||
// create-job
|
||||
// (POST /job-queue/v1/jobs)
|
||||
PostJobQueueV1Jobs(ctx echo.Context) error
|
||||
// get-job
|
||||
// (GET /job-queue/v1/jobs/{job_id})
|
||||
GetJobQueueV1JobsJobId(ctx echo.Context, jobId string) error
|
||||
// update-job
|
||||
// (PATCH /job-queue/v1/jobs/{job_id})
|
||||
PatchJobQueueV1JobsJobId(ctx echo.Context, jobId string) error
|
||||
// add-image
|
||||
// (POST /job-queue/v1/jobs/{job_id}/artifacts/{name})
|
||||
PostJobQueueV1JobsJobIdArtifactsName(ctx echo.Context, jobId string, name string) error
|
||||
// status
|
||||
// (GET /status)
|
||||
GetStatus(ctx echo.Context) error
|
||||
}
|
||||
|
||||
// ServerInterfaceWrapper converts echo contexts to parameters.
|
||||
type ServerInterfaceWrapper struct {
|
||||
Handler ServerInterface
|
||||
}
|
||||
|
||||
// PostJobQueueV1Jobs converts echo context to params.
|
||||
func (w *ServerInterfaceWrapper) PostJobQueueV1Jobs(ctx echo.Context) error {
|
||||
var err error
|
||||
|
||||
// Invoke the callback with all the unmarshalled arguments
|
||||
err = w.Handler.PostJobQueueV1Jobs(ctx)
|
||||
return err
|
||||
}
|
||||
|
||||
// GetJobQueueV1JobsJobId converts echo context to params.
|
||||
func (w *ServerInterfaceWrapper) GetJobQueueV1JobsJobId(ctx echo.Context) error {
|
||||
var err error
|
||||
// ------------- Path parameter "job_id" -------------
|
||||
var jobId string
|
||||
|
||||
err = runtime.BindStyledParameter("simple", false, "job_id", ctx.Param("job_id"), &jobId)
|
||||
if err != nil {
|
||||
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter job_id: %s", err))
|
||||
}
|
||||
|
||||
// Invoke the callback with all the unmarshalled arguments
|
||||
err = w.Handler.GetJobQueueV1JobsJobId(ctx, jobId)
|
||||
return err
|
||||
}
|
||||
|
||||
// PatchJobQueueV1JobsJobId converts echo context to params.
|
||||
func (w *ServerInterfaceWrapper) PatchJobQueueV1JobsJobId(ctx echo.Context) error {
|
||||
var err error
|
||||
// ------------- Path parameter "job_id" -------------
|
||||
var jobId string
|
||||
|
||||
err = runtime.BindStyledParameter("simple", false, "job_id", ctx.Param("job_id"), &jobId)
|
||||
if err != nil {
|
||||
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter job_id: %s", err))
|
||||
}
|
||||
|
||||
// Invoke the callback with all the unmarshalled arguments
|
||||
err = w.Handler.PatchJobQueueV1JobsJobId(ctx, jobId)
|
||||
return err
|
||||
}
|
||||
|
||||
// PostJobQueueV1JobsJobIdArtifactsName converts echo context to params.
|
||||
func (w *ServerInterfaceWrapper) PostJobQueueV1JobsJobIdArtifactsName(ctx echo.Context) error {
|
||||
var err error
|
||||
// ------------- Path parameter "job_id" -------------
|
||||
var jobId string
|
||||
|
||||
err = runtime.BindStyledParameter("simple", false, "job_id", ctx.Param("job_id"), &jobId)
|
||||
if err != nil {
|
||||
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter job_id: %s", err))
|
||||
}
|
||||
|
||||
// ------------- Path parameter "name" -------------
|
||||
var name string
|
||||
|
||||
err = runtime.BindStyledParameter("simple", false, "name", ctx.Param("name"), &name)
|
||||
if err != nil {
|
||||
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter name: %s", err))
|
||||
}
|
||||
|
||||
// Invoke the callback with all the unmarshalled arguments
|
||||
err = w.Handler.PostJobQueueV1JobsJobIdArtifactsName(ctx, jobId, name)
|
||||
return err
|
||||
}
|
||||
|
||||
// GetStatus converts echo context to params.
|
||||
func (w *ServerInterfaceWrapper) GetStatus(ctx echo.Context) error {
|
||||
var err error
|
||||
|
||||
// Invoke the callback with all the unmarshalled arguments
|
||||
err = w.Handler.GetStatus(ctx)
|
||||
return err
|
||||
}
|
||||
|
||||
// This is a simple interface which specifies echo.Route addition functions which
|
||||
// are present on both echo.Echo and echo.Group, since we want to allow using
|
||||
// either of them for path registration
|
||||
type EchoRouter interface {
|
||||
CONNECT(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
|
||||
DELETE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
|
||||
GET(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
|
||||
HEAD(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
|
||||
OPTIONS(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
|
||||
PATCH(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
|
||||
POST(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
|
||||
PUT(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
|
||||
TRACE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
|
||||
}
|
||||
|
||||
// RegisterHandlers adds each server route to the EchoRouter.
|
||||
func RegisterHandlers(router EchoRouter, si ServerInterface) {
|
||||
|
||||
wrapper := ServerInterfaceWrapper{
|
||||
Handler: si,
|
||||
}
|
||||
|
||||
router.POST("/job-queue/v1/jobs", wrapper.PostJobQueueV1Jobs)
|
||||
router.GET("/job-queue/v1/jobs/:job_id", wrapper.GetJobQueueV1JobsJobId)
|
||||
router.PATCH("/job-queue/v1/jobs/:job_id", wrapper.PatchJobQueueV1JobsJobId)
|
||||
router.POST("/job-queue/v1/jobs/:job_id/artifacts/:name", wrapper.PostJobQueueV1JobsJobIdArtifactsName)
|
||||
router.GET("/status", wrapper.GetStatus)
|
||||
|
||||
}
|
||||
3
internal/worker/api/api.go
Normal file
3
internal/worker/api/api.go
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen -package=api -generate types,server -o api.gen.go openapi.yml
|
||||
|
||||
package api
|
||||
133
internal/worker/api/openapi.yml
Normal file
133
internal/worker/api/openapi.yml
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
openapi: 3.0.0
|
||||
info:
|
||||
title: worker
|
||||
version: '1.0'
|
||||
servers: []
|
||||
paths:
|
||||
/status:
|
||||
get:
|
||||
summary: status
|
||||
tags: []
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
headers: {}
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
status:
|
||||
type: string
|
||||
enum:
|
||||
- OK
|
||||
required:
|
||||
- status
|
||||
operationId: get-status
|
||||
description: Simple status handler to check whether the service is up.
|
||||
/job-queue/v1/jobs:
|
||||
post:
|
||||
summary: create-job
|
||||
tags: []
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
format: uuid
|
||||
manifest: {}
|
||||
targets:
|
||||
type: array
|
||||
items: {}
|
||||
required:
|
||||
- id
|
||||
- manifest
|
||||
- targets
|
||||
operationId: post-job-queue-v1-jobs
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties: {}
|
||||
'/job-queue/v1/jobs/{job_id}':
|
||||
parameters:
|
||||
- schema:
|
||||
type: string
|
||||
name: job_id
|
||||
in: path
|
||||
required: true
|
||||
get:
|
||||
summary: get-job
|
||||
tags: []
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
format: uuid
|
||||
canceled:
|
||||
type: boolean
|
||||
required:
|
||||
- id
|
||||
- canceled
|
||||
operationId: get-job-queue-v1-jobs-job_id
|
||||
patch:
|
||||
summary: update-job
|
||||
tags: []
|
||||
responses: {}
|
||||
operationId: patch-job-queue-v1-jobs-job_id
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
status:
|
||||
type: string
|
||||
enum:
|
||||
- WAITING
|
||||
- RUNNING
|
||||
- FINISHED
|
||||
- FAILED
|
||||
result: {}
|
||||
required:
|
||||
- status
|
||||
- result
|
||||
'/job-queue/v1/jobs/{job_id}/artifacts/{name}':
|
||||
parameters:
|
||||
- schema:
|
||||
type: string
|
||||
name: job_id
|
||||
in: path
|
||||
required: true
|
||||
- schema:
|
||||
type: string
|
||||
name: name
|
||||
in: path
|
||||
required: true
|
||||
post:
|
||||
summary: add-image
|
||||
tags: []
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
operationId: post-job-queue-v1-jobs-job_id-artifacts-name
|
||||
requestBody:
|
||||
content:
|
||||
application/octet-stream:
|
||||
schema:
|
||||
type: string
|
||||
components:
|
||||
schemas: {}
|
||||
|
|
@ -13,18 +13,18 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/julienschmidt/httprouter"
|
||||
"github.com/labstack/echo/v4"
|
||||
|
||||
"github.com/osbuild/osbuild-composer/internal/common"
|
||||
"github.com/osbuild/osbuild-composer/internal/distro"
|
||||
"github.com/osbuild/osbuild-composer/internal/jobqueue"
|
||||
"github.com/osbuild/osbuild-composer/internal/target"
|
||||
"github.com/osbuild/osbuild-composer/internal/worker/api"
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
logger *log.Logger
|
||||
jobs jobqueue.JobQueue
|
||||
router *httprouter.Router
|
||||
echo *echo.Echo
|
||||
artifactsDir string
|
||||
}
|
||||
|
||||
|
|
@ -39,33 +39,23 @@ type JobStatus struct {
|
|||
|
||||
func NewServer(logger *log.Logger, jobs jobqueue.JobQueue, artifactsDir string) *Server {
|
||||
s := &Server{
|
||||
logger: logger,
|
||||
jobs: jobs,
|
||||
artifactsDir: artifactsDir,
|
||||
}
|
||||
|
||||
s.router = httprouter.New()
|
||||
s.router.RedirectTrailingSlash = false
|
||||
s.router.RedirectFixedPath = false
|
||||
s.router.MethodNotAllowed = http.HandlerFunc(methodNotAllowedHandler)
|
||||
s.router.NotFound = http.HandlerFunc(notFoundHandler)
|
||||
s.echo = echo.New()
|
||||
s.echo.Binder = binder{}
|
||||
s.echo.StdLogger = logger
|
||||
|
||||
// Add a basic status handler for checking if osbuild-composer is alive.
|
||||
s.router.GET("/status", s.statusHandler)
|
||||
|
||||
// Add handlers for managing jobs.
|
||||
s.router.POST("/job-queue/v1/jobs", s.addJobHandler)
|
||||
s.router.GET("/job-queue/v1/jobs/:job_id", s.jobHandler)
|
||||
s.router.PATCH("/job-queue/v1/jobs/:job_id", s.updateJobHandler)
|
||||
s.router.POST("/job-queue/v1/jobs/:job_id/artifacts/:name", s.addJobImageHandler)
|
||||
api.RegisterHandlers(s.echo, &apiHandlers{s})
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Server) Serve(listener net.Listener) error {
|
||||
server := http.Server{Handler: s}
|
||||
s.echo.Listener = listener
|
||||
|
||||
err := server.Serve(listener)
|
||||
err := s.echo.Start("")
|
||||
if err != nil && err != http.ErrServerClosed {
|
||||
return err
|
||||
}
|
||||
|
|
@ -74,12 +64,7 @@ func (s *Server) Serve(listener net.Listener) error {
|
|||
}
|
||||
|
||||
func (s *Server) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
|
||||
if s.logger != nil {
|
||||
log.Println(request.Method, request.URL.Path)
|
||||
}
|
||||
|
||||
writer.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
s.router.ServeHTTP(writer, request)
|
||||
s.echo.ServeHTTP(writer, request)
|
||||
}
|
||||
|
||||
func (s *Server) Enqueue(manifest distro.Manifest, targets []*target.Target) (uuid.UUID, error) {
|
||||
|
|
@ -166,168 +151,146 @@ func (s *Server) DeleteArtifacts(id uuid.UUID) error {
|
|||
return os.RemoveAll(path.Join(s.artifactsDir, id.String()))
|
||||
}
|
||||
|
||||
// jsonErrorf() is similar to http.Error(), but returns the message in a json
|
||||
// object with a "message" field.
|
||||
func jsonErrorf(writer http.ResponseWriter, code int, message string, args ...interface{}) {
|
||||
writer.WriteHeader(code)
|
||||
|
||||
// ignore error, because we cannot do anything useful with it
|
||||
_ = json.NewEncoder(writer).Encode(&errorResponse{
|
||||
Message: fmt.Sprintf(message, args...),
|
||||
})
|
||||
// apiHandlers implements api.ServerInterface - the http api route handlers
|
||||
// generated from api/openapi.yml. This is a separate object, because these
|
||||
// handlers should not be exposed on the `Server` object.
|
||||
type apiHandlers struct {
|
||||
server *Server
|
||||
}
|
||||
|
||||
func methodNotAllowedHandler(writer http.ResponseWriter, request *http.Request) {
|
||||
jsonErrorf(writer, http.StatusMethodNotAllowed, "method not allowed")
|
||||
}
|
||||
|
||||
func notFoundHandler(writer http.ResponseWriter, request *http.Request) {
|
||||
jsonErrorf(writer, http.StatusNotFound, "not found")
|
||||
}
|
||||
|
||||
func (s *Server) statusHandler(writer http.ResponseWriter, request *http.Request, _ httprouter.Params) {
|
||||
writer.WriteHeader(http.StatusOK)
|
||||
|
||||
// Send back a status message.
|
||||
_ = json.NewEncoder(writer).Encode(&statusResponse{
|
||||
func (h *apiHandlers) GetStatus(ctx echo.Context) error {
|
||||
return ctx.JSON(http.StatusOK, &statusResponse{
|
||||
Status: "OK",
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Server) jobHandler(writer http.ResponseWriter, request *http.Request, params httprouter.Params) {
|
||||
id, err := uuid.Parse(params.ByName("job_id"))
|
||||
func (h *apiHandlers) GetJobQueueV1JobsJobId(ctx echo.Context, jobId string) error {
|
||||
id, err := uuid.Parse(jobId)
|
||||
if err != nil {
|
||||
jsonErrorf(writer, http.StatusBadRequest, "cannot parse compose id: %v", err)
|
||||
return
|
||||
return echo.NewHTTPError(http.StatusBadRequest, "cannot parse compose id: %v", err)
|
||||
}
|
||||
|
||||
status, err := s.JobStatus(id)
|
||||
status, err := h.server.JobStatus(id)
|
||||
if err != nil {
|
||||
switch err {
|
||||
case jobqueue.ErrNotExist:
|
||||
jsonErrorf(writer, http.StatusNotFound, "job does not exist: %s", id)
|
||||
return echo.NewHTTPError(http.StatusNotFound, "job does not exist: %s", id)
|
||||
default:
|
||||
jsonErrorf(writer, http.StatusInternalServerError, "%v", err)
|
||||
return err
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
_ = json.NewEncoder(writer).Encode(jobResponse{
|
||||
return ctx.JSON(http.StatusOK, jobResponse{
|
||||
Id: id,
|
||||
Canceled: status.Canceled,
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Server) addJobHandler(writer http.ResponseWriter, request *http.Request, _ httprouter.Params) {
|
||||
contentType := request.Header["Content-Type"]
|
||||
if len(contentType) != 1 || contentType[0] != "application/json" {
|
||||
jsonErrorf(writer, http.StatusUnsupportedMediaType, "request must contain application/json data")
|
||||
return
|
||||
}
|
||||
|
||||
func (h *apiHandlers) PostJobQueueV1Jobs(ctx echo.Context) error {
|
||||
var body addJobRequest
|
||||
err := json.NewDecoder(request.Body).Decode(&body)
|
||||
err := ctx.Bind(&body)
|
||||
if err != nil {
|
||||
jsonErrorf(writer, http.StatusBadRequest, "%v", err)
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
var job OSBuildJob
|
||||
id, err := s.jobs.Dequeue(request.Context(), []string{"osbuild"}, &job)
|
||||
id, err := h.server.jobs.Dequeue(ctx.Request().Context(), []string{"osbuild"}, &job)
|
||||
if err != nil {
|
||||
jsonErrorf(writer, http.StatusInternalServerError, "%v", err)
|
||||
return
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, "%v", err)
|
||||
}
|
||||
|
||||
writer.WriteHeader(http.StatusCreated)
|
||||
// FIXME: handle or comment this possible error
|
||||
_ = json.NewEncoder(writer).Encode(addJobResponse{
|
||||
return ctx.JSON(http.StatusCreated, addJobResponse{
|
||||
Id: id,
|
||||
Manifest: job.Manifest,
|
||||
Targets: job.Targets,
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Server) updateJobHandler(writer http.ResponseWriter, request *http.Request, params httprouter.Params) {
|
||||
contentType := request.Header["Content-Type"]
|
||||
if len(contentType) != 1 || contentType[0] != "application/json" {
|
||||
jsonErrorf(writer, http.StatusUnsupportedMediaType, "request must contain application/json data")
|
||||
return
|
||||
}
|
||||
|
||||
id, err := uuid.Parse(params.ByName("job_id"))
|
||||
func (h *apiHandlers) PatchJobQueueV1JobsJobId(ctx echo.Context, jobId string) error {
|
||||
id, err := uuid.Parse(jobId)
|
||||
if err != nil {
|
||||
jsonErrorf(writer, http.StatusBadRequest, "cannot parse compose id: %v", err)
|
||||
return
|
||||
return echo.NewHTTPError(http.StatusBadRequest, "cannot parse compose id: %v", err)
|
||||
}
|
||||
|
||||
var body updateJobRequest
|
||||
err = json.NewDecoder(request.Body).Decode(&body)
|
||||
err = ctx.Bind(&body)
|
||||
if err != nil {
|
||||
jsonErrorf(writer, http.StatusBadRequest, "cannot parse request body: %v", err)
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
// The jobqueue doesn't support setting the status before a job is
|
||||
// finished. This branch should never be hit, because the worker
|
||||
// doesn't attempt this. Change the API to remove this awkwardness.
|
||||
if body.Status != common.IBFinished && body.Status != common.IBFailed {
|
||||
jsonErrorf(writer, http.StatusBadRequest, "setting status of a job to waiting or running is not supported")
|
||||
return
|
||||
return echo.NewHTTPError(http.StatusBadRequest, "setting status of a job to waiting or running is not supported")
|
||||
}
|
||||
|
||||
err = s.jobs.FinishJob(id, OSBuildJobResult{OSBuildOutput: body.Result})
|
||||
err = h.server.jobs.FinishJob(id, OSBuildJobResult{OSBuildOutput: body.Result})
|
||||
if err != nil {
|
||||
switch err {
|
||||
case jobqueue.ErrNotExist:
|
||||
jsonErrorf(writer, http.StatusNotFound, "job does not exist: %s", id)
|
||||
return echo.NewHTTPError(http.StatusNotFound, "job does not exist: %s", id)
|
||||
case jobqueue.ErrNotRunning:
|
||||
jsonErrorf(writer, http.StatusBadRequest, "job is not running: %s", id)
|
||||
return echo.NewHTTPError(http.StatusBadRequest, "job is not running: %s", id)
|
||||
default:
|
||||
jsonErrorf(writer, http.StatusInternalServerError, "%v", err)
|
||||
return err
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
_ = json.NewEncoder(writer).Encode(updateJobResponse{})
|
||||
return ctx.JSON(http.StatusOK, updateJobResponse{})
|
||||
}
|
||||
|
||||
func (s *Server) addJobImageHandler(writer http.ResponseWriter, request *http.Request, params httprouter.Params) {
|
||||
id, err := uuid.Parse(params.ByName("job_id"))
|
||||
func (h *apiHandlers) PostJobQueueV1JobsJobIdArtifactsName(ctx echo.Context, jobId string, name string) error {
|
||||
id, err := uuid.Parse(jobId)
|
||||
if err != nil {
|
||||
jsonErrorf(writer, http.StatusBadRequest, "cannot parse compose id: %v", err)
|
||||
return
|
||||
return echo.NewHTTPError(http.StatusBadRequest, "cannot parse compose id: %v", err)
|
||||
}
|
||||
|
||||
name := params.ByName("name")
|
||||
if name == "" {
|
||||
jsonErrorf(writer, http.StatusBadRequest, "invalid artifact name")
|
||||
return
|
||||
}
|
||||
request := ctx.Request()
|
||||
|
||||
if s.artifactsDir == "" {
|
||||
if h.server.artifactsDir == "" {
|
||||
_, err := io.Copy(ioutil.Discard, request.Body)
|
||||
if err != nil {
|
||||
jsonErrorf(writer, http.StatusInternalServerError, "error discarding artifact: %v", err)
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, "error discarding artifact: %v", err)
|
||||
}
|
||||
return
|
||||
return ctx.NoContent(http.StatusOK)
|
||||
}
|
||||
|
||||
err = os.Mkdir(path.Join(s.artifactsDir, id.String()), 0700)
|
||||
err = os.Mkdir(path.Join(h.server.artifactsDir, id.String()), 0700)
|
||||
if err != nil {
|
||||
jsonErrorf(writer, http.StatusInternalServerError, "cannot create artifact directory: %v", err)
|
||||
return
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, "cannot create artifact directory: %v", err)
|
||||
}
|
||||
|
||||
f, err := os.Create(path.Join(s.artifactsDir, id.String(), name))
|
||||
f, err := os.Create(path.Join(h.server.artifactsDir, id.String(), name))
|
||||
if err != nil {
|
||||
jsonErrorf(writer, http.StatusInternalServerError, "cannot create artifact file: %v", err)
|
||||
return
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, "cannot create artifact file: %v", err)
|
||||
}
|
||||
|
||||
_, err = io.Copy(f, request.Body)
|
||||
if err != nil {
|
||||
jsonErrorf(writer, http.StatusInternalServerError, "error writing artifact file: %v", err)
|
||||
return
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, "error writing artifact file: %v", err)
|
||||
}
|
||||
|
||||
return ctx.NoContent(http.StatusOK)
|
||||
}
|
||||
|
||||
// A simple echo.Binder(), which only accepts application/json, but is more
|
||||
// strict than echo's DefaultBinder. It does not handle binding query
|
||||
// parameters either.
|
||||
type binder struct{}
|
||||
|
||||
func (b binder) Bind(i interface{}, ctx echo.Context) error {
|
||||
request := ctx.Request()
|
||||
|
||||
contentType := request.Header["Content-Type"]
|
||||
if len(contentType) != 1 || contentType[0] != "application/json" {
|
||||
return echo.NewHTTPError(http.StatusUnsupportedMediaType, "request must be json-encoded")
|
||||
}
|
||||
|
||||
err := json.NewDecoder(request.Body).Decode(i)
|
||||
if err != nil {
|
||||
return echo.NewHTTPError(http.StatusBadRequest, "cannot parse request body: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,8 +39,10 @@ BuildRequires: golang(github.com/Azure/azure-storage-blob-go/azblob)
|
|||
BuildRequires: golang(github.com/BurntSushi/toml)
|
||||
BuildRequires: golang(github.com/coreos/go-semver/semver)
|
||||
BuildRequires: golang(github.com/coreos/go-systemd/activation)
|
||||
BuildRequires: golang(github.com/deepmap/oapi-codegen/pkg/codegen)
|
||||
BuildRequires: golang(github.com/google/uuid)
|
||||
BuildRequires: golang(github.com/julienschmidt/httprouter)
|
||||
BuildRequires: golang(github.com/labstack/echo/v4)
|
||||
BuildRequires: golang(github.com/gobwas/glob)
|
||||
BuildRequires: golang(github.com/google/go-cmp/cmp)
|
||||
BuildRequires: golang(github.com/gophercloud/gophercloud)
|
||||
|
|
|
|||
2
vendor/github.com/davecgh/go-spew/LICENSE
generated
vendored
2
vendor/github.com/davecgh/go-spew/LICENSE
generated
vendored
|
|
@ -2,7 +2,7 @@ ISC License
|
|||
|
||||
Copyright (c) 2012-2016 Dave Collins <dave@davec.name>
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
|
|
|
|||
187
vendor/github.com/davecgh/go-spew/spew/bypass.go
generated
vendored
187
vendor/github.com/davecgh/go-spew/spew/bypass.go
generated
vendored
|
|
@ -16,7 +16,9 @@
|
|||
// when the code is not running on Google App Engine, compiled by GopherJS, and
|
||||
// "-tags safe" is not added to the go build command line. The "disableunsafe"
|
||||
// tag is deprecated and thus should not be used.
|
||||
// +build !js,!appengine,!safe,!disableunsafe
|
||||
// Go versions prior to 1.4 are disabled because they use a different layout
|
||||
// for interfaces which make the implementation of unsafeReflectValue more complex.
|
||||
// +build !js,!appengine,!safe,!disableunsafe,go1.4
|
||||
|
||||
package spew
|
||||
|
||||
|
|
@ -34,80 +36,49 @@ const (
|
|||
ptrSize = unsafe.Sizeof((*byte)(nil))
|
||||
)
|
||||
|
||||
var (
|
||||
// offsetPtr, offsetScalar, and offsetFlag are the offsets for the
|
||||
// internal reflect.Value fields. These values are valid before golang
|
||||
// commit ecccf07e7f9d which changed the format. The are also valid
|
||||
// after commit 82f48826c6c7 which changed the format again to mirror
|
||||
// the original format. Code in the init function updates these offsets
|
||||
// as necessary.
|
||||
offsetPtr = uintptr(ptrSize)
|
||||
offsetScalar = uintptr(0)
|
||||
offsetFlag = uintptr(ptrSize * 2)
|
||||
type flag uintptr
|
||||
|
||||
// flagKindWidth and flagKindShift indicate various bits that the
|
||||
// reflect package uses internally to track kind information.
|
||||
//
|
||||
// flagRO indicates whether or not the value field of a reflect.Value is
|
||||
// read-only.
|
||||
//
|
||||
// flagIndir indicates whether the value field of a reflect.Value is
|
||||
// the actual data or a pointer to the data.
|
||||
//
|
||||
// These values are valid before golang commit 90a7c3c86944 which
|
||||
// changed their positions. Code in the init function updates these
|
||||
// flags as necessary.
|
||||
flagKindWidth = uintptr(5)
|
||||
flagKindShift = uintptr(flagKindWidth - 1)
|
||||
flagRO = uintptr(1 << 0)
|
||||
flagIndir = uintptr(1 << 1)
|
||||
var (
|
||||
// flagRO indicates whether the value field of a reflect.Value
|
||||
// is read-only.
|
||||
flagRO flag
|
||||
|
||||
// flagAddr indicates whether the address of the reflect.Value's
|
||||
// value may be taken.
|
||||
flagAddr flag
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Older versions of reflect.Value stored small integers directly in the
|
||||
// ptr field (which is named val in the older versions). Versions
|
||||
// between commits ecccf07e7f9d and 82f48826c6c7 added a new field named
|
||||
// scalar for this purpose which unfortunately came before the flag
|
||||
// field, so the offset of the flag field is different for those
|
||||
// versions.
|
||||
//
|
||||
// This code constructs a new reflect.Value from a known small integer
|
||||
// and checks if the size of the reflect.Value struct indicates it has
|
||||
// the scalar field. When it does, the offsets are updated accordingly.
|
||||
vv := reflect.ValueOf(0xf00)
|
||||
if unsafe.Sizeof(vv) == (ptrSize * 4) {
|
||||
offsetScalar = ptrSize * 2
|
||||
offsetFlag = ptrSize * 3
|
||||
}
|
||||
// flagKindMask holds the bits that make up the kind
|
||||
// part of the flags field. In all the supported versions,
|
||||
// it is in the lower 5 bits.
|
||||
const flagKindMask = flag(0x1f)
|
||||
|
||||
// Commit 90a7c3c86944 changed the flag positions such that the low
|
||||
// order bits are the kind. This code extracts the kind from the flags
|
||||
// field and ensures it's the correct type. When it's not, the flag
|
||||
// order has been changed to the newer format, so the flags are updated
|
||||
// accordingly.
|
||||
upf := unsafe.Pointer(uintptr(unsafe.Pointer(&vv)) + offsetFlag)
|
||||
upfv := *(*uintptr)(upf)
|
||||
flagKindMask := uintptr((1<<flagKindWidth - 1) << flagKindShift)
|
||||
if (upfv&flagKindMask)>>flagKindShift != uintptr(reflect.Int) {
|
||||
flagKindShift = 0
|
||||
flagRO = 1 << 5
|
||||
flagIndir = 1 << 6
|
||||
// Different versions of Go have used different
|
||||
// bit layouts for the flags type. This table
|
||||
// records the known combinations.
|
||||
var okFlags = []struct {
|
||||
ro, addr flag
|
||||
}{{
|
||||
// From Go 1.4 to 1.5
|
||||
ro: 1 << 5,
|
||||
addr: 1 << 7,
|
||||
}, {
|
||||
// Up to Go tip.
|
||||
ro: 1<<5 | 1<<6,
|
||||
addr: 1 << 8,
|
||||
}}
|
||||
|
||||
// Commit adf9b30e5594 modified the flags to separate the
|
||||
// flagRO flag into two bits which specifies whether or not the
|
||||
// field is embedded. This causes flagIndir to move over a bit
|
||||
// and means that flagRO is the combination of either of the
|
||||
// original flagRO bit and the new bit.
|
||||
//
|
||||
// This code detects the change by extracting what used to be
|
||||
// the indirect bit to ensure it's set. When it's not, the flag
|
||||
// order has been changed to the newer format, so the flags are
|
||||
// updated accordingly.
|
||||
if upfv&flagIndir == 0 {
|
||||
flagRO = 3 << 5
|
||||
flagIndir = 1 << 7
|
||||
}
|
||||
var flagValOffset = func() uintptr {
|
||||
field, ok := reflect.TypeOf(reflect.Value{}).FieldByName("flag")
|
||||
if !ok {
|
||||
panic("reflect.Value has no flag field")
|
||||
}
|
||||
return field.Offset
|
||||
}()
|
||||
|
||||
// flagField returns a pointer to the flag field of a reflect.Value.
|
||||
func flagField(v *reflect.Value) *flag {
|
||||
return (*flag)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) + flagValOffset))
|
||||
}
|
||||
|
||||
// unsafeReflectValue converts the passed reflect.Value into a one that bypasses
|
||||
|
|
@ -119,34 +90,56 @@ func init() {
|
|||
// This allows us to check for implementations of the Stringer and error
|
||||
// interfaces to be used for pretty printing ordinarily unaddressable and
|
||||
// inaccessible values such as unexported struct fields.
|
||||
func unsafeReflectValue(v reflect.Value) (rv reflect.Value) {
|
||||
indirects := 1
|
||||
vt := v.Type()
|
||||
upv := unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetPtr)
|
||||
rvf := *(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetFlag))
|
||||
if rvf&flagIndir != 0 {
|
||||
vt = reflect.PtrTo(v.Type())
|
||||
indirects++
|
||||
} else if offsetScalar != 0 {
|
||||
// The value is in the scalar field when it's not one of the
|
||||
// reference types.
|
||||
switch vt.Kind() {
|
||||
case reflect.Uintptr:
|
||||
case reflect.Chan:
|
||||
case reflect.Func:
|
||||
case reflect.Map:
|
||||
case reflect.Ptr:
|
||||
case reflect.UnsafePointer:
|
||||
default:
|
||||
upv = unsafe.Pointer(uintptr(unsafe.Pointer(&v)) +
|
||||
offsetScalar)
|
||||
func unsafeReflectValue(v reflect.Value) reflect.Value {
|
||||
if !v.IsValid() || (v.CanInterface() && v.CanAddr()) {
|
||||
return v
|
||||
}
|
||||
flagFieldPtr := flagField(&v)
|
||||
*flagFieldPtr &^= flagRO
|
||||
*flagFieldPtr |= flagAddr
|
||||
return v
|
||||
}
|
||||
|
||||
// Sanity checks against future reflect package changes
|
||||
// to the type or semantics of the Value.flag field.
|
||||
func init() {
|
||||
field, ok := reflect.TypeOf(reflect.Value{}).FieldByName("flag")
|
||||
if !ok {
|
||||
panic("reflect.Value has no flag field")
|
||||
}
|
||||
if field.Type.Kind() != reflect.TypeOf(flag(0)).Kind() {
|
||||
panic("reflect.Value flag field has changed kind")
|
||||
}
|
||||
type t0 int
|
||||
var t struct {
|
||||
A t0
|
||||
// t0 will have flagEmbedRO set.
|
||||
t0
|
||||
// a will have flagStickyRO set
|
||||
a t0
|
||||
}
|
||||
vA := reflect.ValueOf(t).FieldByName("A")
|
||||
va := reflect.ValueOf(t).FieldByName("a")
|
||||
vt0 := reflect.ValueOf(t).FieldByName("t0")
|
||||
|
||||
// Infer flagRO from the difference between the flags
|
||||
// for the (otherwise identical) fields in t.
|
||||
flagPublic := *flagField(&vA)
|
||||
flagWithRO := *flagField(&va) | *flagField(&vt0)
|
||||
flagRO = flagPublic ^ flagWithRO
|
||||
|
||||
// Infer flagAddr from the difference between a value
|
||||
// taken from a pointer and not.
|
||||
vPtrA := reflect.ValueOf(&t).Elem().FieldByName("A")
|
||||
flagNoPtr := *flagField(&vA)
|
||||
flagPtr := *flagField(&vPtrA)
|
||||
flagAddr = flagNoPtr ^ flagPtr
|
||||
|
||||
// Check that the inferred flags tally with one of the known versions.
|
||||
for _, f := range okFlags {
|
||||
if flagRO == f.ro && flagAddr == f.addr {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
pv := reflect.NewAt(vt, upv)
|
||||
rv = pv
|
||||
for i := 0; i < indirects; i++ {
|
||||
rv = rv.Elem()
|
||||
}
|
||||
return rv
|
||||
panic("reflect.Value read-only flag has changed semantics")
|
||||
}
|
||||
|
|
|
|||
2
vendor/github.com/davecgh/go-spew/spew/bypasssafe.go
generated
vendored
2
vendor/github.com/davecgh/go-spew/spew/bypasssafe.go
generated
vendored
|
|
@ -16,7 +16,7 @@
|
|||
// when the code is running on Google App Engine, compiled by GopherJS, or
|
||||
// "-tags safe" is added to the go build command line. The "disableunsafe"
|
||||
// tag is deprecated and thus should not be used.
|
||||
// +build js appengine safe disableunsafe
|
||||
// +build js appengine safe disableunsafe !go1.4
|
||||
|
||||
package spew
|
||||
|
||||
|
|
|
|||
2
vendor/github.com/davecgh/go-spew/spew/common.go
generated
vendored
2
vendor/github.com/davecgh/go-spew/spew/common.go
generated
vendored
|
|
@ -180,7 +180,7 @@ func printComplex(w io.Writer, c complex128, floatPrecision int) {
|
|||
w.Write(closeParenBytes)
|
||||
}
|
||||
|
||||
// printHexPtr outputs a uintptr formatted as hexidecimal with a leading '0x'
|
||||
// printHexPtr outputs a uintptr formatted as hexadecimal with a leading '0x'
|
||||
// prefix to Writer w.
|
||||
func printHexPtr(w io.Writer, p uintptr) {
|
||||
// Null pointer.
|
||||
|
|
|
|||
10
vendor/github.com/davecgh/go-spew/spew/dump.go
generated
vendored
10
vendor/github.com/davecgh/go-spew/spew/dump.go
generated
vendored
|
|
@ -35,16 +35,16 @@ var (
|
|||
|
||||
// cCharRE is a regular expression that matches a cgo char.
|
||||
// It is used to detect character arrays to hexdump them.
|
||||
cCharRE = regexp.MustCompile("^.*\\._Ctype_char$")
|
||||
cCharRE = regexp.MustCompile(`^.*\._Ctype_char$`)
|
||||
|
||||
// cUnsignedCharRE is a regular expression that matches a cgo unsigned
|
||||
// char. It is used to detect unsigned character arrays to hexdump
|
||||
// them.
|
||||
cUnsignedCharRE = regexp.MustCompile("^.*\\._Ctype_unsignedchar$")
|
||||
cUnsignedCharRE = regexp.MustCompile(`^.*\._Ctype_unsignedchar$`)
|
||||
|
||||
// cUint8tCharRE is a regular expression that matches a cgo uint8_t.
|
||||
// It is used to detect uint8_t arrays to hexdump them.
|
||||
cUint8tCharRE = regexp.MustCompile("^.*\\._Ctype_uint8_t$")
|
||||
cUint8tCharRE = regexp.MustCompile(`^.*\._Ctype_uint8_t$`)
|
||||
)
|
||||
|
||||
// dumpState contains information about the state of a dump operation.
|
||||
|
|
@ -143,10 +143,10 @@ func (d *dumpState) dumpPtr(v reflect.Value) {
|
|||
// Display dereferenced value.
|
||||
d.w.Write(openParenBytes)
|
||||
switch {
|
||||
case nilFound == true:
|
||||
case nilFound:
|
||||
d.w.Write(nilAngleBytes)
|
||||
|
||||
case cycleFound == true:
|
||||
case cycleFound:
|
||||
d.w.Write(circularBytes)
|
||||
|
||||
default:
|
||||
|
|
|
|||
4
vendor/github.com/davecgh/go-spew/spew/format.go
generated
vendored
4
vendor/github.com/davecgh/go-spew/spew/format.go
generated
vendored
|
|
@ -182,10 +182,10 @@ func (f *formatState) formatPtr(v reflect.Value) {
|
|||
|
||||
// Display dereferenced value.
|
||||
switch {
|
||||
case nilFound == true:
|
||||
case nilFound:
|
||||
f.fs.Write(nilAngleBytes)
|
||||
|
||||
case cycleFound == true:
|
||||
case cycleFound:
|
||||
f.fs.Write(circularShortBytes)
|
||||
|
||||
default:
|
||||
|
|
|
|||
201
vendor/github.com/deepmap/oapi-codegen/LICENSE
generated
vendored
Normal file
201
vendor/github.com/deepmap/oapi-codegen/LICENSE
generated
vendored
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
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.
|
||||
447
vendor/github.com/deepmap/oapi-codegen/pkg/runtime/bindparam.go
generated
vendored
Normal file
447
vendor/github.com/deepmap/oapi-codegen/pkg/runtime/bindparam.go
generated
vendored
Normal file
|
|
@ -0,0 +1,447 @@
|
|||
// Copyright 2019 DeepMap, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/deepmap/oapi-codegen/pkg/types"
|
||||
)
|
||||
|
||||
// This function binds a parameter as described in the Path Parameters
|
||||
// section here to a Go object:
|
||||
// https://swagger.io/docs/specification/serialization/
|
||||
func BindStyledParameter(style string, explode bool, paramName string,
|
||||
value string, dest interface{}) error {
|
||||
|
||||
if value == "" {
|
||||
return fmt.Errorf("parameter '%s' is empty, can't bind its value", paramName)
|
||||
}
|
||||
|
||||
// Everything comes in by pointer, dereference it
|
||||
v := reflect.Indirect(reflect.ValueOf(dest))
|
||||
|
||||
// This is the basic type of the destination object.
|
||||
t := v.Type()
|
||||
|
||||
if t.Kind() == reflect.Struct {
|
||||
// We've got a destination object, we'll create a JSON representation
|
||||
// of the input value, and let the json library deal with the unmarshaling
|
||||
parts, err := splitStyledParameter(style, explode, true, paramName, value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return bindSplitPartsToDestinationStruct(paramName, parts, explode, dest)
|
||||
}
|
||||
|
||||
if t.Kind() == reflect.Slice {
|
||||
// Chop up the parameter into parts based on its style
|
||||
parts, err := splitStyledParameter(style, explode, false, paramName, value)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error splitting input '%s' into parts: %s", value, err)
|
||||
}
|
||||
|
||||
return bindSplitPartsToDestinationArray(parts, dest)
|
||||
}
|
||||
|
||||
// Try to bind the remaining types as a base type.
|
||||
return BindStringToObject(value, dest)
|
||||
}
|
||||
|
||||
// This is a complex set of operations, but each given parameter style can be
|
||||
// packed together in multiple ways, using different styles of separators, and
|
||||
// different packing strategies based on the explode flag. This function takes
|
||||
// as input any parameter format, and unpacks it to a simple list of strings
|
||||
// or key-values which we can then treat generically.
|
||||
// Why, oh why, great Swagger gods, did you have to make this so complicated?
|
||||
func splitStyledParameter(style string, explode bool, object bool, paramName string, value string) ([]string, error) {
|
||||
switch style {
|
||||
case "simple":
|
||||
// In the simple case, we always split on comma
|
||||
parts := strings.Split(value, ",")
|
||||
return parts, nil
|
||||
case "label":
|
||||
// In the label case, it's more tricky. In the no explode case, we have
|
||||
// /users/.3,4,5 for arrays
|
||||
// /users/.role,admin,firstName,Alex for objects
|
||||
// in the explode case, we have:
|
||||
// /users/.3.4.5
|
||||
// /users/.role=admin.firstName=Alex
|
||||
if explode {
|
||||
// In the exploded case, split everything on periods.
|
||||
parts := strings.Split(value, ".")
|
||||
// The first part should be an empty string because we have a
|
||||
// leading period.
|
||||
if parts[0] != "" {
|
||||
return nil, fmt.Errorf("invalid format for label parameter '%s', should start with '.'", paramName)
|
||||
}
|
||||
return parts[1:], nil
|
||||
|
||||
} else {
|
||||
// In the unexploded case, we strip off the leading period.
|
||||
if value[0] != '.' {
|
||||
return nil, fmt.Errorf("invalid format for label parameter '%s', should start with '.'", paramName)
|
||||
}
|
||||
// The rest is comma separated.
|
||||
return strings.Split(value[1:], ","), nil
|
||||
}
|
||||
|
||||
case "matrix":
|
||||
if explode {
|
||||
// In the exploded case, we break everything up on semicolon
|
||||
parts := strings.Split(value, ";")
|
||||
// The first part should always be empty string, since we started
|
||||
// with ;something
|
||||
if parts[0] != "" {
|
||||
return nil, fmt.Errorf("invalid format for matrix parameter '%s', should start with ';'", paramName)
|
||||
}
|
||||
parts = parts[1:]
|
||||
// Now, if we have an object, we just have a list of x=y statements.
|
||||
// for a non-object, like an array, we have id=x, id=y. id=z, etc,
|
||||
// so we need to strip the prefix from each of them.
|
||||
if !object {
|
||||
prefix := paramName + "="
|
||||
for i := range parts {
|
||||
parts[i] = strings.TrimPrefix(parts[i], prefix)
|
||||
}
|
||||
}
|
||||
return parts, nil
|
||||
} else {
|
||||
// In the unexploded case, parameters will start with ;paramName=
|
||||
prefix := ";" + paramName + "="
|
||||
if !strings.HasPrefix(value, prefix) {
|
||||
return nil, fmt.Errorf("expected parameter '%s' to start with %s", paramName, prefix)
|
||||
}
|
||||
str := strings.TrimPrefix(value, prefix)
|
||||
return strings.Split(str, ","), nil
|
||||
}
|
||||
case "form":
|
||||
var parts []string
|
||||
if explode {
|
||||
parts = strings.Split(value, "&")
|
||||
if !object {
|
||||
prefix := paramName + "="
|
||||
for i := range parts {
|
||||
parts[i] = strings.TrimPrefix(parts[i], prefix)
|
||||
}
|
||||
}
|
||||
return parts, nil
|
||||
} else {
|
||||
parts = strings.Split(value, ",")
|
||||
prefix := paramName + "="
|
||||
for i := range parts {
|
||||
parts[i] = strings.TrimPrefix(parts[i], prefix)
|
||||
}
|
||||
}
|
||||
return parts, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("unhandled parameter style: %s", style)
|
||||
}
|
||||
|
||||
// Given a set of values as a slice, create a slice to hold them all, and
|
||||
// assign to each one by one.
|
||||
func bindSplitPartsToDestinationArray(parts []string, dest interface{}) error {
|
||||
// Everything comes in by pointer, dereference it
|
||||
v := reflect.Indirect(reflect.ValueOf(dest))
|
||||
|
||||
// This is the basic type of the destination object.
|
||||
t := v.Type()
|
||||
|
||||
// We've got a destination array, bind each object one by one.
|
||||
// This generates a slice of the correct element type and length to
|
||||
// hold all the parts.
|
||||
newArray := reflect.MakeSlice(t, len(parts), len(parts))
|
||||
for i, p := range parts {
|
||||
err := BindStringToObject(p, newArray.Index(i).Addr().Interface())
|
||||
if err != nil {
|
||||
return fmt.Errorf("error setting array element: %s", err)
|
||||
}
|
||||
}
|
||||
v.Set(newArray)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Given a set of chopped up parameter parts, bind them to a destination
|
||||
// struct. The exploded parameter controls whether we send key value pairs
|
||||
// in the exploded case, or a sequence of values which are interpreted as
|
||||
// tuples.
|
||||
// Given the struct Id { firstName string, role string }, as in the canonical
|
||||
// swagger examples, in the exploded case, we would pass
|
||||
// ["firstName=Alex", "role=admin"], where in the non-exploded case, we would
|
||||
// pass "firstName", "Alex", "role", "admin"]
|
||||
//
|
||||
// We punt the hard work of binding these values to the object to the json
|
||||
// library. We'll turn those arrays into JSON strings, and unmarshal
|
||||
// into the struct.
|
||||
func bindSplitPartsToDestinationStruct(paramName string, parts []string, explode bool, dest interface{}) error {
|
||||
// We've got a destination object, we'll create a JSON representation
|
||||
// of the input value, and let the json library deal with the unmarshaling
|
||||
var fields []string
|
||||
if explode {
|
||||
fields = make([]string, len(parts))
|
||||
for i, property := range parts {
|
||||
propertyParts := strings.Split(property, "=")
|
||||
if len(propertyParts) != 2 {
|
||||
return fmt.Errorf("parameter '%s' has invalid exploded format", paramName)
|
||||
}
|
||||
fields[i] = "\"" + propertyParts[0] + "\":\"" + propertyParts[1] + "\""
|
||||
}
|
||||
} else {
|
||||
if len(parts)%2 != 0 {
|
||||
return fmt.Errorf("parameter '%s' has invalid format, property/values need to be pairs", paramName)
|
||||
}
|
||||
fields = make([]string, len(parts)/2)
|
||||
for i := 0; i < len(parts); i += 2 {
|
||||
key := parts[i]
|
||||
value := parts[i+1]
|
||||
fields[i/2] = "\"" + key + "\":\"" + value + "\""
|
||||
}
|
||||
}
|
||||
jsonParam := "{" + strings.Join(fields, ",") + "}"
|
||||
err := json.Unmarshal([]byte(jsonParam), dest)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error binding parameter %s fields: %s", paramName, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// This works much like BindStyledParameter, however it takes a query argument
|
||||
// input array from the url package, since query arguments come through a
|
||||
// different path than the styled arguments. They're also exceptionally fussy.
|
||||
// For example, consider the exploded and unexploded form parameter examples:
|
||||
// (exploded) /users?role=admin&firstName=Alex
|
||||
// (unexploded) /users?id=role,admin,firstName,Alex
|
||||
//
|
||||
// In the first case, we can pull the "id" parameter off the context,
|
||||
// and unmarshal via json as an intermediate. Easy. In the second case, we
|
||||
// don't have the id QueryParam present, but must find "role", and "firstName".
|
||||
// what if there is another parameter similar to "ID" named "role"? We can't
|
||||
// tell them apart. This code tries to fail, but the moral of the story is that
|
||||
// you shouldn't pass objects via form styled query arguments, just use
|
||||
// the Content parameter form.
|
||||
func BindQueryParameter(style string, explode bool, required bool, paramName string,
|
||||
queryParams url.Values, dest interface{}) error {
|
||||
|
||||
// dv = destination value.
|
||||
dv := reflect.Indirect(reflect.ValueOf(dest))
|
||||
|
||||
// intermediate value form which is either dv or dv dereferenced.
|
||||
v := dv
|
||||
|
||||
// inner code will bind the string's value to this interface.
|
||||
var output interface{}
|
||||
|
||||
if required {
|
||||
// If the parameter is required, then the generated code will pass us
|
||||
// a pointer to it: &int, &object, and so forth. We can directly set
|
||||
// them.
|
||||
output = dest
|
||||
} else {
|
||||
// For optional parameters, we have an extra indirect. An optional
|
||||
// parameter of type "int" will be *int on the struct. We pass that
|
||||
// in by pointer, and have **int.
|
||||
|
||||
// If the destination, is a nil pointer, we need to allocate it.
|
||||
if v.IsNil() {
|
||||
t := v.Type()
|
||||
newValue := reflect.New(t.Elem())
|
||||
// for now, hang onto the output buffer separately from destination,
|
||||
// as we don't want to write anything to destination until we can
|
||||
// unmarshal successfully, and check whether a field is required.
|
||||
output = newValue.Interface()
|
||||
} else {
|
||||
// If the destination isn't nil, just use that.
|
||||
output = v.Interface()
|
||||
}
|
||||
|
||||
// Get rid of that extra indirect as compared to the required case,
|
||||
// so the code below doesn't have to care.
|
||||
v = reflect.Indirect(reflect.ValueOf(output))
|
||||
}
|
||||
|
||||
// This is the basic type of the destination object.
|
||||
t := v.Type()
|
||||
k := t.Kind()
|
||||
|
||||
switch style {
|
||||
case "form":
|
||||
var parts []string
|
||||
if explode {
|
||||
// ok, the explode case in query arguments is very, very annoying,
|
||||
// because an exploded object, such as /users?role=admin&firstName=Alex
|
||||
// isn't actually present in the parameter array. We have to do
|
||||
// different things based on destination type.
|
||||
values, found := queryParams[paramName]
|
||||
var err error
|
||||
|
||||
switch k {
|
||||
case reflect.Slice:
|
||||
// In the slice case, we simply use the arguments provided by
|
||||
// http library.
|
||||
if !found {
|
||||
if required {
|
||||
return fmt.Errorf("query parameter '%s' is required", paramName)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
err = bindSplitPartsToDestinationArray(values, output)
|
||||
case reflect.Struct:
|
||||
// This case is really annoying, and error prone, but the
|
||||
// form style object binding doesn't tell us which arguments
|
||||
// in the query string correspond to the object's fields. We'll
|
||||
// try to bind field by field.
|
||||
err = bindParamsToExplodedObject(paramName, queryParams, output)
|
||||
default:
|
||||
// Primitive object case. We expect to have 1 value to
|
||||
// unmarshal.
|
||||
if len(values) == 0 {
|
||||
if required {
|
||||
return fmt.Errorf("query parameter '%s' is required", paramName)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
if len(values) != 1 {
|
||||
return fmt.Errorf("multiple values for single value parameter '%s'", paramName)
|
||||
}
|
||||
err = BindStringToObject(values[0], output)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// If the parameter is required, and we've successfully unmarshaled
|
||||
// it, this assigns the new object to the pointer pointer.
|
||||
if !required {
|
||||
dv.Set(reflect.ValueOf(output))
|
||||
}
|
||||
return nil
|
||||
} else {
|
||||
values, found := queryParams[paramName]
|
||||
if !found {
|
||||
if required {
|
||||
return fmt.Errorf("query parameter '%s' is required", paramName)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
if len(values) != 1 {
|
||||
return fmt.Errorf("parameter '%s' is not exploded, but is specified multiple times", paramName)
|
||||
}
|
||||
parts = strings.Split(values[0], ",")
|
||||
}
|
||||
var err error
|
||||
switch k {
|
||||
case reflect.Slice:
|
||||
err = bindSplitPartsToDestinationArray(parts, output)
|
||||
case reflect.Struct:
|
||||
err = bindSplitPartsToDestinationStruct(paramName, parts, explode, output)
|
||||
default:
|
||||
if len(parts) == 0 {
|
||||
if required {
|
||||
return fmt.Errorf("query parameter '%s' is required", paramName)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
if len(parts) != 1 {
|
||||
return fmt.Errorf("multiple values for single value parameter '%s'", paramName)
|
||||
}
|
||||
err = BindStringToObject(parts[0], output)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !required {
|
||||
dv.Set(reflect.ValueOf(output))
|
||||
}
|
||||
return nil
|
||||
case "deepObject":
|
||||
if !explode {
|
||||
return errors.New("deepObjects must be exploded")
|
||||
}
|
||||
return UnmarshalDeepObject(dest, paramName, queryParams)
|
||||
case "spaceDelimited", "pipeDelimited":
|
||||
return fmt.Errorf("query arguments of style '%s' aren't yet supported", style)
|
||||
default:
|
||||
return fmt.Errorf("style '%s' on parameter '%s' is invalid", style, paramName)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// This function reflects the destination structure, and pulls the value for
|
||||
// each settable field from the given parameters map. This is to deal with the
|
||||
// exploded form styled object which may occupy any number of parameter names.
|
||||
// We don't try to be smart here, if the field exists as a query argument,
|
||||
// set its value.
|
||||
func bindParamsToExplodedObject(paramName string, values url.Values, dest interface{}) error {
|
||||
// special handling for custom types
|
||||
switch dest.(type) {
|
||||
case *types.Date:
|
||||
return BindStringToObject(values.Get(paramName), dest)
|
||||
case *time.Time:
|
||||
return BindStringToObject(values.Get(paramName), dest)
|
||||
|
||||
}
|
||||
|
||||
v := reflect.Indirect(reflect.ValueOf(dest))
|
||||
if v.Type().Kind() != reflect.Struct {
|
||||
return fmt.Errorf("unmarshaling query arg '%s' into wrong type", paramName)
|
||||
}
|
||||
|
||||
t := v.Type()
|
||||
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
fieldT := t.Field(i)
|
||||
|
||||
// Skip unsettable fields, such as internal ones.
|
||||
if !v.Field(i).CanSet() {
|
||||
continue
|
||||
}
|
||||
|
||||
// Find the json annotation on the field, and use the json specified
|
||||
// name if available, otherwise, just the field name.
|
||||
tag := fieldT.Tag.Get("json")
|
||||
fieldName := fieldT.Name
|
||||
if tag != "" {
|
||||
tagParts := strings.Split(tag, ",")
|
||||
name := tagParts[0]
|
||||
if name != "" {
|
||||
fieldName = name
|
||||
}
|
||||
}
|
||||
|
||||
// At this point, we look up field name in the parameter list.
|
||||
fieldVal, found := values[fieldName]
|
||||
if found {
|
||||
if len(fieldVal) != 1 {
|
||||
return fmt.Errorf("field '%s' specified multiple times for param '%s'", fieldName, paramName)
|
||||
}
|
||||
err := BindStringToObject(fieldVal[0], v.Field(i).Addr().Interface())
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not bind query arg '%s' to request object: %s'", paramName, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
116
vendor/github.com/deepmap/oapi-codegen/pkg/runtime/bindstring.go
generated
vendored
Normal file
116
vendor/github.com/deepmap/oapi-codegen/pkg/runtime/bindstring.go
generated
vendored
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
// Copyright 2019 DeepMap, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/deepmap/oapi-codegen/pkg/types"
|
||||
)
|
||||
|
||||
// This function takes a string, and attempts to assign it to the destination
|
||||
// interface via whatever type conversion is necessary. We have to do this
|
||||
// via reflection instead of a much simpler type switch so that we can handle
|
||||
// type aliases. This function was the easy way out, the better way, since we
|
||||
// know the destination type each place that we use this, is to generate code
|
||||
// to read each specific type.
|
||||
func BindStringToObject(src string, dst interface{}) error {
|
||||
var err error
|
||||
|
||||
v := reflect.ValueOf(dst)
|
||||
t := reflect.TypeOf(dst)
|
||||
|
||||
// We need to dereference pointers
|
||||
if t.Kind() == reflect.Ptr {
|
||||
v = reflect.Indirect(v)
|
||||
t = v.Type()
|
||||
}
|
||||
|
||||
// The resulting type must be settable. reflect will catch issues like
|
||||
// passing the destination by value.
|
||||
if !v.CanSet() {
|
||||
return errors.New("destination is not settable")
|
||||
}
|
||||
|
||||
switch t.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
var val int64
|
||||
val, err = strconv.ParseInt(src, 10, 64)
|
||||
if err == nil {
|
||||
v.SetInt(val)
|
||||
}
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
var val uint64
|
||||
val, err = strconv.ParseUint(src, 10, 64)
|
||||
if err == nil {
|
||||
v.SetUint(val)
|
||||
}
|
||||
case reflect.String:
|
||||
v.SetString(src)
|
||||
err = nil
|
||||
case reflect.Float64, reflect.Float32:
|
||||
var val float64
|
||||
val, err = strconv.ParseFloat(src, 64)
|
||||
if err == nil {
|
||||
v.SetFloat(val)
|
||||
}
|
||||
case reflect.Bool:
|
||||
var val bool
|
||||
val, err = strconv.ParseBool(src)
|
||||
if err == nil {
|
||||
v.SetBool(val)
|
||||
}
|
||||
case reflect.Struct:
|
||||
switch dstType := dst.(type) {
|
||||
case *time.Time:
|
||||
// Don't fail on empty string.
|
||||
if src == "" {
|
||||
return nil
|
||||
}
|
||||
// Time is a special case of a struct that we handle
|
||||
parsedTime, err := time.Parse(time.RFC3339Nano, src)
|
||||
if err != nil {
|
||||
parsedTime, err = time.Parse(types.DateFormat, src)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error parsing '%s' as RFC3339 or 2006-01-02 time: %s", src, err)
|
||||
}
|
||||
}
|
||||
*dstType = parsedTime
|
||||
return nil
|
||||
case *types.Date:
|
||||
// Don't fail on empty string.
|
||||
if src == "" {
|
||||
return nil
|
||||
}
|
||||
parsedTime, err := time.Parse(types.DateFormat, src)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error parsing '%s' as date: %s", src, err)
|
||||
}
|
||||
dstType.Time = parsedTime
|
||||
return nil
|
||||
}
|
||||
fallthrough
|
||||
default:
|
||||
// We've got a bunch of types unimplemented, don't fail silently.
|
||||
err = fmt.Errorf("can not bind to destination of type: %s", t.Kind())
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("error binding string parameter: %s", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
332
vendor/github.com/deepmap/oapi-codegen/pkg/runtime/deepobject.go
generated
vendored
Normal file
332
vendor/github.com/deepmap/oapi-codegen/pkg/runtime/deepobject.go
generated
vendored
Normal file
|
|
@ -0,0 +1,332 @@
|
|||
package runtime
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/deepmap/oapi-codegen/pkg/types"
|
||||
)
|
||||
|
||||
func marshalDeepObject(in interface{}, path []string) ([]string, error) {
|
||||
var result []string
|
||||
|
||||
switch t := in.(type) {
|
||||
case []interface{}:
|
||||
// For the array, we will use numerical subscripts of the form [x],
|
||||
// in the same order as the array.
|
||||
for i, iface := range t {
|
||||
newPath := append(path, strconv.Itoa(i))
|
||||
fields, err := marshalDeepObject(iface, newPath)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "error traversing array")
|
||||
}
|
||||
result = append(result, fields...)
|
||||
}
|
||||
case map[string]interface{}:
|
||||
// For a map, each key (field name) becomes a member of the path, and
|
||||
// we recurse. First, sort the keys.
|
||||
keys := make([]string, len(t))
|
||||
i := 0
|
||||
for k := range t {
|
||||
keys[i] = k
|
||||
i++
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
// Now, for each key, we recursively marshal it.
|
||||
for _, k := range keys {
|
||||
newPath := append(path, k)
|
||||
fields, err := marshalDeepObject(t[k], newPath)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "error traversing map")
|
||||
}
|
||||
result = append(result, fields...)
|
||||
}
|
||||
default:
|
||||
// Now, for a concrete value, we will turn the path elements
|
||||
// into a deepObject style set of subscripts. [a, b, c] turns into
|
||||
// [a][b][c]
|
||||
prefix := "[" + strings.Join(path, "][") + "]"
|
||||
result = []string{
|
||||
prefix + fmt.Sprintf("=%v", t),
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func MarshalDeepObject(i interface{}, paramName string) (string, error) {
|
||||
// We're going to marshal to JSON and unmarshal into an interface{},
|
||||
// which will use the json pkg to deal with all the field annotations. We
|
||||
// can then walk the generic object structure to produce a deepObject. This
|
||||
// isn't efficient and it would be more efficient to reflect on our own,
|
||||
// but it's complicated, error-prone code.
|
||||
buf, err := json.Marshal(i)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "failed to marshal input to JSON")
|
||||
}
|
||||
var i2 interface{}
|
||||
err = json.Unmarshal(buf, &i2)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "failed to unmarshal JSON")
|
||||
}
|
||||
fields, err := marshalDeepObject(i2, nil)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "error traversing JSON structure")
|
||||
}
|
||||
|
||||
// Prefix the param name to each subscripted field.
|
||||
for i := range fields {
|
||||
fields[i] = paramName + fields[i]
|
||||
}
|
||||
return strings.Join(fields, "&"), nil
|
||||
}
|
||||
|
||||
type fieldOrValue struct {
|
||||
fields map[string]fieldOrValue
|
||||
value string
|
||||
}
|
||||
|
||||
func (f *fieldOrValue) appendPathValue(path []string, value string) {
|
||||
fieldName := path[0]
|
||||
if len(path) == 1 {
|
||||
f.fields[fieldName] = fieldOrValue{value: value}
|
||||
return
|
||||
}
|
||||
|
||||
pv, found := f.fields[fieldName]
|
||||
if !found {
|
||||
pv = fieldOrValue{
|
||||
fields: make(map[string]fieldOrValue),
|
||||
}
|
||||
f.fields[fieldName] = pv
|
||||
}
|
||||
pv.appendPathValue(path[1:], value)
|
||||
}
|
||||
|
||||
func makeFieldOrValue(paths [][]string, values []string) fieldOrValue {
|
||||
|
||||
f := fieldOrValue{
|
||||
fields: make(map[string]fieldOrValue),
|
||||
}
|
||||
for i := range paths {
|
||||
path := paths[i]
|
||||
value := values[i]
|
||||
f.appendPathValue(path, value)
|
||||
}
|
||||
return f
|
||||
}
|
||||
|
||||
func UnmarshalDeepObject(dst interface{}, paramName string, params url.Values) error {
|
||||
// Params are all the query args, so we need those that look like
|
||||
// "paramName["...
|
||||
var fieldNames []string
|
||||
var fieldValues []string
|
||||
searchStr := paramName + "["
|
||||
for pName, pValues := range params {
|
||||
if strings.HasPrefix(pName, searchStr) {
|
||||
// trim the parameter name from the full name.
|
||||
pName = pName[len(paramName):]
|
||||
fieldNames = append(fieldNames, pName)
|
||||
if len(pValues) != 1 {
|
||||
return fmt.Errorf("%s has multiple values", pName)
|
||||
}
|
||||
fieldValues = append(fieldValues, pValues[0])
|
||||
}
|
||||
}
|
||||
|
||||
// Now, for each field, reconstruct its subscript path and value
|
||||
paths := make([][]string, len(fieldNames))
|
||||
for i, path := range fieldNames {
|
||||
path = strings.TrimLeft(path, "[")
|
||||
path = strings.TrimRight(path, "]")
|
||||
paths[i] = strings.Split(path, "][")
|
||||
}
|
||||
|
||||
fieldPaths := makeFieldOrValue(paths, fieldValues)
|
||||
err := assignPathValues(dst, fieldPaths)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error assigning value to destination")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// This returns a field name, either using the variable name, or the json
|
||||
// annotation if that exists.
|
||||
func getFieldName(f reflect.StructField) string {
|
||||
n := f.Name
|
||||
tag, found := f.Tag.Lookup("json")
|
||||
if found {
|
||||
// If we have a json field, and the first part of it before the
|
||||
// first comma is non-empty, that's our field name.
|
||||
parts := strings.Split(tag, ",")
|
||||
if parts[0] != "" {
|
||||
n = parts[0]
|
||||
}
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
// Create a map of field names that we'll see in the deepObject to reflect
|
||||
// field indices on the given type.
|
||||
func fieldIndicesByJsonTag(i interface{}) (map[string]int, error) {
|
||||
t := reflect.TypeOf(i)
|
||||
if t.Kind() != reflect.Struct {
|
||||
return nil, errors.New("expected a struct as input")
|
||||
}
|
||||
|
||||
n := t.NumField()
|
||||
fieldMap := make(map[string]int)
|
||||
for i := 0; i < n; i++ {
|
||||
field := t.Field(i)
|
||||
fieldName := getFieldName(field)
|
||||
fieldMap[fieldName] = i
|
||||
}
|
||||
return fieldMap, nil
|
||||
}
|
||||
|
||||
func assignPathValues(dst interface{}, pathValues fieldOrValue) error {
|
||||
//t := reflect.TypeOf(dst)
|
||||
v := reflect.ValueOf(dst)
|
||||
|
||||
iv := reflect.Indirect(v)
|
||||
it := iv.Type()
|
||||
|
||||
switch it.Kind() {
|
||||
case reflect.Slice:
|
||||
sliceLength := len(pathValues.fields)
|
||||
dstSlice := reflect.MakeSlice(it, sliceLength, sliceLength)
|
||||
err := assignSlice(dstSlice, pathValues)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error assigning slice")
|
||||
}
|
||||
iv.Set(dstSlice)
|
||||
return nil
|
||||
case reflect.Struct:
|
||||
// Some special types we care about are structs. Handle them
|
||||
// here.
|
||||
if _, isDate := iv.Interface().(types.Date); isDate {
|
||||
var date types.Date
|
||||
var err error
|
||||
date.Time, err = time.Parse(types.DateFormat, pathValues.value)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "invalid date format")
|
||||
}
|
||||
iv.Set(reflect.ValueOf(date))
|
||||
}
|
||||
if _, isTime := iv.Interface().(time.Time); isTime {
|
||||
var tm time.Time
|
||||
var err error
|
||||
tm, err = time.Parse(types.DateFormat, pathValues.value)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "invalid date format")
|
||||
}
|
||||
iv.Set(reflect.ValueOf(tm))
|
||||
}
|
||||
|
||||
fieldMap, err := fieldIndicesByJsonTag(iv.Interface())
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed enumerating fields")
|
||||
}
|
||||
for _, fieldName := range sortedFieldOrValueKeys(pathValues.fields) {
|
||||
fieldValue := pathValues.fields[fieldName]
|
||||
fieldIndex, found := fieldMap[fieldName]
|
||||
if !found {
|
||||
return fmt.Errorf("field [%s] is not present in destination object", fieldName)
|
||||
}
|
||||
field := iv.Field(fieldIndex)
|
||||
err = assignPathValues(field.Addr().Interface(), fieldValue)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "error assigning field [%s]", fieldName)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
case reflect.Ptr:
|
||||
// If we have a pointer after redirecting, it means we're dealing with
|
||||
// an optional field, such as *string, which was passed in as &foo. We
|
||||
// will allocate it if necessary, and call ourselves with a different
|
||||
// interface.
|
||||
dstVal := reflect.New(it.Elem())
|
||||
dstPtr := dstVal.Interface()
|
||||
err := assignPathValues(dstPtr, pathValues)
|
||||
iv.Set(dstVal)
|
||||
return err
|
||||
case reflect.Bool:
|
||||
val, err := strconv.ParseBool(pathValues.value)
|
||||
if err != nil {
|
||||
return fmt.Errorf("expected a valid bool, got %s", pathValues.value)
|
||||
}
|
||||
iv.SetBool(val)
|
||||
return nil
|
||||
case reflect.Float32:
|
||||
val, err := strconv.ParseFloat(pathValues.value, 32)
|
||||
if err != nil {
|
||||
return fmt.Errorf("expected a valid float, got %s", pathValues.value)
|
||||
}
|
||||
iv.SetFloat(val)
|
||||
return nil
|
||||
case reflect.Float64:
|
||||
val, err := strconv.ParseFloat(pathValues.value, 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("expected a valid float, got %s", pathValues.value)
|
||||
}
|
||||
iv.SetFloat(val)
|
||||
return nil
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
val, err := strconv.ParseInt(pathValues.value, 10, 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("expected a valid int, got %s", pathValues.value)
|
||||
}
|
||||
iv.SetInt(val)
|
||||
return nil
|
||||
case reflect.String:
|
||||
iv.SetString(pathValues.value)
|
||||
return nil
|
||||
default:
|
||||
return errors.New("unhandled type: " + it.String())
|
||||
}
|
||||
}
|
||||
|
||||
func assignSlice(dst reflect.Value, pathValues fieldOrValue) error {
|
||||
// Gather up the values
|
||||
nValues := len(pathValues.fields)
|
||||
values := make([]string, nValues)
|
||||
// We expect to have consecutive array indices in the map
|
||||
for i := 0; i < nValues; i++ {
|
||||
indexStr := strconv.Itoa(i)
|
||||
fv, found := pathValues.fields[indexStr]
|
||||
if !found {
|
||||
return errors.New("array deepObjects must have consecutive indices")
|
||||
}
|
||||
values[i] = fv.value
|
||||
}
|
||||
|
||||
// This could be cleaner, but we can call into assignPathValues to
|
||||
// avoid recreating this logic.
|
||||
for i:=0; i < nValues; i++ {
|
||||
dstElem := dst.Index(i).Addr()
|
||||
err := assignPathValues(dstElem.Interface(), fieldOrValue{value:values[i]})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error binding array")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func sortedFieldOrValueKeys(m map[string]fieldOrValue) []string {
|
||||
keys := make([]string, 0, len(m))
|
||||
for k := range m {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
return keys
|
||||
}
|
||||
337
vendor/github.com/deepmap/oapi-codegen/pkg/runtime/styleparam.go
generated
vendored
Normal file
337
vendor/github.com/deepmap/oapi-codegen/pkg/runtime/styleparam.go
generated
vendored
Normal file
|
|
@ -0,0 +1,337 @@
|
|||
// Copyright 2019 DeepMap, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Given an input value, such as a primitive type, array or object, turn it
|
||||
// into a parameter based on style/explode definition.
|
||||
func StyleParam(style string, explode bool, paramName string, value interface{}) (string, error) {
|
||||
t := reflect.TypeOf(value)
|
||||
v := reflect.ValueOf(value)
|
||||
|
||||
// Things may be passed in by pointer, we need to dereference, so return
|
||||
// error on nil.
|
||||
if t.Kind() == reflect.Ptr {
|
||||
if v.IsNil() {
|
||||
return "", fmt.Errorf("value is a nil pointer")
|
||||
}
|
||||
v = reflect.Indirect(v)
|
||||
t = v.Type()
|
||||
}
|
||||
|
||||
switch t.Kind() {
|
||||
case reflect.Slice:
|
||||
n := v.Len()
|
||||
sliceVal := make([]interface{}, n)
|
||||
for i := 0; i < n; i++ {
|
||||
sliceVal[i] = v.Index(i).Interface()
|
||||
}
|
||||
return styleSlice(style, explode, paramName, sliceVal)
|
||||
case reflect.Struct:
|
||||
return styleStruct(style, explode, paramName, value)
|
||||
case reflect.Map:
|
||||
return styleMap(style, explode, paramName, value)
|
||||
default:
|
||||
return stylePrimitive(style, explode, paramName, value)
|
||||
}
|
||||
}
|
||||
|
||||
func styleSlice(style string, explode bool, paramName string, values []interface{}) (string, error) {
|
||||
if style == "deepObject" {
|
||||
if !explode {
|
||||
return "", errors.New("deepObjects must be exploded")
|
||||
}
|
||||
return MarshalDeepObject(values, paramName)
|
||||
}
|
||||
|
||||
var prefix string
|
||||
var separator string
|
||||
|
||||
switch style {
|
||||
case "simple":
|
||||
separator = ","
|
||||
case "label":
|
||||
prefix = "."
|
||||
if explode {
|
||||
separator = "."
|
||||
} else {
|
||||
separator = ","
|
||||
}
|
||||
case "matrix":
|
||||
prefix = fmt.Sprintf(";%s=", paramName)
|
||||
if explode {
|
||||
separator = prefix
|
||||
} else {
|
||||
separator = ","
|
||||
}
|
||||
case "form":
|
||||
prefix = fmt.Sprintf("%s=", paramName)
|
||||
if explode {
|
||||
separator = "&" + prefix
|
||||
} else {
|
||||
separator = ","
|
||||
}
|
||||
case "spaceDelimited":
|
||||
prefix = fmt.Sprintf("%s=", paramName)
|
||||
if explode {
|
||||
separator = "&" + prefix
|
||||
} else {
|
||||
separator = " "
|
||||
}
|
||||
case "pipeDelimited":
|
||||
prefix = fmt.Sprintf("%s=", paramName)
|
||||
if explode {
|
||||
separator = "&" + prefix
|
||||
} else {
|
||||
separator = "|"
|
||||
}
|
||||
default:
|
||||
return "", fmt.Errorf("unsupported style '%s'", style)
|
||||
}
|
||||
|
||||
// We're going to assume here that the array is one of simple types.
|
||||
var err error
|
||||
parts := make([]string, len(values))
|
||||
for i, v := range values {
|
||||
parts[i], err = primitiveToString(v)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error formatting '%s': %s", paramName, err)
|
||||
}
|
||||
}
|
||||
return prefix + strings.Join(parts, separator), nil
|
||||
}
|
||||
|
||||
func sortedKeys(strMap map[string]string) []string {
|
||||
keys := make([]string, len(strMap))
|
||||
i := 0
|
||||
for k := range strMap {
|
||||
keys[i] = k
|
||||
i++
|
||||
}
|
||||
sort.Strings(keys)
|
||||
return keys
|
||||
}
|
||||
|
||||
|
||||
// This is a special case. The struct may be a time, in which case, marshal
|
||||
// it in RFC3339 format.
|
||||
func marshalTimeValue(value interface{}) (string, bool) {
|
||||
if timeVal, ok := value.(*time.Time); ok {
|
||||
return timeVal.Format(time.RFC3339Nano), true
|
||||
}
|
||||
|
||||
if timeVal, ok := value.(time.Time); ok {
|
||||
return timeVal.Format(time.RFC3339Nano), true
|
||||
}
|
||||
|
||||
return "", false
|
||||
}
|
||||
|
||||
func styleStruct(style string, explode bool, paramName string, value interface{}) (string, error) {
|
||||
if timeVal, ok := marshalTimeValue(value); ok {
|
||||
return stylePrimitive(style, explode, paramName, timeVal)
|
||||
}
|
||||
|
||||
if style == "deepObject" {
|
||||
if !explode {
|
||||
return "", errors.New("deepObjects must be exploded")
|
||||
}
|
||||
return MarshalDeepObject(value, paramName)
|
||||
}
|
||||
|
||||
// Otherwise, we need to build a dictionary of the struct's fields. Each
|
||||
// field may only be a primitive value.
|
||||
v := reflect.ValueOf(value)
|
||||
t := reflect.TypeOf(value)
|
||||
fieldDict := make(map[string]string)
|
||||
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
fieldT := t.Field(i)
|
||||
// Find the json annotation on the field, and use the json specified
|
||||
// name if available, otherwise, just the field name.
|
||||
tag := fieldT.Tag.Get("json")
|
||||
fieldName := fieldT.Name
|
||||
if tag != "" {
|
||||
tagParts := strings.Split(tag, ",")
|
||||
name := tagParts[0]
|
||||
if name != "" {
|
||||
fieldName = name
|
||||
}
|
||||
}
|
||||
f := v.Field(i)
|
||||
|
||||
// Unset optional fields will be nil pointers, skip over those.
|
||||
if f.Type().Kind() == reflect.Ptr && f.IsNil() {
|
||||
continue
|
||||
}
|
||||
str, err := primitiveToString(f.Interface())
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error formatting '%s': %s", paramName, err)
|
||||
}
|
||||
fieldDict[fieldName] = str
|
||||
}
|
||||
|
||||
return processFieldDict(style, explode, paramName, fieldDict)
|
||||
}
|
||||
|
||||
func styleMap(style string, explode bool, paramName string, value interface{}) (string, error) {
|
||||
if style == "deepObject" {
|
||||
if !explode {
|
||||
return "", errors.New("deepObjects must be exploded")
|
||||
}
|
||||
return MarshalDeepObject(value, paramName)
|
||||
}
|
||||
|
||||
dict, ok := value.(map[string]interface{})
|
||||
if !ok {
|
||||
return "", errors.New("map not of type map[string]interface{}")
|
||||
}
|
||||
|
||||
fieldDict := make(map[string]string)
|
||||
for fieldName, value := range dict {
|
||||
str, err := primitiveToString(value)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error formatting '%s': %s", paramName, err)
|
||||
}
|
||||
fieldDict[fieldName] = str
|
||||
}
|
||||
|
||||
return processFieldDict(style, explode, paramName, fieldDict)
|
||||
}
|
||||
|
||||
func processFieldDict(style string, explode bool, paramName string, fieldDict map[string]string) (string, error) {
|
||||
var parts []string
|
||||
|
||||
// This works for everything except deepObject. We'll handle that one
|
||||
// separately.
|
||||
if style != "deepObject" {
|
||||
if explode {
|
||||
for _, k := range sortedKeys(fieldDict) {
|
||||
v := fieldDict[k]
|
||||
parts = append(parts, k+"="+v)
|
||||
}
|
||||
} else {
|
||||
for _, k := range sortedKeys(fieldDict) {
|
||||
v := fieldDict[k]
|
||||
parts = append(parts, k)
|
||||
parts = append(parts, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var prefix string
|
||||
var separator string
|
||||
|
||||
switch style {
|
||||
case "simple":
|
||||
separator = ","
|
||||
case "label":
|
||||
prefix = "."
|
||||
if explode {
|
||||
separator = prefix
|
||||
} else {
|
||||
separator = ","
|
||||
}
|
||||
case "matrix":
|
||||
if explode {
|
||||
separator = ";"
|
||||
prefix = ";"
|
||||
} else {
|
||||
separator = ","
|
||||
prefix = fmt.Sprintf(";%s=", paramName)
|
||||
}
|
||||
case "form":
|
||||
if explode {
|
||||
separator = "&"
|
||||
} else {
|
||||
prefix = fmt.Sprintf("%s=", paramName)
|
||||
separator = ","
|
||||
}
|
||||
case "deepObject":
|
||||
{
|
||||
if !explode {
|
||||
return "", fmt.Errorf("deepObject parameters must be exploded")
|
||||
}
|
||||
for _, k := range sortedKeys(fieldDict) {
|
||||
v := fieldDict[k]
|
||||
part := fmt.Sprintf("%s[%s]=%s", paramName, k, v)
|
||||
parts = append(parts, part)
|
||||
}
|
||||
separator = "&"
|
||||
}
|
||||
default:
|
||||
return "", fmt.Errorf("unsupported style '%s'", style)
|
||||
}
|
||||
|
||||
return prefix + strings.Join(parts, separator), nil
|
||||
}
|
||||
|
||||
func stylePrimitive(style string, explode bool, paramName string, value interface{}) (string, error) {
|
||||
strVal, err := primitiveToString(value)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var prefix string
|
||||
switch style {
|
||||
case "simple":
|
||||
case "label":
|
||||
prefix = "."
|
||||
case "matrix":
|
||||
prefix = fmt.Sprintf(";%s=", paramName)
|
||||
case "form":
|
||||
prefix = fmt.Sprintf("%s=", paramName)
|
||||
default:
|
||||
return "", fmt.Errorf("unsupported style '%s'", style)
|
||||
}
|
||||
return prefix + strVal, nil
|
||||
}
|
||||
|
||||
// Converts a primitive value to a string. We need to do this based on the
|
||||
// Kind of an interface, not the Type to work with aliased types.
|
||||
func primitiveToString(value interface{}) (string, error) {
|
||||
var output string
|
||||
|
||||
// Values may come in by pointer for optionals, so make sure to dereferene.
|
||||
v := reflect.Indirect(reflect.ValueOf(value))
|
||||
t := v.Type()
|
||||
kind := t.Kind()
|
||||
|
||||
switch kind {
|
||||
case reflect.Int8, reflect.Int32, reflect.Int64, reflect.Int:
|
||||
output = strconv.FormatInt(v.Int(), 10)
|
||||
case reflect.Float32, reflect.Float64:
|
||||
output = strconv.FormatFloat(v.Float(), 'f', -1, 64)
|
||||
case reflect.Bool:
|
||||
if v.Bool() {
|
||||
output = "true"
|
||||
} else {
|
||||
output = "false"
|
||||
}
|
||||
case reflect.String:
|
||||
output = v.String()
|
||||
default:
|
||||
return "", fmt.Errorf("unsupported type %s", reflect.TypeOf(value).String())
|
||||
}
|
||||
return output, nil
|
||||
}
|
||||
30
vendor/github.com/deepmap/oapi-codegen/pkg/types/date.go
generated
vendored
Normal file
30
vendor/github.com/deepmap/oapi-codegen/pkg/types/date.go
generated
vendored
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
)
|
||||
|
||||
const DateFormat = "2006-01-02"
|
||||
|
||||
type Date struct {
|
||||
time.Time
|
||||
}
|
||||
|
||||
func (d Date) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(d.Time.Format(DateFormat))
|
||||
}
|
||||
|
||||
func (d *Date) UnmarshalJSON(data []byte) error {
|
||||
var dateStr string
|
||||
err := json.Unmarshal(data, &dateStr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
parsed, err := time.Parse(DateFormat, dateStr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.Time = parsed
|
||||
return nil
|
||||
}
|
||||
27
vendor/github.com/deepmap/oapi-codegen/pkg/types/email.go
generated
vendored
Normal file
27
vendor/github.com/deepmap/oapi-codegen/pkg/types/email.go
generated
vendored
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
)
|
||||
|
||||
type Email string
|
||||
|
||||
func (e Email) MarshalJSON() ([]byte, error) {
|
||||
if !emailRegex.MatchString(string(e)) {
|
||||
return nil, errors.New("email: failed to pass regex validation")
|
||||
}
|
||||
return json.Marshal(string(e))
|
||||
}
|
||||
|
||||
func (e *Email) UnmarshalJSON(data []byte) error {
|
||||
var s string
|
||||
if err := json.Unmarshal(data, &s); err != nil {
|
||||
return err
|
||||
}
|
||||
if !emailRegex.MatchString(s) {
|
||||
return errors.New("email: failed to pass regex validation")
|
||||
}
|
||||
*e = Email(s)
|
||||
return nil
|
||||
}
|
||||
11
vendor/github.com/deepmap/oapi-codegen/pkg/types/regexes.go
generated
vendored
Normal file
11
vendor/github.com/deepmap/oapi-codegen/pkg/types/regexes.go
generated
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
package types
|
||||
|
||||
import "regexp"
|
||||
|
||||
const (
|
||||
emailRegexString = "^(?:(?:(?:(?:[a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+(?:\\.([a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+)*)|(?:(?:\\x22)(?:(?:(?:(?:\\x20|\\x09)*(?:\\x0d\\x0a))?(?:\\x20|\\x09)+)?(?:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]|\\x21|[\\x23-\\x5b]|[\\x5d-\\x7e]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(?:(?:[\\x01-\\x09\\x0b\\x0c\\x0d-\\x7f]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}]))))*(?:(?:(?:\\x20|\\x09)*(?:\\x0d\\x0a))?(\\x20|\\x09)+)?(?:\\x22))))@(?:(?:(?:[a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(?:(?:[a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])(?:[a-zA-Z]|\\d|-|\\.|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*(?:[a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.)+(?:(?:[a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(?:(?:[a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])(?:[a-zA-Z]|\\d|-|\\.|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*(?:[a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.?$"
|
||||
)
|
||||
|
||||
var (
|
||||
emailRegex = regexp.MustCompile(emailRegexString)
|
||||
)
|
||||
25
vendor/github.com/labstack/echo/v4/.editorconfig
generated
vendored
Normal file
25
vendor/github.com/labstack/echo/v4/.editorconfig
generated
vendored
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
# EditorConfig coding styles definitions. For more information about the
|
||||
# properties used in this file, please see the EditorConfig documentation:
|
||||
# http://editorconfig.org/
|
||||
|
||||
# indicate this is the root of the project
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
|
||||
end_of_line = LF
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[Makefile]
|
||||
indent_style = tab
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
[*.go]
|
||||
indent_style = tab
|
||||
20
vendor/github.com/labstack/echo/v4/.gitattributes
generated
vendored
Normal file
20
vendor/github.com/labstack/echo/v4/.gitattributes
generated
vendored
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
# Automatically normalize line endings for all text-based files
|
||||
# http://git-scm.com/docs/gitattributes#_end_of_line_conversion
|
||||
* text=auto
|
||||
|
||||
# For the following file types, normalize line endings to LF on checking and
|
||||
# prevent conversion to CRLF when they are checked out (this is required in
|
||||
# order to prevent newline related issues)
|
||||
.* text eol=lf
|
||||
*.go text eol=lf
|
||||
*.yml text eol=lf
|
||||
*.html text eol=lf
|
||||
*.css text eol=lf
|
||||
*.js text eol=lf
|
||||
*.json text eol=lf
|
||||
LICENSE text eol=lf
|
||||
|
||||
# Exclude `website` and `cookbook` from GitHub's language statistics
|
||||
# https://github.com/github/linguist#using-gitattributes
|
||||
cookbook/* linguist-documentation
|
||||
website/* linguist-documentation
|
||||
7
vendor/github.com/labstack/echo/v4/.gitignore
generated
vendored
Normal file
7
vendor/github.com/labstack/echo/v4/.gitignore
generated
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
.DS_Store
|
||||
coverage.txt
|
||||
_test
|
||||
vendor
|
||||
.idea
|
||||
*.iml
|
||||
*.out
|
||||
17
vendor/github.com/labstack/echo/v4/.travis.yml
generated
vendored
Normal file
17
vendor/github.com/labstack/echo/v4/.travis.yml
generated
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
language: go
|
||||
go:
|
||||
- 1.11.x
|
||||
- 1.12.x
|
||||
- tip
|
||||
env:
|
||||
- GO111MODULE=on
|
||||
install:
|
||||
- go get -v golang.org/x/lint/golint
|
||||
script:
|
||||
- golint -set_exit_status ./...
|
||||
- go test -race -coverprofile=coverage.txt -covermode=atomic ./...
|
||||
after_success:
|
||||
- bash <(curl -s https://codecov.io/bash)
|
||||
matrix:
|
||||
allow_failures:
|
||||
- go: tip
|
||||
21
vendor/github.com/labstack/echo/v4/LICENSE
generated
vendored
Normal file
21
vendor/github.com/labstack/echo/v4/LICENSE
generated
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2017 LabStack
|
||||
|
||||
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.
|
||||
3
vendor/github.com/labstack/echo/v4/Makefile
generated
vendored
Normal file
3
vendor/github.com/labstack/echo/v4/Makefile
generated
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
tag:
|
||||
@git tag `grep -P '^\tversion = ' echo.go|cut -f2 -d'"'`
|
||||
@git tag|grep -v ^v
|
||||
113
vendor/github.com/labstack/echo/v4/README.md
generated
vendored
Normal file
113
vendor/github.com/labstack/echo/v4/README.md
generated
vendored
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
<a href="https://echo.labstack.com"><img height="80" src="https://cdn.labstack.com/images/echo-logo.svg"></a>
|
||||
|
||||
[](https://sourcegraph.com/github.com/labstack/echo?badge)
|
||||
[](http://godoc.org/github.com/labstack/echo)
|
||||
[](https://goreportcard.com/report/github.com/labstack/echo)
|
||||
[](https://travis-ci.org/labstack/echo)
|
||||
[](https://codecov.io/gh/labstack/echo)
|
||||
[](https://gitter.im/labstack/echo)
|
||||
[](https://forum.labstack.com)
|
||||
[](https://twitter.com/labstack)
|
||||
[](https://raw.githubusercontent.com/labstack/echo/master/LICENSE)
|
||||
|
||||
## Supported Go versions
|
||||
|
||||
As of version 4.0.0, Echo is available as a [Go module](https://github.com/golang/go/wiki/Modules).
|
||||
Therefore a Go version capable of understanding /vN suffixed imports is required:
|
||||
|
||||
- 1.9.7+
|
||||
- 1.10.3+
|
||||
- 1.11+
|
||||
|
||||
Any of these versions will allow you to import Echo as `github.com/labstack/echo/v4` which is the recommended
|
||||
way of using Echo going forward.
|
||||
|
||||
For older versions, please use the latest v3 tag.
|
||||
|
||||
## Feature Overview
|
||||
|
||||
- Optimized HTTP router which smartly prioritize routes
|
||||
- Build robust and scalable RESTful APIs
|
||||
- Group APIs
|
||||
- Extensible middleware framework
|
||||
- Define middleware at root, group or route level
|
||||
- Data binding for JSON, XML and form payload
|
||||
- Handy functions to send variety of HTTP responses
|
||||
- Centralized HTTP error handling
|
||||
- Template rendering with any template engine
|
||||
- Define your format for the logger
|
||||
- Highly customizable
|
||||
- Automatic TLS via Let’s Encrypt
|
||||
- HTTP/2 support
|
||||
|
||||
## Benchmarks
|
||||
|
||||
Date: 2018/03/15<br>
|
||||
Source: https://github.com/vishr/web-framework-benchmark<br>
|
||||
Lower is better!
|
||||
|
||||
<img src="https://i.imgur.com/I32VdMJ.png">
|
||||
|
||||
## [Guide](https://echo.labstack.com/guide)
|
||||
|
||||
### Example
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/labstack/echo/v4/middleware"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Echo instance
|
||||
e := echo.New()
|
||||
|
||||
// Middleware
|
||||
e.Use(middleware.Logger())
|
||||
e.Use(middleware.Recover())
|
||||
|
||||
// Routes
|
||||
e.GET("/", hello)
|
||||
|
||||
// Start server
|
||||
e.Logger.Fatal(e.Start(":1323"))
|
||||
}
|
||||
|
||||
// Handler
|
||||
func hello(c echo.Context) error {
|
||||
return c.String(http.StatusOK, "Hello, World!")
|
||||
}
|
||||
```
|
||||
|
||||
## Help
|
||||
|
||||
- [Forum](https://forum.labstack.com)
|
||||
- [Chat](https://gitter.im/labstack/echo)
|
||||
|
||||
## Contribute
|
||||
|
||||
**Use issues for everything**
|
||||
|
||||
- For a small change, just send a PR.
|
||||
- For bigger changes open an issue for discussion before sending a PR.
|
||||
- PR should have:
|
||||
- Test case
|
||||
- Documentation
|
||||
- Example (If it makes sense)
|
||||
- You can also contribute by:
|
||||
- Reporting issues
|
||||
- Suggesting new features or enhancements
|
||||
- Improve/fix documentation
|
||||
|
||||
## Credits
|
||||
|
||||
- [Vishal Rana](https://github.com/vishr) - Author
|
||||
- [Nitin Rana](https://github.com/nr17) - Consultant
|
||||
- [Contributors](https://github.com/labstack/echo/graphs/contributors)
|
||||
|
||||
## License
|
||||
|
||||
[MIT](https://github.com/labstack/echo/blob/master/LICENSE)
|
||||
311
vendor/github.com/labstack/echo/v4/bind.go
generated
vendored
Normal file
311
vendor/github.com/labstack/echo/v4/bind.go
generated
vendored
Normal file
|
|
@ -0,0 +1,311 @@
|
|||
package echo
|
||||
|
||||
import (
|
||||
"encoding"
|
||||
"encoding/json"
|
||||
"encoding/xml"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type (
|
||||
// Binder is the interface that wraps the Bind method.
|
||||
Binder interface {
|
||||
Bind(i interface{}, c Context) error
|
||||
}
|
||||
|
||||
// DefaultBinder is the default implementation of the Binder interface.
|
||||
DefaultBinder struct{}
|
||||
|
||||
// BindUnmarshaler is the interface used to wrap the UnmarshalParam method.
|
||||
// Types that don't implement this, but do implement encoding.TextUnmarshaler
|
||||
// will use that interface instead.
|
||||
BindUnmarshaler interface {
|
||||
// UnmarshalParam decodes and assigns a value from an form or query param.
|
||||
UnmarshalParam(param string) error
|
||||
}
|
||||
)
|
||||
|
||||
// Bind implements the `Binder#Bind` function.
|
||||
func (b *DefaultBinder) Bind(i interface{}, c Context) (err error) {
|
||||
req := c.Request()
|
||||
|
||||
names := c.ParamNames()
|
||||
values := c.ParamValues()
|
||||
params := map[string][]string{}
|
||||
for i, name := range names {
|
||||
params[name] = []string{values[i]}
|
||||
}
|
||||
if err := b.bindData(i, params, "param"); err != nil {
|
||||
return NewHTTPError(http.StatusBadRequest, err.Error()).SetInternal(err)
|
||||
}
|
||||
if err = b.bindData(i, c.QueryParams(), "query"); err != nil {
|
||||
return NewHTTPError(http.StatusBadRequest, err.Error()).SetInternal(err)
|
||||
}
|
||||
if req.ContentLength == 0 {
|
||||
return
|
||||
}
|
||||
ctype := req.Header.Get(HeaderContentType)
|
||||
switch {
|
||||
case strings.HasPrefix(ctype, MIMEApplicationJSON):
|
||||
if err = json.NewDecoder(req.Body).Decode(i); err != nil {
|
||||
if ute, ok := err.(*json.UnmarshalTypeError); ok {
|
||||
return NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Unmarshal type error: expected=%v, got=%v, field=%v, offset=%v", ute.Type, ute.Value, ute.Field, ute.Offset)).SetInternal(err)
|
||||
} else if se, ok := err.(*json.SyntaxError); ok {
|
||||
return NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Syntax error: offset=%v, error=%v", se.Offset, se.Error())).SetInternal(err)
|
||||
}
|
||||
return NewHTTPError(http.StatusBadRequest, err.Error()).SetInternal(err)
|
||||
}
|
||||
case strings.HasPrefix(ctype, MIMEApplicationXML), strings.HasPrefix(ctype, MIMETextXML):
|
||||
if err = xml.NewDecoder(req.Body).Decode(i); err != nil {
|
||||
if ute, ok := err.(*xml.UnsupportedTypeError); ok {
|
||||
return NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Unsupported type error: type=%v, error=%v", ute.Type, ute.Error())).SetInternal(err)
|
||||
} else if se, ok := err.(*xml.SyntaxError); ok {
|
||||
return NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Syntax error: line=%v, error=%v", se.Line, se.Error())).SetInternal(err)
|
||||
}
|
||||
return NewHTTPError(http.StatusBadRequest, err.Error()).SetInternal(err)
|
||||
}
|
||||
case strings.HasPrefix(ctype, MIMEApplicationForm), strings.HasPrefix(ctype, MIMEMultipartForm):
|
||||
params, err := c.FormParams()
|
||||
if err != nil {
|
||||
return NewHTTPError(http.StatusBadRequest, err.Error()).SetInternal(err)
|
||||
}
|
||||
if err = b.bindData(i, params, "form"); err != nil {
|
||||
return NewHTTPError(http.StatusBadRequest, err.Error()).SetInternal(err)
|
||||
}
|
||||
default:
|
||||
return ErrUnsupportedMediaType
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (b *DefaultBinder) bindData(ptr interface{}, data map[string][]string, tag string) error {
|
||||
if ptr == nil || len(data) == 0 {
|
||||
return nil
|
||||
}
|
||||
typ := reflect.TypeOf(ptr).Elem()
|
||||
val := reflect.ValueOf(ptr).Elem()
|
||||
|
||||
if m, ok := ptr.(*map[string]interface{}); ok {
|
||||
for k, v := range data {
|
||||
(*m)[k] = v[0]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if typ.Kind() != reflect.Struct {
|
||||
return errors.New("binding element must be a struct")
|
||||
}
|
||||
|
||||
for i := 0; i < typ.NumField(); i++ {
|
||||
typeField := typ.Field(i)
|
||||
structField := val.Field(i)
|
||||
if !structField.CanSet() {
|
||||
continue
|
||||
}
|
||||
structFieldKind := structField.Kind()
|
||||
inputFieldName := typeField.Tag.Get(tag)
|
||||
|
||||
if inputFieldName == "" {
|
||||
inputFieldName = typeField.Name
|
||||
// If tag is nil, we inspect if the field is a struct.
|
||||
if _, ok := bindUnmarshaler(structField); !ok && structFieldKind == reflect.Struct {
|
||||
if err := b.bindData(structField.Addr().Interface(), data, tag); err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
inputValue, exists := data[inputFieldName]
|
||||
if !exists {
|
||||
// Go json.Unmarshal supports case insensitive binding. However the
|
||||
// url params are bound case sensitive which is inconsistent. To
|
||||
// fix this we must check all of the map values in a
|
||||
// case-insensitive search.
|
||||
inputFieldName = strings.ToLower(inputFieldName)
|
||||
for k, v := range data {
|
||||
if strings.ToLower(k) == inputFieldName {
|
||||
inputValue = v
|
||||
exists = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !exists {
|
||||
continue
|
||||
}
|
||||
|
||||
// Call this first, in case we're dealing with an alias to an array type
|
||||
if ok, err := unmarshalField(typeField.Type.Kind(), inputValue[0], structField); ok {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
numElems := len(inputValue)
|
||||
if structFieldKind == reflect.Slice && numElems > 0 {
|
||||
sliceOf := structField.Type().Elem().Kind()
|
||||
slice := reflect.MakeSlice(structField.Type(), numElems, numElems)
|
||||
for j := 0; j < numElems; j++ {
|
||||
if err := setWithProperType(sliceOf, inputValue[j], slice.Index(j)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
val.Field(i).Set(slice)
|
||||
} else if err := setWithProperType(typeField.Type.Kind(), inputValue[0], structField); err != nil {
|
||||
return err
|
||||
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func setWithProperType(valueKind reflect.Kind, val string, structField reflect.Value) error {
|
||||
// But also call it here, in case we're dealing with an array of BindUnmarshalers
|
||||
if ok, err := unmarshalField(valueKind, val, structField); ok {
|
||||
return err
|
||||
}
|
||||
|
||||
switch valueKind {
|
||||
case reflect.Ptr:
|
||||
return setWithProperType(structField.Elem().Kind(), val, structField.Elem())
|
||||
case reflect.Int:
|
||||
return setIntField(val, 0, structField)
|
||||
case reflect.Int8:
|
||||
return setIntField(val, 8, structField)
|
||||
case reflect.Int16:
|
||||
return setIntField(val, 16, structField)
|
||||
case reflect.Int32:
|
||||
return setIntField(val, 32, structField)
|
||||
case reflect.Int64:
|
||||
return setIntField(val, 64, structField)
|
||||
case reflect.Uint:
|
||||
return setUintField(val, 0, structField)
|
||||
case reflect.Uint8:
|
||||
return setUintField(val, 8, structField)
|
||||
case reflect.Uint16:
|
||||
return setUintField(val, 16, structField)
|
||||
case reflect.Uint32:
|
||||
return setUintField(val, 32, structField)
|
||||
case reflect.Uint64:
|
||||
return setUintField(val, 64, structField)
|
||||
case reflect.Bool:
|
||||
return setBoolField(val, structField)
|
||||
case reflect.Float32:
|
||||
return setFloatField(val, 32, structField)
|
||||
case reflect.Float64:
|
||||
return setFloatField(val, 64, structField)
|
||||
case reflect.String:
|
||||
structField.SetString(val)
|
||||
default:
|
||||
return errors.New("unknown type")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func unmarshalField(valueKind reflect.Kind, val string, field reflect.Value) (bool, error) {
|
||||
switch valueKind {
|
||||
case reflect.Ptr:
|
||||
return unmarshalFieldPtr(val, field)
|
||||
default:
|
||||
return unmarshalFieldNonPtr(val, field)
|
||||
}
|
||||
}
|
||||
|
||||
// bindUnmarshaler attempts to unmarshal a reflect.Value into a BindUnmarshaler
|
||||
func bindUnmarshaler(field reflect.Value) (BindUnmarshaler, bool) {
|
||||
ptr := reflect.New(field.Type())
|
||||
if ptr.CanInterface() {
|
||||
iface := ptr.Interface()
|
||||
if unmarshaler, ok := iface.(BindUnmarshaler); ok {
|
||||
return unmarshaler, ok
|
||||
}
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// textUnmarshaler attempts to unmarshal a reflect.Value into a TextUnmarshaler
|
||||
func textUnmarshaler(field reflect.Value) (encoding.TextUnmarshaler, bool) {
|
||||
ptr := reflect.New(field.Type())
|
||||
if ptr.CanInterface() {
|
||||
iface := ptr.Interface()
|
||||
if unmarshaler, ok := iface.(encoding.TextUnmarshaler); ok {
|
||||
return unmarshaler, ok
|
||||
}
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func unmarshalFieldNonPtr(value string, field reflect.Value) (bool, error) {
|
||||
if unmarshaler, ok := bindUnmarshaler(field); ok {
|
||||
err := unmarshaler.UnmarshalParam(value)
|
||||
field.Set(reflect.ValueOf(unmarshaler).Elem())
|
||||
return true, err
|
||||
}
|
||||
if unmarshaler, ok := textUnmarshaler(field); ok {
|
||||
err := unmarshaler.UnmarshalText([]byte(value))
|
||||
field.Set(reflect.ValueOf(unmarshaler).Elem())
|
||||
return true, err
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func unmarshalFieldPtr(value string, field reflect.Value) (bool, error) {
|
||||
if field.IsNil() {
|
||||
// Initialize the pointer to a nil value
|
||||
field.Set(reflect.New(field.Type().Elem()))
|
||||
}
|
||||
return unmarshalFieldNonPtr(value, field.Elem())
|
||||
}
|
||||
|
||||
func setIntField(value string, bitSize int, field reflect.Value) error {
|
||||
if value == "" {
|
||||
value = "0"
|
||||
}
|
||||
intVal, err := strconv.ParseInt(value, 10, bitSize)
|
||||
if err == nil {
|
||||
field.SetInt(intVal)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func setUintField(value string, bitSize int, field reflect.Value) error {
|
||||
if value == "" {
|
||||
value = "0"
|
||||
}
|
||||
uintVal, err := strconv.ParseUint(value, 10, bitSize)
|
||||
if err == nil {
|
||||
field.SetUint(uintVal)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func setBoolField(value string, field reflect.Value) error {
|
||||
if value == "" {
|
||||
value = "false"
|
||||
}
|
||||
boolVal, err := strconv.ParseBool(value)
|
||||
if err == nil {
|
||||
field.SetBool(boolVal)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func setFloatField(value string, bitSize int, field reflect.Value) error {
|
||||
if value == "" {
|
||||
value = "0.0"
|
||||
}
|
||||
floatVal, err := strconv.ParseFloat(value, bitSize)
|
||||
if err == nil {
|
||||
field.SetFloat(floatVal)
|
||||
}
|
||||
return err
|
||||
}
|
||||
613
vendor/github.com/labstack/echo/v4/context.go
generated
vendored
Normal file
613
vendor/github.com/labstack/echo/v4/context.go
generated
vendored
Normal file
|
|
@ -0,0 +1,613 @@
|
|||
package echo
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"io"
|
||||
"mime/multipart"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type (
|
||||
// Context represents the context of the current HTTP request. It holds request and
|
||||
// response objects, path, path parameters, data and registered handler.
|
||||
Context interface {
|
||||
// Request returns `*http.Request`.
|
||||
Request() *http.Request
|
||||
|
||||
// SetRequest sets `*http.Request`.
|
||||
SetRequest(r *http.Request)
|
||||
|
||||
// SetResponse sets `*Response`.
|
||||
SetResponse(r *Response)
|
||||
|
||||
// Response returns `*Response`.
|
||||
Response() *Response
|
||||
|
||||
// IsTLS returns true if HTTP connection is TLS otherwise false.
|
||||
IsTLS() bool
|
||||
|
||||
// IsWebSocket returns true if HTTP connection is WebSocket otherwise false.
|
||||
IsWebSocket() bool
|
||||
|
||||
// Scheme returns the HTTP protocol scheme, `http` or `https`.
|
||||
Scheme() string
|
||||
|
||||
// RealIP returns the client's network address based on `X-Forwarded-For`
|
||||
// or `X-Real-IP` request header.
|
||||
RealIP() string
|
||||
|
||||
// Path returns the registered path for the handler.
|
||||
Path() string
|
||||
|
||||
// SetPath sets the registered path for the handler.
|
||||
SetPath(p string)
|
||||
|
||||
// Param returns path parameter by name.
|
||||
Param(name string) string
|
||||
|
||||
// ParamNames returns path parameter names.
|
||||
ParamNames() []string
|
||||
|
||||
// SetParamNames sets path parameter names.
|
||||
SetParamNames(names ...string)
|
||||
|
||||
// ParamValues returns path parameter values.
|
||||
ParamValues() []string
|
||||
|
||||
// SetParamValues sets path parameter values.
|
||||
SetParamValues(values ...string)
|
||||
|
||||
// QueryParam returns the query param for the provided name.
|
||||
QueryParam(name string) string
|
||||
|
||||
// QueryParams returns the query parameters as `url.Values`.
|
||||
QueryParams() url.Values
|
||||
|
||||
// QueryString returns the URL query string.
|
||||
QueryString() string
|
||||
|
||||
// FormValue returns the form field value for the provided name.
|
||||
FormValue(name string) string
|
||||
|
||||
// FormParams returns the form parameters as `url.Values`.
|
||||
FormParams() (url.Values, error)
|
||||
|
||||
// FormFile returns the multipart form file for the provided name.
|
||||
FormFile(name string) (*multipart.FileHeader, error)
|
||||
|
||||
// MultipartForm returns the multipart form.
|
||||
MultipartForm() (*multipart.Form, error)
|
||||
|
||||
// Cookie returns the named cookie provided in the request.
|
||||
Cookie(name string) (*http.Cookie, error)
|
||||
|
||||
// SetCookie adds a `Set-Cookie` header in HTTP response.
|
||||
SetCookie(cookie *http.Cookie)
|
||||
|
||||
// Cookies returns the HTTP cookies sent with the request.
|
||||
Cookies() []*http.Cookie
|
||||
|
||||
// Get retrieves data from the context.
|
||||
Get(key string) interface{}
|
||||
|
||||
// Set saves data in the context.
|
||||
Set(key string, val interface{})
|
||||
|
||||
// Bind binds the request body into provided type `i`. The default binder
|
||||
// does it based on Content-Type header.
|
||||
Bind(i interface{}) error
|
||||
|
||||
// Validate validates provided `i`. It is usually called after `Context#Bind()`.
|
||||
// Validator must be registered using `Echo#Validator`.
|
||||
Validate(i interface{}) error
|
||||
|
||||
// Render renders a template with data and sends a text/html response with status
|
||||
// code. Renderer must be registered using `Echo.Renderer`.
|
||||
Render(code int, name string, data interface{}) error
|
||||
|
||||
// HTML sends an HTTP response with status code.
|
||||
HTML(code int, html string) error
|
||||
|
||||
// HTMLBlob sends an HTTP blob response with status code.
|
||||
HTMLBlob(code int, b []byte) error
|
||||
|
||||
// String sends a string response with status code.
|
||||
String(code int, s string) error
|
||||
|
||||
// JSON sends a JSON response with status code.
|
||||
JSON(code int, i interface{}) error
|
||||
|
||||
// JSONPretty sends a pretty-print JSON with status code.
|
||||
JSONPretty(code int, i interface{}, indent string) error
|
||||
|
||||
// JSONBlob sends a JSON blob response with status code.
|
||||
JSONBlob(code int, b []byte) error
|
||||
|
||||
// JSONP sends a JSONP response with status code. It uses `callback` to construct
|
||||
// the JSONP payload.
|
||||
JSONP(code int, callback string, i interface{}) error
|
||||
|
||||
// JSONPBlob sends a JSONP blob response with status code. It uses `callback`
|
||||
// to construct the JSONP payload.
|
||||
JSONPBlob(code int, callback string, b []byte) error
|
||||
|
||||
// XML sends an XML response with status code.
|
||||
XML(code int, i interface{}) error
|
||||
|
||||
// XMLPretty sends a pretty-print XML with status code.
|
||||
XMLPretty(code int, i interface{}, indent string) error
|
||||
|
||||
// XMLBlob sends an XML blob response with status code.
|
||||
XMLBlob(code int, b []byte) error
|
||||
|
||||
// Blob sends a blob response with status code and content type.
|
||||
Blob(code int, contentType string, b []byte) error
|
||||
|
||||
// Stream sends a streaming response with status code and content type.
|
||||
Stream(code int, contentType string, r io.Reader) error
|
||||
|
||||
// File sends a response with the content of the file.
|
||||
File(file string) error
|
||||
|
||||
// Attachment sends a response as attachment, prompting client to save the
|
||||
// file.
|
||||
Attachment(file string, name string) error
|
||||
|
||||
// Inline sends a response as inline, opening the file in the browser.
|
||||
Inline(file string, name string) error
|
||||
|
||||
// NoContent sends a response with no body and a status code.
|
||||
NoContent(code int) error
|
||||
|
||||
// Redirect redirects the request to a provided URL with status code.
|
||||
Redirect(code int, url string) error
|
||||
|
||||
// Error invokes the registered HTTP error handler. Generally used by middleware.
|
||||
Error(err error)
|
||||
|
||||
// Handler returns the matched handler by router.
|
||||
Handler() HandlerFunc
|
||||
|
||||
// SetHandler sets the matched handler by router.
|
||||
SetHandler(h HandlerFunc)
|
||||
|
||||
// Logger returns the `Logger` instance.
|
||||
Logger() Logger
|
||||
|
||||
// Echo returns the `Echo` instance.
|
||||
Echo() *Echo
|
||||
|
||||
// Reset resets the context after request completes. It must be called along
|
||||
// with `Echo#AcquireContext()` and `Echo#ReleaseContext()`.
|
||||
// See `Echo#ServeHTTP()`
|
||||
Reset(r *http.Request, w http.ResponseWriter)
|
||||
}
|
||||
|
||||
context struct {
|
||||
request *http.Request
|
||||
response *Response
|
||||
path string
|
||||
pnames []string
|
||||
pvalues []string
|
||||
query url.Values
|
||||
handler HandlerFunc
|
||||
store Map
|
||||
echo *Echo
|
||||
lock sync.RWMutex
|
||||
}
|
||||
)
|
||||
|
||||
const (
|
||||
defaultMemory = 32 << 20 // 32 MB
|
||||
indexPage = "index.html"
|
||||
defaultIndent = " "
|
||||
)
|
||||
|
||||
func (c *context) writeContentType(value string) {
|
||||
header := c.Response().Header()
|
||||
if header.Get(HeaderContentType) == "" {
|
||||
header.Set(HeaderContentType, value)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *context) Request() *http.Request {
|
||||
return c.request
|
||||
}
|
||||
|
||||
func (c *context) SetRequest(r *http.Request) {
|
||||
c.request = r
|
||||
}
|
||||
|
||||
func (c *context) Response() *Response {
|
||||
return c.response
|
||||
}
|
||||
|
||||
func (c *context) SetResponse(r *Response) {
|
||||
c.response = r
|
||||
}
|
||||
|
||||
func (c *context) IsTLS() bool {
|
||||
return c.request.TLS != nil
|
||||
}
|
||||
|
||||
func (c *context) IsWebSocket() bool {
|
||||
upgrade := c.request.Header.Get(HeaderUpgrade)
|
||||
return strings.ToLower(upgrade) == "websocket"
|
||||
}
|
||||
|
||||
func (c *context) Scheme() string {
|
||||
// Can't use `r.Request.URL.Scheme`
|
||||
// See: https://groups.google.com/forum/#!topic/golang-nuts/pMUkBlQBDF0
|
||||
if c.IsTLS() {
|
||||
return "https"
|
||||
}
|
||||
if scheme := c.request.Header.Get(HeaderXForwardedProto); scheme != "" {
|
||||
return scheme
|
||||
}
|
||||
if scheme := c.request.Header.Get(HeaderXForwardedProtocol); scheme != "" {
|
||||
return scheme
|
||||
}
|
||||
if ssl := c.request.Header.Get(HeaderXForwardedSsl); ssl == "on" {
|
||||
return "https"
|
||||
}
|
||||
if scheme := c.request.Header.Get(HeaderXUrlScheme); scheme != "" {
|
||||
return scheme
|
||||
}
|
||||
return "http"
|
||||
}
|
||||
|
||||
func (c *context) RealIP() string {
|
||||
if ip := c.request.Header.Get(HeaderXForwardedFor); ip != "" {
|
||||
return strings.Split(ip, ", ")[0]
|
||||
}
|
||||
if ip := c.request.Header.Get(HeaderXRealIP); ip != "" {
|
||||
return ip
|
||||
}
|
||||
ra, _, _ := net.SplitHostPort(c.request.RemoteAddr)
|
||||
return ra
|
||||
}
|
||||
|
||||
func (c *context) Path() string {
|
||||
return c.path
|
||||
}
|
||||
|
||||
func (c *context) SetPath(p string) {
|
||||
c.path = p
|
||||
}
|
||||
|
||||
func (c *context) Param(name string) string {
|
||||
for i, n := range c.pnames {
|
||||
if i < len(c.pvalues) {
|
||||
if n == name {
|
||||
return c.pvalues[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (c *context) ParamNames() []string {
|
||||
return c.pnames
|
||||
}
|
||||
|
||||
func (c *context) SetParamNames(names ...string) {
|
||||
c.pnames = names
|
||||
}
|
||||
|
||||
func (c *context) ParamValues() []string {
|
||||
return c.pvalues[:len(c.pnames)]
|
||||
}
|
||||
|
||||
func (c *context) SetParamValues(values ...string) {
|
||||
c.pvalues = values
|
||||
}
|
||||
|
||||
func (c *context) QueryParam(name string) string {
|
||||
if c.query == nil {
|
||||
c.query = c.request.URL.Query()
|
||||
}
|
||||
return c.query.Get(name)
|
||||
}
|
||||
|
||||
func (c *context) QueryParams() url.Values {
|
||||
if c.query == nil {
|
||||
c.query = c.request.URL.Query()
|
||||
}
|
||||
return c.query
|
||||
}
|
||||
|
||||
func (c *context) QueryString() string {
|
||||
return c.request.URL.RawQuery
|
||||
}
|
||||
|
||||
func (c *context) FormValue(name string) string {
|
||||
return c.request.FormValue(name)
|
||||
}
|
||||
|
||||
func (c *context) FormParams() (url.Values, error) {
|
||||
if strings.HasPrefix(c.request.Header.Get(HeaderContentType), MIMEMultipartForm) {
|
||||
if err := c.request.ParseMultipartForm(defaultMemory); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
if err := c.request.ParseForm(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return c.request.Form, nil
|
||||
}
|
||||
|
||||
func (c *context) FormFile(name string) (*multipart.FileHeader, error) {
|
||||
_, fh, err := c.request.FormFile(name)
|
||||
return fh, err
|
||||
}
|
||||
|
||||
func (c *context) MultipartForm() (*multipart.Form, error) {
|
||||
err := c.request.ParseMultipartForm(defaultMemory)
|
||||
return c.request.MultipartForm, err
|
||||
}
|
||||
|
||||
func (c *context) Cookie(name string) (*http.Cookie, error) {
|
||||
return c.request.Cookie(name)
|
||||
}
|
||||
|
||||
func (c *context) SetCookie(cookie *http.Cookie) {
|
||||
http.SetCookie(c.Response(), cookie)
|
||||
}
|
||||
|
||||
func (c *context) Cookies() []*http.Cookie {
|
||||
return c.request.Cookies()
|
||||
}
|
||||
|
||||
func (c *context) Get(key string) interface{} {
|
||||
c.lock.RLock()
|
||||
defer c.lock.RUnlock()
|
||||
return c.store[key]
|
||||
}
|
||||
|
||||
func (c *context) Set(key string, val interface{}) {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
|
||||
if c.store == nil {
|
||||
c.store = make(Map)
|
||||
}
|
||||
c.store[key] = val
|
||||
}
|
||||
|
||||
func (c *context) Bind(i interface{}) error {
|
||||
return c.echo.Binder.Bind(i, c)
|
||||
}
|
||||
|
||||
func (c *context) Validate(i interface{}) error {
|
||||
if c.echo.Validator == nil {
|
||||
return ErrValidatorNotRegistered
|
||||
}
|
||||
return c.echo.Validator.Validate(i)
|
||||
}
|
||||
|
||||
func (c *context) Render(code int, name string, data interface{}) (err error) {
|
||||
if c.echo.Renderer == nil {
|
||||
return ErrRendererNotRegistered
|
||||
}
|
||||
buf := new(bytes.Buffer)
|
||||
if err = c.echo.Renderer.Render(buf, name, data, c); err != nil {
|
||||
return
|
||||
}
|
||||
return c.HTMLBlob(code, buf.Bytes())
|
||||
}
|
||||
|
||||
func (c *context) HTML(code int, html string) (err error) {
|
||||
return c.HTMLBlob(code, []byte(html))
|
||||
}
|
||||
|
||||
func (c *context) HTMLBlob(code int, b []byte) (err error) {
|
||||
return c.Blob(code, MIMETextHTMLCharsetUTF8, b)
|
||||
}
|
||||
|
||||
func (c *context) String(code int, s string) (err error) {
|
||||
return c.Blob(code, MIMETextPlainCharsetUTF8, []byte(s))
|
||||
}
|
||||
|
||||
func (c *context) jsonPBlob(code int, callback string, i interface{}) (err error) {
|
||||
enc := json.NewEncoder(c.response)
|
||||
_, pretty := c.QueryParams()["pretty"]
|
||||
if c.echo.Debug || pretty {
|
||||
enc.SetIndent("", " ")
|
||||
}
|
||||
c.writeContentType(MIMEApplicationJavaScriptCharsetUTF8)
|
||||
c.response.WriteHeader(code)
|
||||
if _, err = c.response.Write([]byte(callback + "(")); err != nil {
|
||||
return
|
||||
}
|
||||
if err = enc.Encode(i); err != nil {
|
||||
return
|
||||
}
|
||||
if _, err = c.response.Write([]byte(");")); err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (c *context) json(code int, i interface{}, indent string) error {
|
||||
enc := json.NewEncoder(c.response)
|
||||
if indent != "" {
|
||||
enc.SetIndent("", indent)
|
||||
}
|
||||
c.writeContentType(MIMEApplicationJSONCharsetUTF8)
|
||||
c.response.Status = code
|
||||
return enc.Encode(i)
|
||||
}
|
||||
|
||||
func (c *context) JSON(code int, i interface{}) (err error) {
|
||||
indent := ""
|
||||
if _, pretty := c.QueryParams()["pretty"]; c.echo.Debug || pretty {
|
||||
indent = defaultIndent
|
||||
}
|
||||
return c.json(code, i, indent)
|
||||
}
|
||||
|
||||
func (c *context) JSONPretty(code int, i interface{}, indent string) (err error) {
|
||||
return c.json(code, i, indent)
|
||||
}
|
||||
|
||||
func (c *context) JSONBlob(code int, b []byte) (err error) {
|
||||
return c.Blob(code, MIMEApplicationJSONCharsetUTF8, b)
|
||||
}
|
||||
|
||||
func (c *context) JSONP(code int, callback string, i interface{}) (err error) {
|
||||
return c.jsonPBlob(code, callback, i)
|
||||
}
|
||||
|
||||
func (c *context) JSONPBlob(code int, callback string, b []byte) (err error) {
|
||||
c.writeContentType(MIMEApplicationJavaScriptCharsetUTF8)
|
||||
c.response.WriteHeader(code)
|
||||
if _, err = c.response.Write([]byte(callback + "(")); err != nil {
|
||||
return
|
||||
}
|
||||
if _, err = c.response.Write(b); err != nil {
|
||||
return
|
||||
}
|
||||
_, err = c.response.Write([]byte(");"))
|
||||
return
|
||||
}
|
||||
|
||||
func (c *context) xml(code int, i interface{}, indent string) (err error) {
|
||||
c.writeContentType(MIMEApplicationXMLCharsetUTF8)
|
||||
c.response.WriteHeader(code)
|
||||
enc := xml.NewEncoder(c.response)
|
||||
if indent != "" {
|
||||
enc.Indent("", indent)
|
||||
}
|
||||
if _, err = c.response.Write([]byte(xml.Header)); err != nil {
|
||||
return
|
||||
}
|
||||
return enc.Encode(i)
|
||||
}
|
||||
|
||||
func (c *context) XML(code int, i interface{}) (err error) {
|
||||
indent := ""
|
||||
if _, pretty := c.QueryParams()["pretty"]; c.echo.Debug || pretty {
|
||||
indent = defaultIndent
|
||||
}
|
||||
return c.xml(code, i, indent)
|
||||
}
|
||||
|
||||
func (c *context) XMLPretty(code int, i interface{}, indent string) (err error) {
|
||||
return c.xml(code, i, indent)
|
||||
}
|
||||
|
||||
func (c *context) XMLBlob(code int, b []byte) (err error) {
|
||||
c.writeContentType(MIMEApplicationXMLCharsetUTF8)
|
||||
c.response.WriteHeader(code)
|
||||
if _, err = c.response.Write([]byte(xml.Header)); err != nil {
|
||||
return
|
||||
}
|
||||
_, err = c.response.Write(b)
|
||||
return
|
||||
}
|
||||
|
||||
func (c *context) Blob(code int, contentType string, b []byte) (err error) {
|
||||
c.writeContentType(contentType)
|
||||
c.response.WriteHeader(code)
|
||||
_, err = c.response.Write(b)
|
||||
return
|
||||
}
|
||||
|
||||
func (c *context) Stream(code int, contentType string, r io.Reader) (err error) {
|
||||
c.writeContentType(contentType)
|
||||
c.response.WriteHeader(code)
|
||||
_, err = io.Copy(c.response, r)
|
||||
return
|
||||
}
|
||||
|
||||
func (c *context) File(file string) (err error) {
|
||||
f, err := os.Open(file)
|
||||
if err != nil {
|
||||
return NotFoundHandler(c)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
fi, _ := f.Stat()
|
||||
if fi.IsDir() {
|
||||
file = filepath.Join(file, indexPage)
|
||||
f, err = os.Open(file)
|
||||
if err != nil {
|
||||
return NotFoundHandler(c)
|
||||
}
|
||||
defer f.Close()
|
||||
if fi, err = f.Stat(); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
http.ServeContent(c.Response(), c.Request(), fi.Name(), fi.ModTime(), f)
|
||||
return
|
||||
}
|
||||
|
||||
func (c *context) Attachment(file, name string) error {
|
||||
return c.contentDisposition(file, name, "attachment")
|
||||
}
|
||||
|
||||
func (c *context) Inline(file, name string) error {
|
||||
return c.contentDisposition(file, name, "inline")
|
||||
}
|
||||
|
||||
func (c *context) contentDisposition(file, name, dispositionType string) error {
|
||||
c.response.Header().Set(HeaderContentDisposition, fmt.Sprintf("%s; filename=%q", dispositionType, name))
|
||||
return c.File(file)
|
||||
}
|
||||
|
||||
func (c *context) NoContent(code int) error {
|
||||
c.response.WriteHeader(code)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *context) Redirect(code int, url string) error {
|
||||
if code < 300 || code > 308 {
|
||||
return ErrInvalidRedirectCode
|
||||
}
|
||||
c.response.Header().Set(HeaderLocation, url)
|
||||
c.response.WriteHeader(code)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *context) Error(err error) {
|
||||
c.echo.HTTPErrorHandler(err, c)
|
||||
}
|
||||
|
||||
func (c *context) Echo() *Echo {
|
||||
return c.echo
|
||||
}
|
||||
|
||||
func (c *context) Handler() HandlerFunc {
|
||||
return c.handler
|
||||
}
|
||||
|
||||
func (c *context) SetHandler(h HandlerFunc) {
|
||||
c.handler = h
|
||||
}
|
||||
|
||||
func (c *context) Logger() Logger {
|
||||
return c.echo.Logger
|
||||
}
|
||||
|
||||
func (c *context) Reset(r *http.Request, w http.ResponseWriter) {
|
||||
c.request = r
|
||||
c.response.reset(w)
|
||||
c.query = nil
|
||||
c.handler = NotFoundHandler
|
||||
c.store = nil
|
||||
c.path = ""
|
||||
c.pnames = nil
|
||||
// NOTE: Don't reset because it has to have length c.echo.maxParam at all times
|
||||
// c.pvalues = nil
|
||||
}
|
||||
844
vendor/github.com/labstack/echo/v4/echo.go
generated
vendored
Normal file
844
vendor/github.com/labstack/echo/v4/echo.go
generated
vendored
Normal file
|
|
@ -0,0 +1,844 @@
|
|||
/*
|
||||
Package echo implements high performance, minimalist Go web framework.
|
||||
|
||||
Example:
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/labstack/echo/v4/middleware"
|
||||
)
|
||||
|
||||
// Handler
|
||||
func hello(c echo.Context) error {
|
||||
return c.String(http.StatusOK, "Hello, World!")
|
||||
}
|
||||
|
||||
func main() {
|
||||
// Echo instance
|
||||
e := echo.New()
|
||||
|
||||
// Middleware
|
||||
e.Use(middleware.Logger())
|
||||
e.Use(middleware.Recover())
|
||||
|
||||
// Routes
|
||||
e.GET("/", hello)
|
||||
|
||||
// Start server
|
||||
e.Logger.Fatal(e.Start(":1323"))
|
||||
}
|
||||
|
||||
Learn more at https://echo.labstack.com
|
||||
*/
|
||||
package echo
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
stdContext "context"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
stdLog "log"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/labstack/gommon/color"
|
||||
"github.com/labstack/gommon/log"
|
||||
"golang.org/x/crypto/acme"
|
||||
"golang.org/x/crypto/acme/autocert"
|
||||
)
|
||||
|
||||
type (
|
||||
// Echo is the top-level framework instance.
|
||||
Echo struct {
|
||||
common
|
||||
StdLogger *stdLog.Logger
|
||||
colorer *color.Color
|
||||
premiddleware []MiddlewareFunc
|
||||
middleware []MiddlewareFunc
|
||||
maxParam *int
|
||||
router *Router
|
||||
routers map[string]*Router
|
||||
notFoundHandler HandlerFunc
|
||||
pool sync.Pool
|
||||
Server *http.Server
|
||||
TLSServer *http.Server
|
||||
Listener net.Listener
|
||||
TLSListener net.Listener
|
||||
AutoTLSManager autocert.Manager
|
||||
DisableHTTP2 bool
|
||||
Debug bool
|
||||
HideBanner bool
|
||||
HidePort bool
|
||||
HTTPErrorHandler HTTPErrorHandler
|
||||
Binder Binder
|
||||
Validator Validator
|
||||
Renderer Renderer
|
||||
Logger Logger
|
||||
}
|
||||
|
||||
// Route contains a handler and information for matching against requests.
|
||||
Route struct {
|
||||
Method string `json:"method"`
|
||||
Path string `json:"path"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// HTTPError represents an error that occurred while handling a request.
|
||||
HTTPError struct {
|
||||
Code int `json:"-"`
|
||||
Message interface{} `json:"message"`
|
||||
Internal error `json:"-"` // Stores the error returned by an external dependency
|
||||
}
|
||||
|
||||
// MiddlewareFunc defines a function to process middleware.
|
||||
MiddlewareFunc func(HandlerFunc) HandlerFunc
|
||||
|
||||
// HandlerFunc defines a function to serve HTTP requests.
|
||||
HandlerFunc func(Context) error
|
||||
|
||||
// HTTPErrorHandler is a centralized HTTP error handler.
|
||||
HTTPErrorHandler func(error, Context)
|
||||
|
||||
// Validator is the interface that wraps the Validate function.
|
||||
Validator interface {
|
||||
Validate(i interface{}) error
|
||||
}
|
||||
|
||||
// Renderer is the interface that wraps the Render function.
|
||||
Renderer interface {
|
||||
Render(io.Writer, string, interface{}, Context) error
|
||||
}
|
||||
|
||||
// Map defines a generic map of type `map[string]interface{}`.
|
||||
Map map[string]interface{}
|
||||
|
||||
// Common struct for Echo & Group.
|
||||
common struct{}
|
||||
)
|
||||
|
||||
// HTTP methods
|
||||
// NOTE: Deprecated, please use the stdlib constants directly instead.
|
||||
const (
|
||||
CONNECT = http.MethodConnect
|
||||
DELETE = http.MethodDelete
|
||||
GET = http.MethodGet
|
||||
HEAD = http.MethodHead
|
||||
OPTIONS = http.MethodOptions
|
||||
PATCH = http.MethodPatch
|
||||
POST = http.MethodPost
|
||||
// PROPFIND = "PROPFIND"
|
||||
PUT = http.MethodPut
|
||||
TRACE = http.MethodTrace
|
||||
)
|
||||
|
||||
// MIME types
|
||||
const (
|
||||
MIMEApplicationJSON = "application/json"
|
||||
MIMEApplicationJSONCharsetUTF8 = MIMEApplicationJSON + "; " + charsetUTF8
|
||||
MIMEApplicationJavaScript = "application/javascript"
|
||||
MIMEApplicationJavaScriptCharsetUTF8 = MIMEApplicationJavaScript + "; " + charsetUTF8
|
||||
MIMEApplicationXML = "application/xml"
|
||||
MIMEApplicationXMLCharsetUTF8 = MIMEApplicationXML + "; " + charsetUTF8
|
||||
MIMETextXML = "text/xml"
|
||||
MIMETextXMLCharsetUTF8 = MIMETextXML + "; " + charsetUTF8
|
||||
MIMEApplicationForm = "application/x-www-form-urlencoded"
|
||||
MIMEApplicationProtobuf = "application/protobuf"
|
||||
MIMEApplicationMsgpack = "application/msgpack"
|
||||
MIMETextHTML = "text/html"
|
||||
MIMETextHTMLCharsetUTF8 = MIMETextHTML + "; " + charsetUTF8
|
||||
MIMETextPlain = "text/plain"
|
||||
MIMETextPlainCharsetUTF8 = MIMETextPlain + "; " + charsetUTF8
|
||||
MIMEMultipartForm = "multipart/form-data"
|
||||
MIMEOctetStream = "application/octet-stream"
|
||||
)
|
||||
|
||||
const (
|
||||
charsetUTF8 = "charset=UTF-8"
|
||||
// PROPFIND Method can be used on collection and property resources.
|
||||
PROPFIND = "PROPFIND"
|
||||
// REPORT Method can be used to get information about a resource, see rfc 3253
|
||||
REPORT = "REPORT"
|
||||
)
|
||||
|
||||
// Headers
|
||||
const (
|
||||
HeaderAccept = "Accept"
|
||||
HeaderAcceptEncoding = "Accept-Encoding"
|
||||
HeaderAllow = "Allow"
|
||||
HeaderAuthorization = "Authorization"
|
||||
HeaderContentDisposition = "Content-Disposition"
|
||||
HeaderContentEncoding = "Content-Encoding"
|
||||
HeaderContentLength = "Content-Length"
|
||||
HeaderContentType = "Content-Type"
|
||||
HeaderCookie = "Cookie"
|
||||
HeaderSetCookie = "Set-Cookie"
|
||||
HeaderIfModifiedSince = "If-Modified-Since"
|
||||
HeaderLastModified = "Last-Modified"
|
||||
HeaderLocation = "Location"
|
||||
HeaderUpgrade = "Upgrade"
|
||||
HeaderVary = "Vary"
|
||||
HeaderWWWAuthenticate = "WWW-Authenticate"
|
||||
HeaderXForwardedFor = "X-Forwarded-For"
|
||||
HeaderXForwardedProto = "X-Forwarded-Proto"
|
||||
HeaderXForwardedProtocol = "X-Forwarded-Protocol"
|
||||
HeaderXForwardedSsl = "X-Forwarded-Ssl"
|
||||
HeaderXUrlScheme = "X-Url-Scheme"
|
||||
HeaderXHTTPMethodOverride = "X-HTTP-Method-Override"
|
||||
HeaderXRealIP = "X-Real-IP"
|
||||
HeaderXRequestID = "X-Request-ID"
|
||||
HeaderXRequestedWith = "X-Requested-With"
|
||||
HeaderServer = "Server"
|
||||
HeaderOrigin = "Origin"
|
||||
|
||||
// Access control
|
||||
HeaderAccessControlRequestMethod = "Access-Control-Request-Method"
|
||||
HeaderAccessControlRequestHeaders = "Access-Control-Request-Headers"
|
||||
HeaderAccessControlAllowOrigin = "Access-Control-Allow-Origin"
|
||||
HeaderAccessControlAllowMethods = "Access-Control-Allow-Methods"
|
||||
HeaderAccessControlAllowHeaders = "Access-Control-Allow-Headers"
|
||||
HeaderAccessControlAllowCredentials = "Access-Control-Allow-Credentials"
|
||||
HeaderAccessControlExposeHeaders = "Access-Control-Expose-Headers"
|
||||
HeaderAccessControlMaxAge = "Access-Control-Max-Age"
|
||||
|
||||
// Security
|
||||
HeaderStrictTransportSecurity = "Strict-Transport-Security"
|
||||
HeaderXContentTypeOptions = "X-Content-Type-Options"
|
||||
HeaderXXSSProtection = "X-XSS-Protection"
|
||||
HeaderXFrameOptions = "X-Frame-Options"
|
||||
HeaderContentSecurityPolicy = "Content-Security-Policy"
|
||||
HeaderContentSecurityPolicyReportOnly = "Content-Security-Policy-Report-Only"
|
||||
HeaderXCSRFToken = "X-CSRF-Token"
|
||||
HeaderReferrerPolicy = "Referrer-Policy"
|
||||
)
|
||||
|
||||
const (
|
||||
// Version of Echo
|
||||
Version = "4.1.11"
|
||||
website = "https://echo.labstack.com"
|
||||
// http://patorjk.com/software/taag/#p=display&f=Small%20Slant&t=Echo
|
||||
banner = `
|
||||
____ __
|
||||
/ __/___/ / ___
|
||||
/ _// __/ _ \/ _ \
|
||||
/___/\__/_//_/\___/ %s
|
||||
High performance, minimalist Go web framework
|
||||
%s
|
||||
____________________________________O/_______
|
||||
O\
|
||||
`
|
||||
)
|
||||
|
||||
var (
|
||||
methods = [...]string{
|
||||
http.MethodConnect,
|
||||
http.MethodDelete,
|
||||
http.MethodGet,
|
||||
http.MethodHead,
|
||||
http.MethodOptions,
|
||||
http.MethodPatch,
|
||||
http.MethodPost,
|
||||
PROPFIND,
|
||||
http.MethodPut,
|
||||
http.MethodTrace,
|
||||
REPORT,
|
||||
}
|
||||
)
|
||||
|
||||
// Errors
|
||||
var (
|
||||
ErrUnsupportedMediaType = NewHTTPError(http.StatusUnsupportedMediaType)
|
||||
ErrNotFound = NewHTTPError(http.StatusNotFound)
|
||||
ErrUnauthorized = NewHTTPError(http.StatusUnauthorized)
|
||||
ErrForbidden = NewHTTPError(http.StatusForbidden)
|
||||
ErrMethodNotAllowed = NewHTTPError(http.StatusMethodNotAllowed)
|
||||
ErrStatusRequestEntityTooLarge = NewHTTPError(http.StatusRequestEntityTooLarge)
|
||||
ErrTooManyRequests = NewHTTPError(http.StatusTooManyRequests)
|
||||
ErrBadRequest = NewHTTPError(http.StatusBadRequest)
|
||||
ErrBadGateway = NewHTTPError(http.StatusBadGateway)
|
||||
ErrInternalServerError = NewHTTPError(http.StatusInternalServerError)
|
||||
ErrRequestTimeout = NewHTTPError(http.StatusRequestTimeout)
|
||||
ErrServiceUnavailable = NewHTTPError(http.StatusServiceUnavailable)
|
||||
ErrValidatorNotRegistered = errors.New("validator not registered")
|
||||
ErrRendererNotRegistered = errors.New("renderer not registered")
|
||||
ErrInvalidRedirectCode = errors.New("invalid redirect status code")
|
||||
ErrCookieNotFound = errors.New("cookie not found")
|
||||
ErrInvalidCertOrKeyType = errors.New("invalid cert or key type, must be string or []byte")
|
||||
)
|
||||
|
||||
// Error handlers
|
||||
var (
|
||||
NotFoundHandler = func(c Context) error {
|
||||
return ErrNotFound
|
||||
}
|
||||
|
||||
MethodNotAllowedHandler = func(c Context) error {
|
||||
return ErrMethodNotAllowed
|
||||
}
|
||||
)
|
||||
|
||||
// New creates an instance of Echo.
|
||||
func New() (e *Echo) {
|
||||
e = &Echo{
|
||||
Server: new(http.Server),
|
||||
TLSServer: new(http.Server),
|
||||
AutoTLSManager: autocert.Manager{
|
||||
Prompt: autocert.AcceptTOS,
|
||||
},
|
||||
Logger: log.New("echo"),
|
||||
colorer: color.New(),
|
||||
maxParam: new(int),
|
||||
}
|
||||
e.Server.Handler = e
|
||||
e.TLSServer.Handler = e
|
||||
e.HTTPErrorHandler = e.DefaultHTTPErrorHandler
|
||||
e.Binder = &DefaultBinder{}
|
||||
e.Logger.SetLevel(log.ERROR)
|
||||
e.StdLogger = stdLog.New(e.Logger.Output(), e.Logger.Prefix()+": ", 0)
|
||||
e.pool.New = func() interface{} {
|
||||
return e.NewContext(nil, nil)
|
||||
}
|
||||
e.router = NewRouter(e)
|
||||
e.routers = map[string]*Router{}
|
||||
return
|
||||
}
|
||||
|
||||
// NewContext returns a Context instance.
|
||||
func (e *Echo) NewContext(r *http.Request, w http.ResponseWriter) Context {
|
||||
return &context{
|
||||
request: r,
|
||||
response: NewResponse(w, e),
|
||||
store: make(Map),
|
||||
echo: e,
|
||||
pvalues: make([]string, *e.maxParam),
|
||||
handler: NotFoundHandler,
|
||||
}
|
||||
}
|
||||
|
||||
// Router returns the default router.
|
||||
func (e *Echo) Router() *Router {
|
||||
return e.router
|
||||
}
|
||||
|
||||
// Routers returns the map of host => router.
|
||||
func (e *Echo) Routers() map[string]*Router {
|
||||
return e.routers
|
||||
}
|
||||
|
||||
// DefaultHTTPErrorHandler is the default HTTP error handler. It sends a JSON response
|
||||
// with status code.
|
||||
func (e *Echo) DefaultHTTPErrorHandler(err error, c Context) {
|
||||
he, ok := err.(*HTTPError)
|
||||
if ok {
|
||||
if he.Internal != nil {
|
||||
if herr, ok := he.Internal.(*HTTPError); ok {
|
||||
he = herr
|
||||
}
|
||||
}
|
||||
} else {
|
||||
he = &HTTPError{
|
||||
Code: http.StatusInternalServerError,
|
||||
Message: http.StatusText(http.StatusInternalServerError),
|
||||
}
|
||||
}
|
||||
if e.Debug {
|
||||
he.Message = err.Error()
|
||||
} else if m, ok := he.Message.(string); ok {
|
||||
he.Message = Map{"message": m}
|
||||
}
|
||||
|
||||
// Send response
|
||||
if !c.Response().Committed {
|
||||
if c.Request().Method == http.MethodHead { // Issue #608
|
||||
err = c.NoContent(he.Code)
|
||||
} else {
|
||||
err = c.JSON(he.Code, he.Message)
|
||||
}
|
||||
if err != nil {
|
||||
e.Logger.Error(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Pre adds middleware to the chain which is run before router.
|
||||
func (e *Echo) Pre(middleware ...MiddlewareFunc) {
|
||||
e.premiddleware = append(e.premiddleware, middleware...)
|
||||
}
|
||||
|
||||
// Use adds middleware to the chain which is run after router.
|
||||
func (e *Echo) Use(middleware ...MiddlewareFunc) {
|
||||
e.middleware = append(e.middleware, middleware...)
|
||||
}
|
||||
|
||||
// CONNECT registers a new CONNECT route for a path with matching handler in the
|
||||
// router with optional route-level middleware.
|
||||
func (e *Echo) CONNECT(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
|
||||
return e.Add(http.MethodConnect, path, h, m...)
|
||||
}
|
||||
|
||||
// DELETE registers a new DELETE route for a path with matching handler in the router
|
||||
// with optional route-level middleware.
|
||||
func (e *Echo) DELETE(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
|
||||
return e.Add(http.MethodDelete, path, h, m...)
|
||||
}
|
||||
|
||||
// GET registers a new GET route for a path with matching handler in the router
|
||||
// with optional route-level middleware.
|
||||
func (e *Echo) GET(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
|
||||
return e.Add(http.MethodGet, path, h, m...)
|
||||
}
|
||||
|
||||
// HEAD registers a new HEAD route for a path with matching handler in the
|
||||
// router with optional route-level middleware.
|
||||
func (e *Echo) HEAD(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
|
||||
return e.Add(http.MethodHead, path, h, m...)
|
||||
}
|
||||
|
||||
// OPTIONS registers a new OPTIONS route for a path with matching handler in the
|
||||
// router with optional route-level middleware.
|
||||
func (e *Echo) OPTIONS(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
|
||||
return e.Add(http.MethodOptions, path, h, m...)
|
||||
}
|
||||
|
||||
// PATCH registers a new PATCH route for a path with matching handler in the
|
||||
// router with optional route-level middleware.
|
||||
func (e *Echo) PATCH(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
|
||||
return e.Add(http.MethodPatch, path, h, m...)
|
||||
}
|
||||
|
||||
// POST registers a new POST route for a path with matching handler in the
|
||||
// router with optional route-level middleware.
|
||||
func (e *Echo) POST(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
|
||||
return e.Add(http.MethodPost, path, h, m...)
|
||||
}
|
||||
|
||||
// PUT registers a new PUT route for a path with matching handler in the
|
||||
// router with optional route-level middleware.
|
||||
func (e *Echo) PUT(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
|
||||
return e.Add(http.MethodPut, path, h, m...)
|
||||
}
|
||||
|
||||
// TRACE registers a new TRACE route for a path with matching handler in the
|
||||
// router with optional route-level middleware.
|
||||
func (e *Echo) TRACE(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
|
||||
return e.Add(http.MethodTrace, path, h, m...)
|
||||
}
|
||||
|
||||
// Any registers a new route for all HTTP methods and path with matching handler
|
||||
// in the router with optional route-level middleware.
|
||||
func (e *Echo) Any(path string, handler HandlerFunc, middleware ...MiddlewareFunc) []*Route {
|
||||
routes := make([]*Route, len(methods))
|
||||
for i, m := range methods {
|
||||
routes[i] = e.Add(m, path, handler, middleware...)
|
||||
}
|
||||
return routes
|
||||
}
|
||||
|
||||
// Match registers a new route for multiple HTTP methods and path with matching
|
||||
// handler in the router with optional route-level middleware.
|
||||
func (e *Echo) Match(methods []string, path string, handler HandlerFunc, middleware ...MiddlewareFunc) []*Route {
|
||||
routes := make([]*Route, len(methods))
|
||||
for i, m := range methods {
|
||||
routes[i] = e.Add(m, path, handler, middleware...)
|
||||
}
|
||||
return routes
|
||||
}
|
||||
|
||||
// Static registers a new route with path prefix to serve static files from the
|
||||
// provided root directory.
|
||||
func (e *Echo) Static(prefix, root string) *Route {
|
||||
if root == "" {
|
||||
root = "." // For security we want to restrict to CWD.
|
||||
}
|
||||
return e.static(prefix, root, e.GET)
|
||||
}
|
||||
|
||||
func (common) static(prefix, root string, get func(string, HandlerFunc, ...MiddlewareFunc) *Route) *Route {
|
||||
h := func(c Context) error {
|
||||
p, err := url.PathUnescape(c.Param("*"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
name := filepath.Join(root, path.Clean("/"+p)) // "/"+ for security
|
||||
return c.File(name)
|
||||
}
|
||||
if prefix == "/" {
|
||||
return get(prefix+"*", h)
|
||||
}
|
||||
return get(prefix+"/*", h)
|
||||
}
|
||||
|
||||
func (common) file(path, file string, get func(string, HandlerFunc, ...MiddlewareFunc) *Route,
|
||||
m ...MiddlewareFunc) *Route {
|
||||
return get(path, func(c Context) error {
|
||||
return c.File(file)
|
||||
}, m...)
|
||||
}
|
||||
|
||||
// File registers a new route with path to serve a static file with optional route-level middleware.
|
||||
func (e *Echo) File(path, file string, m ...MiddlewareFunc) *Route {
|
||||
return e.file(path, file, e.GET, m...)
|
||||
}
|
||||
|
||||
func (e *Echo) add(host, method, path string, handler HandlerFunc, middleware ...MiddlewareFunc) *Route {
|
||||
name := handlerName(handler)
|
||||
router := e.findRouter(host)
|
||||
router.Add(method, path, func(c Context) error {
|
||||
h := handler
|
||||
// Chain middleware
|
||||
for i := len(middleware) - 1; i >= 0; i-- {
|
||||
h = middleware[i](h)
|
||||
}
|
||||
return h(c)
|
||||
})
|
||||
r := &Route{
|
||||
Method: method,
|
||||
Path: path,
|
||||
Name: name,
|
||||
}
|
||||
e.router.routes[method+path] = r
|
||||
return r
|
||||
}
|
||||
|
||||
// Add registers a new route for an HTTP method and path with matching handler
|
||||
// in the router with optional route-level middleware.
|
||||
func (e *Echo) Add(method, path string, handler HandlerFunc, middleware ...MiddlewareFunc) *Route {
|
||||
return e.add("", method, path, handler, middleware...)
|
||||
}
|
||||
|
||||
// Host creates a new router group for the provided host and optional host-level middleware.
|
||||
func (e *Echo) Host(name string, m ...MiddlewareFunc) (g *Group) {
|
||||
e.routers[name] = NewRouter(e)
|
||||
g = &Group{host: name, echo: e}
|
||||
g.Use(m...)
|
||||
return
|
||||
}
|
||||
|
||||
// Group creates a new router group with prefix and optional group-level middleware.
|
||||
func (e *Echo) Group(prefix string, m ...MiddlewareFunc) (g *Group) {
|
||||
g = &Group{prefix: prefix, echo: e}
|
||||
g.Use(m...)
|
||||
return
|
||||
}
|
||||
|
||||
// URI generates a URI from handler.
|
||||
func (e *Echo) URI(handler HandlerFunc, params ...interface{}) string {
|
||||
name := handlerName(handler)
|
||||
return e.Reverse(name, params...)
|
||||
}
|
||||
|
||||
// URL is an alias for `URI` function.
|
||||
func (e *Echo) URL(h HandlerFunc, params ...interface{}) string {
|
||||
return e.URI(h, params...)
|
||||
}
|
||||
|
||||
// Reverse generates an URL from route name and provided parameters.
|
||||
func (e *Echo) Reverse(name string, params ...interface{}) string {
|
||||
uri := new(bytes.Buffer)
|
||||
ln := len(params)
|
||||
n := 0
|
||||
for _, r := range e.router.routes {
|
||||
if r.Name == name {
|
||||
for i, l := 0, len(r.Path); i < l; i++ {
|
||||
if r.Path[i] == ':' && n < ln {
|
||||
for ; i < l && r.Path[i] != '/'; i++ {
|
||||
}
|
||||
uri.WriteString(fmt.Sprintf("%v", params[n]))
|
||||
n++
|
||||
}
|
||||
if i < l {
|
||||
uri.WriteByte(r.Path[i])
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
return uri.String()
|
||||
}
|
||||
|
||||
// Routes returns the registered routes.
|
||||
func (e *Echo) Routes() []*Route {
|
||||
routes := make([]*Route, 0, len(e.router.routes))
|
||||
for _, v := range e.router.routes {
|
||||
routes = append(routes, v)
|
||||
}
|
||||
return routes
|
||||
}
|
||||
|
||||
// AcquireContext returns an empty `Context` instance from the pool.
|
||||
// You must return the context by calling `ReleaseContext()`.
|
||||
func (e *Echo) AcquireContext() Context {
|
||||
return e.pool.Get().(Context)
|
||||
}
|
||||
|
||||
// ReleaseContext returns the `Context` instance back to the pool.
|
||||
// You must call it after `AcquireContext()`.
|
||||
func (e *Echo) ReleaseContext(c Context) {
|
||||
e.pool.Put(c)
|
||||
}
|
||||
|
||||
// ServeHTTP implements `http.Handler` interface, which serves HTTP requests.
|
||||
func (e *Echo) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
// Acquire context
|
||||
c := e.pool.Get().(*context)
|
||||
c.Reset(r, w)
|
||||
|
||||
h := NotFoundHandler
|
||||
|
||||
if e.premiddleware == nil {
|
||||
e.findRouter(r.Host).Find(r.Method, getPath(r), c)
|
||||
h = c.Handler()
|
||||
h = applyMiddleware(h, e.middleware...)
|
||||
} else {
|
||||
h = func(c Context) error {
|
||||
e.findRouter(r.Host).Find(r.Method, getPath(r), c)
|
||||
h := c.Handler()
|
||||
h = applyMiddleware(h, e.middleware...)
|
||||
return h(c)
|
||||
}
|
||||
h = applyMiddleware(h, e.premiddleware...)
|
||||
}
|
||||
|
||||
// Execute chain
|
||||
if err := h(c); err != nil {
|
||||
e.HTTPErrorHandler(err, c)
|
||||
}
|
||||
|
||||
// Release context
|
||||
e.pool.Put(c)
|
||||
}
|
||||
|
||||
// Start starts an HTTP server.
|
||||
func (e *Echo) Start(address string) error {
|
||||
e.Server.Addr = address
|
||||
return e.StartServer(e.Server)
|
||||
}
|
||||
|
||||
// StartTLS starts an HTTPS server.
|
||||
// If `certFile` or `keyFile` is `string` the values are treated as file paths.
|
||||
// If `certFile` or `keyFile` is `[]byte` the values are treated as the certificate or key as-is.
|
||||
func (e *Echo) StartTLS(address string, certFile, keyFile interface{}) (err error) {
|
||||
var cert []byte
|
||||
if cert, err = filepathOrContent(certFile); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var key []byte
|
||||
if key, err = filepathOrContent(keyFile); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
s := e.TLSServer
|
||||
s.TLSConfig = new(tls.Config)
|
||||
s.TLSConfig.Certificates = make([]tls.Certificate, 1)
|
||||
if s.TLSConfig.Certificates[0], err = tls.X509KeyPair(cert, key); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return e.startTLS(address)
|
||||
}
|
||||
|
||||
func filepathOrContent(fileOrContent interface{}) (content []byte, err error) {
|
||||
switch v := fileOrContent.(type) {
|
||||
case string:
|
||||
return ioutil.ReadFile(v)
|
||||
case []byte:
|
||||
return v, nil
|
||||
default:
|
||||
return nil, ErrInvalidCertOrKeyType
|
||||
}
|
||||
}
|
||||
|
||||
// StartAutoTLS starts an HTTPS server using certificates automatically installed from https://letsencrypt.org.
|
||||
func (e *Echo) StartAutoTLS(address string) error {
|
||||
s := e.TLSServer
|
||||
s.TLSConfig = new(tls.Config)
|
||||
s.TLSConfig.GetCertificate = e.AutoTLSManager.GetCertificate
|
||||
s.TLSConfig.NextProtos = append(s.TLSConfig.NextProtos, acme.ALPNProto)
|
||||
return e.startTLS(address)
|
||||
}
|
||||
|
||||
func (e *Echo) startTLS(address string) error {
|
||||
s := e.TLSServer
|
||||
s.Addr = address
|
||||
if !e.DisableHTTP2 {
|
||||
s.TLSConfig.NextProtos = append(s.TLSConfig.NextProtos, "h2")
|
||||
}
|
||||
return e.StartServer(e.TLSServer)
|
||||
}
|
||||
|
||||
// StartServer starts a custom http server.
|
||||
func (e *Echo) StartServer(s *http.Server) (err error) {
|
||||
// Setup
|
||||
e.colorer.SetOutput(e.Logger.Output())
|
||||
s.ErrorLog = e.StdLogger
|
||||
s.Handler = e
|
||||
if e.Debug {
|
||||
e.Logger.SetLevel(log.DEBUG)
|
||||
}
|
||||
|
||||
if !e.HideBanner {
|
||||
e.colorer.Printf(banner, e.colorer.Red("v"+Version), e.colorer.Blue(website))
|
||||
}
|
||||
|
||||
if s.TLSConfig == nil {
|
||||
if e.Listener == nil {
|
||||
e.Listener, err = newListener(s.Addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if !e.HidePort {
|
||||
e.colorer.Printf("⇨ http server started on %s\n", e.colorer.Green(e.Listener.Addr()))
|
||||
}
|
||||
return s.Serve(e.Listener)
|
||||
}
|
||||
if e.TLSListener == nil {
|
||||
l, err := newListener(s.Addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
e.TLSListener = tls.NewListener(l, s.TLSConfig)
|
||||
}
|
||||
if !e.HidePort {
|
||||
e.colorer.Printf("⇨ https server started on %s\n", e.colorer.Green(e.TLSListener.Addr()))
|
||||
}
|
||||
return s.Serve(e.TLSListener)
|
||||
}
|
||||
|
||||
// Close immediately stops the server.
|
||||
// It internally calls `http.Server#Close()`.
|
||||
func (e *Echo) Close() error {
|
||||
if err := e.TLSServer.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
return e.Server.Close()
|
||||
}
|
||||
|
||||
// Shutdown stops the server gracefully.
|
||||
// It internally calls `http.Server#Shutdown()`.
|
||||
func (e *Echo) Shutdown(ctx stdContext.Context) error {
|
||||
if err := e.TLSServer.Shutdown(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
return e.Server.Shutdown(ctx)
|
||||
}
|
||||
|
||||
// NewHTTPError creates a new HTTPError instance.
|
||||
func NewHTTPError(code int, message ...interface{}) *HTTPError {
|
||||
he := &HTTPError{Code: code, Message: http.StatusText(code)}
|
||||
if len(message) > 0 {
|
||||
he.Message = message[0]
|
||||
}
|
||||
return he
|
||||
}
|
||||
|
||||
// Error makes it compatible with `error` interface.
|
||||
func (he *HTTPError) Error() string {
|
||||
return fmt.Sprintf("code=%d, message=%v, internal=%v", he.Code, he.Message, he.Internal)
|
||||
}
|
||||
|
||||
// SetInternal sets error to HTTPError.Internal
|
||||
func (he *HTTPError) SetInternal(err error) *HTTPError {
|
||||
he.Internal = err
|
||||
return he
|
||||
}
|
||||
|
||||
// WrapHandler wraps `http.Handler` into `echo.HandlerFunc`.
|
||||
func WrapHandler(h http.Handler) HandlerFunc {
|
||||
return func(c Context) error {
|
||||
h.ServeHTTP(c.Response(), c.Request())
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WrapMiddleware wraps `func(http.Handler) http.Handler` into `echo.MiddlewareFunc`
|
||||
func WrapMiddleware(m func(http.Handler) http.Handler) MiddlewareFunc {
|
||||
return func(next HandlerFunc) HandlerFunc {
|
||||
return func(c Context) (err error) {
|
||||
m(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
c.SetRequest(r)
|
||||
c.SetResponse(NewResponse(w, c.Echo()))
|
||||
err = next(c)
|
||||
})).ServeHTTP(c.Response(), c.Request())
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getPath(r *http.Request) string {
|
||||
path := r.URL.RawPath
|
||||
if path == "" {
|
||||
path = r.URL.Path
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
func (e *Echo) findRouter(host string) *Router {
|
||||
if len(e.routers) > 0 {
|
||||
if r, ok := e.routers[host]; ok {
|
||||
return r
|
||||
}
|
||||
}
|
||||
return e.router
|
||||
}
|
||||
|
||||
func handlerName(h HandlerFunc) string {
|
||||
t := reflect.ValueOf(h).Type()
|
||||
if t.Kind() == reflect.Func {
|
||||
return runtime.FuncForPC(reflect.ValueOf(h).Pointer()).Name()
|
||||
}
|
||||
return t.String()
|
||||
}
|
||||
|
||||
// // PathUnescape is wraps `url.PathUnescape`
|
||||
// func PathUnescape(s string) (string, error) {
|
||||
// return url.PathUnescape(s)
|
||||
// }
|
||||
|
||||
// tcpKeepAliveListener sets TCP keep-alive timeouts on accepted
|
||||
// connections. It's used by ListenAndServe and ListenAndServeTLS so
|
||||
// dead TCP connections (e.g. closing laptop mid-download) eventually
|
||||
// go away.
|
||||
type tcpKeepAliveListener struct {
|
||||
*net.TCPListener
|
||||
}
|
||||
|
||||
func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
|
||||
if c, err = ln.AcceptTCP(); err != nil {
|
||||
return
|
||||
} else if err = c.(*net.TCPConn).SetKeepAlive(true); err != nil {
|
||||
return
|
||||
} else if err = c.(*net.TCPConn).SetKeepAlivePeriod(3 * time.Minute); err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func newListener(address string) (*tcpKeepAliveListener, error) {
|
||||
l, err := net.Listen("tcp", address)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &tcpKeepAliveListener{l.(*net.TCPListener)}, nil
|
||||
}
|
||||
|
||||
func applyMiddleware(h HandlerFunc, middleware ...MiddlewareFunc) HandlerFunc {
|
||||
for i := len(middleware) - 1; i >= 0; i-- {
|
||||
h = middleware[i](h)
|
||||
}
|
||||
return h
|
||||
}
|
||||
11
vendor/github.com/labstack/echo/v4/go.mod
generated
vendored
Normal file
11
vendor/github.com/labstack/echo/v4/go.mod
generated
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
module github.com/labstack/echo/v4
|
||||
|
||||
go 1.12
|
||||
|
||||
require (
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
||||
github.com/labstack/gommon v0.3.0
|
||||
github.com/stretchr/testify v1.4.0
|
||||
github.com/valyala/fasttemplate v1.0.1
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4
|
||||
)
|
||||
34
vendor/github.com/labstack/echo/v4/go.sum
generated
vendored
Normal file
34
vendor/github.com/labstack/echo/v4/go.sum
generated
vendored
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/labstack/gommon v0.3.0 h1:JEeO0bvc78PKdyHxloTKiF8BD5iGrH8T6MSeGvSgob0=
|
||||
github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
|
||||
github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU=
|
||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.9 h1:d5US/mDsogSGW37IV293h//ZFaeajb69h+EHFsv2xGg=
|
||||
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasttemplate v1.0.1 h1:tY9CJiPnMXf1ERmG2EyK7gNUd+c6RKGD0IfU8WdUSz8=
|
||||
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc=
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
124
vendor/github.com/labstack/echo/v4/group.go
generated
vendored
Normal file
124
vendor/github.com/labstack/echo/v4/group.go
generated
vendored
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
package echo
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type (
|
||||
// Group is a set of sub-routes for a specified route. It can be used for inner
|
||||
// routes that share a common middleware or functionality that should be separate
|
||||
// from the parent echo instance while still inheriting from it.
|
||||
Group struct {
|
||||
common
|
||||
host string
|
||||
prefix string
|
||||
middleware []MiddlewareFunc
|
||||
echo *Echo
|
||||
}
|
||||
)
|
||||
|
||||
// Use implements `Echo#Use()` for sub-routes within the Group.
|
||||
func (g *Group) Use(middleware ...MiddlewareFunc) {
|
||||
g.middleware = append(g.middleware, middleware...)
|
||||
if len(g.middleware) == 0 {
|
||||
return
|
||||
}
|
||||
// Allow all requests to reach the group as they might get dropped if router
|
||||
// doesn't find a match, making none of the group middleware process.
|
||||
g.Any("", NotFoundHandler)
|
||||
g.Any("/*", NotFoundHandler)
|
||||
}
|
||||
|
||||
// CONNECT implements `Echo#CONNECT()` for sub-routes within the Group.
|
||||
func (g *Group) CONNECT(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
|
||||
return g.Add(http.MethodConnect, path, h, m...)
|
||||
}
|
||||
|
||||
// DELETE implements `Echo#DELETE()` for sub-routes within the Group.
|
||||
func (g *Group) DELETE(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
|
||||
return g.Add(http.MethodDelete, path, h, m...)
|
||||
}
|
||||
|
||||
// GET implements `Echo#GET()` for sub-routes within the Group.
|
||||
func (g *Group) GET(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
|
||||
return g.Add(http.MethodGet, path, h, m...)
|
||||
}
|
||||
|
||||
// HEAD implements `Echo#HEAD()` for sub-routes within the Group.
|
||||
func (g *Group) HEAD(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
|
||||
return g.Add(http.MethodHead, path, h, m...)
|
||||
}
|
||||
|
||||
// OPTIONS implements `Echo#OPTIONS()` for sub-routes within the Group.
|
||||
func (g *Group) OPTIONS(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
|
||||
return g.Add(http.MethodOptions, path, h, m...)
|
||||
}
|
||||
|
||||
// PATCH implements `Echo#PATCH()` for sub-routes within the Group.
|
||||
func (g *Group) PATCH(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
|
||||
return g.Add(http.MethodPatch, path, h, m...)
|
||||
}
|
||||
|
||||
// POST implements `Echo#POST()` for sub-routes within the Group.
|
||||
func (g *Group) POST(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
|
||||
return g.Add(http.MethodPost, path, h, m...)
|
||||
}
|
||||
|
||||
// PUT implements `Echo#PUT()` for sub-routes within the Group.
|
||||
func (g *Group) PUT(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
|
||||
return g.Add(http.MethodPut, path, h, m...)
|
||||
}
|
||||
|
||||
// TRACE implements `Echo#TRACE()` for sub-routes within the Group.
|
||||
func (g *Group) TRACE(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
|
||||
return g.Add(http.MethodTrace, path, h, m...)
|
||||
}
|
||||
|
||||
// Any implements `Echo#Any()` for sub-routes within the Group.
|
||||
func (g *Group) Any(path string, handler HandlerFunc, middleware ...MiddlewareFunc) []*Route {
|
||||
routes := make([]*Route, len(methods))
|
||||
for i, m := range methods {
|
||||
routes[i] = g.Add(m, path, handler, middleware...)
|
||||
}
|
||||
return routes
|
||||
}
|
||||
|
||||
// Match implements `Echo#Match()` for sub-routes within the Group.
|
||||
func (g *Group) Match(methods []string, path string, handler HandlerFunc, middleware ...MiddlewareFunc) []*Route {
|
||||
routes := make([]*Route, len(methods))
|
||||
for i, m := range methods {
|
||||
routes[i] = g.Add(m, path, handler, middleware...)
|
||||
}
|
||||
return routes
|
||||
}
|
||||
|
||||
// Group creates a new sub-group with prefix and optional sub-group-level middleware.
|
||||
func (g *Group) Group(prefix string, middleware ...MiddlewareFunc) (sg *Group) {
|
||||
m := make([]MiddlewareFunc, 0, len(g.middleware)+len(middleware))
|
||||
m = append(m, g.middleware...)
|
||||
m = append(m, middleware...)
|
||||
sg = g.echo.Group(g.prefix+prefix, m...)
|
||||
sg.host = g.host
|
||||
return
|
||||
}
|
||||
|
||||
// Static implements `Echo#Static()` for sub-routes within the Group.
|
||||
func (g *Group) Static(prefix, root string) {
|
||||
g.static(prefix, root, g.GET)
|
||||
}
|
||||
|
||||
// File implements `Echo#File()` for sub-routes within the Group.
|
||||
func (g *Group) File(path, file string) {
|
||||
g.file(g.prefix+path, file, g.GET)
|
||||
}
|
||||
|
||||
// Add implements `Echo#Add()` for sub-routes within the Group.
|
||||
func (g *Group) Add(method, path string, handler HandlerFunc, middleware ...MiddlewareFunc) *Route {
|
||||
// Combine into a new slice to avoid accidentally passing the same slice for
|
||||
// multiple routes, which would lead to later add() calls overwriting the
|
||||
// middleware from earlier calls.
|
||||
m := make([]MiddlewareFunc, 0, len(g.middleware)+len(middleware))
|
||||
m = append(m, g.middleware...)
|
||||
m = append(m, middleware...)
|
||||
return g.echo.add(g.host, method, g.prefix+path, handler, m...)
|
||||
}
|
||||
41
vendor/github.com/labstack/echo/v4/log.go
generated
vendored
Normal file
41
vendor/github.com/labstack/echo/v4/log.go
generated
vendored
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
package echo
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/labstack/gommon/log"
|
||||
)
|
||||
|
||||
type (
|
||||
// Logger defines the logging interface.
|
||||
Logger interface {
|
||||
Output() io.Writer
|
||||
SetOutput(w io.Writer)
|
||||
Prefix() string
|
||||
SetPrefix(p string)
|
||||
Level() log.Lvl
|
||||
SetLevel(v log.Lvl)
|
||||
SetHeader(h string)
|
||||
Print(i ...interface{})
|
||||
Printf(format string, args ...interface{})
|
||||
Printj(j log.JSON)
|
||||
Debug(i ...interface{})
|
||||
Debugf(format string, args ...interface{})
|
||||
Debugj(j log.JSON)
|
||||
Info(i ...interface{})
|
||||
Infof(format string, args ...interface{})
|
||||
Infoj(j log.JSON)
|
||||
Warn(i ...interface{})
|
||||
Warnf(format string, args ...interface{})
|
||||
Warnj(j log.JSON)
|
||||
Error(i ...interface{})
|
||||
Errorf(format string, args ...interface{})
|
||||
Errorj(j log.JSON)
|
||||
Fatal(i ...interface{})
|
||||
Fatalj(j log.JSON)
|
||||
Fatalf(format string, args ...interface{})
|
||||
Panic(i ...interface{})
|
||||
Panicj(j log.JSON)
|
||||
Panicf(format string, args ...interface{})
|
||||
}
|
||||
)
|
||||
104
vendor/github.com/labstack/echo/v4/response.go
generated
vendored
Normal file
104
vendor/github.com/labstack/echo/v4/response.go
generated
vendored
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
package echo
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"net"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type (
|
||||
// Response wraps an http.ResponseWriter and implements its interface to be used
|
||||
// by an HTTP handler to construct an HTTP response.
|
||||
// See: https://golang.org/pkg/net/http/#ResponseWriter
|
||||
Response struct {
|
||||
echo *Echo
|
||||
beforeFuncs []func()
|
||||
afterFuncs []func()
|
||||
Writer http.ResponseWriter
|
||||
Status int
|
||||
Size int64
|
||||
Committed bool
|
||||
}
|
||||
)
|
||||
|
||||
// NewResponse creates a new instance of Response.
|
||||
func NewResponse(w http.ResponseWriter, e *Echo) (r *Response) {
|
||||
return &Response{Writer: w, echo: e}
|
||||
}
|
||||
|
||||
// Header returns the header map for the writer that will be sent by
|
||||
// WriteHeader. Changing the header after a call to WriteHeader (or Write) has
|
||||
// no effect unless the modified headers were declared as trailers by setting
|
||||
// the "Trailer" header before the call to WriteHeader (see example)
|
||||
// To suppress implicit response headers, set their value to nil.
|
||||
// Example: https://golang.org/pkg/net/http/#example_ResponseWriter_trailers
|
||||
func (r *Response) Header() http.Header {
|
||||
return r.Writer.Header()
|
||||
}
|
||||
|
||||
// Before registers a function which is called just before the response is written.
|
||||
func (r *Response) Before(fn func()) {
|
||||
r.beforeFuncs = append(r.beforeFuncs, fn)
|
||||
}
|
||||
|
||||
// After registers a function which is called just after the response is written.
|
||||
// If the `Content-Length` is unknown, none of the after function is executed.
|
||||
func (r *Response) After(fn func()) {
|
||||
r.afterFuncs = append(r.afterFuncs, fn)
|
||||
}
|
||||
|
||||
// WriteHeader sends an HTTP response header with status code. If WriteHeader is
|
||||
// not called explicitly, the first call to Write will trigger an implicit
|
||||
// WriteHeader(http.StatusOK). Thus explicit calls to WriteHeader are mainly
|
||||
// used to send error codes.
|
||||
func (r *Response) WriteHeader(code int) {
|
||||
if r.Committed {
|
||||
r.echo.Logger.Warn("response already committed")
|
||||
return
|
||||
}
|
||||
for _, fn := range r.beforeFuncs {
|
||||
fn()
|
||||
}
|
||||
r.Status = code
|
||||
r.Writer.WriteHeader(code)
|
||||
r.Committed = true
|
||||
}
|
||||
|
||||
// Write writes the data to the connection as part of an HTTP reply.
|
||||
func (r *Response) Write(b []byte) (n int, err error) {
|
||||
if !r.Committed {
|
||||
if r.Status == 0 {
|
||||
r.Status = http.StatusOK
|
||||
}
|
||||
r.WriteHeader(r.Status)
|
||||
}
|
||||
n, err = r.Writer.Write(b)
|
||||
r.Size += int64(n)
|
||||
for _, fn := range r.afterFuncs {
|
||||
fn()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Flush implements the http.Flusher interface to allow an HTTP handler to flush
|
||||
// buffered data to the client.
|
||||
// See [http.Flusher](https://golang.org/pkg/net/http/#Flusher)
|
||||
func (r *Response) Flush() {
|
||||
r.Writer.(http.Flusher).Flush()
|
||||
}
|
||||
|
||||
// Hijack implements the http.Hijacker interface to allow an HTTP handler to
|
||||
// take over the connection.
|
||||
// See [http.Hijacker](https://golang.org/pkg/net/http/#Hijacker)
|
||||
func (r *Response) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
||||
return r.Writer.(http.Hijacker).Hijack()
|
||||
}
|
||||
|
||||
func (r *Response) reset(w http.ResponseWriter) {
|
||||
r.beforeFuncs = nil
|
||||
r.afterFuncs = nil
|
||||
r.Writer = w
|
||||
r.Size = 0
|
||||
r.Status = http.StatusOK
|
||||
r.Committed = false
|
||||
}
|
||||
443
vendor/github.com/labstack/echo/v4/router.go
generated
vendored
Normal file
443
vendor/github.com/labstack/echo/v4/router.go
generated
vendored
Normal file
|
|
@ -0,0 +1,443 @@
|
|||
package echo
|
||||
|
||||
import "net/http"
|
||||
|
||||
type (
|
||||
// Router is the registry of all registered routes for an `Echo` instance for
|
||||
// request matching and URL path parameter parsing.
|
||||
Router struct {
|
||||
tree *node
|
||||
routes map[string]*Route
|
||||
echo *Echo
|
||||
}
|
||||
node struct {
|
||||
kind kind
|
||||
label byte
|
||||
prefix string
|
||||
parent *node
|
||||
children children
|
||||
ppath string
|
||||
pnames []string
|
||||
methodHandler *methodHandler
|
||||
}
|
||||
kind uint8
|
||||
children []*node
|
||||
methodHandler struct {
|
||||
connect HandlerFunc
|
||||
delete HandlerFunc
|
||||
get HandlerFunc
|
||||
head HandlerFunc
|
||||
options HandlerFunc
|
||||
patch HandlerFunc
|
||||
post HandlerFunc
|
||||
propfind HandlerFunc
|
||||
put HandlerFunc
|
||||
trace HandlerFunc
|
||||
report HandlerFunc
|
||||
}
|
||||
)
|
||||
|
||||
const (
|
||||
skind kind = iota
|
||||
pkind
|
||||
akind
|
||||
)
|
||||
|
||||
// NewRouter returns a new Router instance.
|
||||
func NewRouter(e *Echo) *Router {
|
||||
return &Router{
|
||||
tree: &node{
|
||||
methodHandler: new(methodHandler),
|
||||
},
|
||||
routes: map[string]*Route{},
|
||||
echo: e,
|
||||
}
|
||||
}
|
||||
|
||||
// Add registers a new route for method and path with matching handler.
|
||||
func (r *Router) Add(method, path string, h HandlerFunc) {
|
||||
// Validate path
|
||||
if path == "" {
|
||||
path = "/"
|
||||
}
|
||||
if path[0] != '/' {
|
||||
path = "/" + path
|
||||
}
|
||||
pnames := []string{} // Param names
|
||||
ppath := path // Pristine path
|
||||
|
||||
for i, l := 0, len(path); i < l; i++ {
|
||||
if path[i] == ':' {
|
||||
j := i + 1
|
||||
|
||||
r.insert(method, path[:i], nil, skind, "", nil)
|
||||
for ; i < l && path[i] != '/'; i++ {
|
||||
}
|
||||
|
||||
pnames = append(pnames, path[j:i])
|
||||
path = path[:j] + path[i:]
|
||||
i, l = j, len(path)
|
||||
|
||||
if i == l {
|
||||
r.insert(method, path[:i], h, pkind, ppath, pnames)
|
||||
} else {
|
||||
r.insert(method, path[:i], nil, pkind, "", nil)
|
||||
}
|
||||
} else if path[i] == '*' {
|
||||
r.insert(method, path[:i], nil, skind, "", nil)
|
||||
pnames = append(pnames, "*")
|
||||
r.insert(method, path[:i+1], h, akind, ppath, pnames)
|
||||
}
|
||||
}
|
||||
|
||||
r.insert(method, path, h, skind, ppath, pnames)
|
||||
}
|
||||
|
||||
func (r *Router) insert(method, path string, h HandlerFunc, t kind, ppath string, pnames []string) {
|
||||
// Adjust max param
|
||||
l := len(pnames)
|
||||
if *r.echo.maxParam < l {
|
||||
*r.echo.maxParam = l
|
||||
}
|
||||
|
||||
cn := r.tree // Current node as root
|
||||
if cn == nil {
|
||||
panic("echo: invalid method")
|
||||
}
|
||||
search := path
|
||||
|
||||
for {
|
||||
sl := len(search)
|
||||
pl := len(cn.prefix)
|
||||
l := 0
|
||||
|
||||
// LCP
|
||||
max := pl
|
||||
if sl < max {
|
||||
max = sl
|
||||
}
|
||||
for ; l < max && search[l] == cn.prefix[l]; l++ {
|
||||
}
|
||||
|
||||
if l == 0 {
|
||||
// At root node
|
||||
cn.label = search[0]
|
||||
cn.prefix = search
|
||||
if h != nil {
|
||||
cn.kind = t
|
||||
cn.addHandler(method, h)
|
||||
cn.ppath = ppath
|
||||
cn.pnames = pnames
|
||||
}
|
||||
} else if l < pl {
|
||||
// Split node
|
||||
n := newNode(cn.kind, cn.prefix[l:], cn, cn.children, cn.methodHandler, cn.ppath, cn.pnames)
|
||||
|
||||
// Reset parent node
|
||||
cn.kind = skind
|
||||
cn.label = cn.prefix[0]
|
||||
cn.prefix = cn.prefix[:l]
|
||||
cn.children = nil
|
||||
cn.methodHandler = new(methodHandler)
|
||||
cn.ppath = ""
|
||||
cn.pnames = nil
|
||||
|
||||
cn.addChild(n)
|
||||
|
||||
if l == sl {
|
||||
// At parent node
|
||||
cn.kind = t
|
||||
cn.addHandler(method, h)
|
||||
cn.ppath = ppath
|
||||
cn.pnames = pnames
|
||||
} else {
|
||||
// Create child node
|
||||
n = newNode(t, search[l:], cn, nil, new(methodHandler), ppath, pnames)
|
||||
n.addHandler(method, h)
|
||||
cn.addChild(n)
|
||||
}
|
||||
} else if l < sl {
|
||||
search = search[l:]
|
||||
c := cn.findChildWithLabel(search[0])
|
||||
if c != nil {
|
||||
// Go deeper
|
||||
cn = c
|
||||
continue
|
||||
}
|
||||
// Create child node
|
||||
n := newNode(t, search, cn, nil, new(methodHandler), ppath, pnames)
|
||||
n.addHandler(method, h)
|
||||
cn.addChild(n)
|
||||
} else {
|
||||
// Node already exists
|
||||
if h != nil {
|
||||
cn.addHandler(method, h)
|
||||
cn.ppath = ppath
|
||||
if len(cn.pnames) == 0 { // Issue #729
|
||||
cn.pnames = pnames
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func newNode(t kind, pre string, p *node, c children, mh *methodHandler, ppath string, pnames []string) *node {
|
||||
return &node{
|
||||
kind: t,
|
||||
label: pre[0],
|
||||
prefix: pre,
|
||||
parent: p,
|
||||
children: c,
|
||||
ppath: ppath,
|
||||
pnames: pnames,
|
||||
methodHandler: mh,
|
||||
}
|
||||
}
|
||||
|
||||
func (n *node) addChild(c *node) {
|
||||
n.children = append(n.children, c)
|
||||
}
|
||||
|
||||
func (n *node) findChild(l byte, t kind) *node {
|
||||
for _, c := range n.children {
|
||||
if c.label == l && c.kind == t {
|
||||
return c
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *node) findChildWithLabel(l byte) *node {
|
||||
for _, c := range n.children {
|
||||
if c.label == l {
|
||||
return c
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *node) findChildByKind(t kind) *node {
|
||||
for _, c := range n.children {
|
||||
if c.kind == t {
|
||||
return c
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *node) addHandler(method string, h HandlerFunc) {
|
||||
switch method {
|
||||
case http.MethodConnect:
|
||||
n.methodHandler.connect = h
|
||||
case http.MethodDelete:
|
||||
n.methodHandler.delete = h
|
||||
case http.MethodGet:
|
||||
n.methodHandler.get = h
|
||||
case http.MethodHead:
|
||||
n.methodHandler.head = h
|
||||
case http.MethodOptions:
|
||||
n.methodHandler.options = h
|
||||
case http.MethodPatch:
|
||||
n.methodHandler.patch = h
|
||||
case http.MethodPost:
|
||||
n.methodHandler.post = h
|
||||
case PROPFIND:
|
||||
n.methodHandler.propfind = h
|
||||
case http.MethodPut:
|
||||
n.methodHandler.put = h
|
||||
case http.MethodTrace:
|
||||
n.methodHandler.trace = h
|
||||
case REPORT:
|
||||
n.methodHandler.report = h
|
||||
}
|
||||
}
|
||||
|
||||
func (n *node) findHandler(method string) HandlerFunc {
|
||||
switch method {
|
||||
case http.MethodConnect:
|
||||
return n.methodHandler.connect
|
||||
case http.MethodDelete:
|
||||
return n.methodHandler.delete
|
||||
case http.MethodGet:
|
||||
return n.methodHandler.get
|
||||
case http.MethodHead:
|
||||
return n.methodHandler.head
|
||||
case http.MethodOptions:
|
||||
return n.methodHandler.options
|
||||
case http.MethodPatch:
|
||||
return n.methodHandler.patch
|
||||
case http.MethodPost:
|
||||
return n.methodHandler.post
|
||||
case PROPFIND:
|
||||
return n.methodHandler.propfind
|
||||
case http.MethodPut:
|
||||
return n.methodHandler.put
|
||||
case http.MethodTrace:
|
||||
return n.methodHandler.trace
|
||||
case REPORT:
|
||||
return n.methodHandler.report
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (n *node) checkMethodNotAllowed() HandlerFunc {
|
||||
for _, m := range methods {
|
||||
if h := n.findHandler(m); h != nil {
|
||||
return MethodNotAllowedHandler
|
||||
}
|
||||
}
|
||||
return NotFoundHandler
|
||||
}
|
||||
|
||||
// Find lookup a handler registered for method and path. It also parses URL for path
|
||||
// parameters and load them into context.
|
||||
//
|
||||
// For performance:
|
||||
//
|
||||
// - Get context from `Echo#AcquireContext()`
|
||||
// - Reset it `Context#Reset()`
|
||||
// - Return it `Echo#ReleaseContext()`.
|
||||
func (r *Router) Find(method, path string, c Context) {
|
||||
ctx := c.(*context)
|
||||
ctx.path = path
|
||||
cn := r.tree // Current node as root
|
||||
|
||||
var (
|
||||
search = path
|
||||
child *node // Child node
|
||||
n int // Param counter
|
||||
nk kind // Next kind
|
||||
nn *node // Next node
|
||||
ns string // Next search
|
||||
pvalues = ctx.pvalues // Use the internal slice so the interface can keep the illusion of a dynamic slice
|
||||
)
|
||||
|
||||
// Search order static > param > any
|
||||
for {
|
||||
if search == "" {
|
||||
break
|
||||
}
|
||||
|
||||
pl := 0 // Prefix length
|
||||
l := 0 // LCP length
|
||||
|
||||
if cn.label != ':' {
|
||||
sl := len(search)
|
||||
pl = len(cn.prefix)
|
||||
|
||||
// LCP
|
||||
max := pl
|
||||
if sl < max {
|
||||
max = sl
|
||||
}
|
||||
for ; l < max && search[l] == cn.prefix[l]; l++ {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if l == pl {
|
||||
// Continue search
|
||||
search = search[l:]
|
||||
} else {
|
||||
if nn == nil { // Issue #1348
|
||||
return // Not found
|
||||
}
|
||||
cn = nn
|
||||
search = ns
|
||||
if nk == pkind {
|
||||
goto Param
|
||||
} else if nk == akind {
|
||||
goto Any
|
||||
}
|
||||
}
|
||||
|
||||
if search == "" {
|
||||
break
|
||||
}
|
||||
|
||||
// Static node
|
||||
if child = cn.findChild(search[0], skind); child != nil {
|
||||
// Save next
|
||||
if cn.prefix[len(cn.prefix)-1] == '/' { // Issue #623
|
||||
nk = pkind
|
||||
nn = cn
|
||||
ns = search
|
||||
}
|
||||
cn = child
|
||||
continue
|
||||
}
|
||||
|
||||
// Param node
|
||||
Param:
|
||||
if child = cn.findChildByKind(pkind); child != nil {
|
||||
// Issue #378
|
||||
if len(pvalues) == n {
|
||||
continue
|
||||
}
|
||||
|
||||
// Save next
|
||||
if cn.prefix[len(cn.prefix)-1] == '/' { // Issue #623
|
||||
nk = akind
|
||||
nn = cn
|
||||
ns = search
|
||||
}
|
||||
|
||||
cn = child
|
||||
i, l := 0, len(search)
|
||||
for ; i < l && search[i] != '/'; i++ {
|
||||
}
|
||||
pvalues[n] = search[:i]
|
||||
n++
|
||||
search = search[i:]
|
||||
continue
|
||||
}
|
||||
|
||||
// Any node
|
||||
Any:
|
||||
if cn = cn.findChildByKind(akind); cn == nil {
|
||||
if nn != nil {
|
||||
cn = nn
|
||||
nn = cn.parent // Next (Issue #954)
|
||||
if nn != nil {
|
||||
nk = nn.kind
|
||||
}
|
||||
search = ns
|
||||
if nk == pkind {
|
||||
goto Param
|
||||
} else if nk == akind {
|
||||
goto Any
|
||||
}
|
||||
}
|
||||
return // Not found
|
||||
}
|
||||
pvalues[len(cn.pnames)-1] = search
|
||||
break
|
||||
}
|
||||
|
||||
ctx.handler = cn.findHandler(method)
|
||||
ctx.path = cn.ppath
|
||||
ctx.pnames = cn.pnames
|
||||
|
||||
// NOTE: Slow zone...
|
||||
if ctx.handler == nil {
|
||||
ctx.handler = cn.checkMethodNotAllowed()
|
||||
|
||||
// Dig further for any, might have an empty value for *, e.g.
|
||||
// serving a directory. Issue #207.
|
||||
if cn = cn.findChildByKind(akind); cn == nil {
|
||||
return
|
||||
}
|
||||
if h := cn.findHandler(method); h != nil {
|
||||
ctx.handler = h
|
||||
} else {
|
||||
ctx.handler = cn.checkMethodNotAllowed()
|
||||
}
|
||||
ctx.path = cn.ppath
|
||||
ctx.pnames = cn.pnames
|
||||
pvalues[len(cn.pnames)-1] = ""
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
22
vendor/github.com/labstack/gommon/LICENSE
generated
vendored
Normal file
22
vendor/github.com/labstack/gommon/LICENSE
generated
vendored
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2018 labstack
|
||||
|
||||
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.
|
||||
|
||||
86
vendor/github.com/labstack/gommon/color/README.md
generated
vendored
Normal file
86
vendor/github.com/labstack/gommon/color/README.md
generated
vendored
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
# Color
|
||||
|
||||
Style terminal text.
|
||||
|
||||
## Installation
|
||||
|
||||
```sh
|
||||
go get github.com/labstack/gommon/color
|
||||
```
|
||||
|
||||
## Windows?
|
||||
|
||||
Try [cmder](http://bliker.github.io/cmder) or https://github.com/mattn/go-colorable
|
||||
|
||||
## [Usage](https://github.com/labstack/gommon/blob/master/color/color_test.go)
|
||||
|
||||
```sh
|
||||
import github.com/labstack/gommon/color
|
||||
```
|
||||
|
||||
### Colored text
|
||||
|
||||
```go
|
||||
color.Println(color.Black("black"))
|
||||
color.Println(color.Red("red"))
|
||||
color.Println(color.Green("green"))
|
||||
color.Println(color.Yellow("yellow"))
|
||||
color.Println(color.Blue("blue"))
|
||||
color.Println(color.Magenta("magenta"))
|
||||
color.Println(color.Cyan("cyan"))
|
||||
color.Println(color.White("white"))
|
||||
color.Println(color.Grey("grey"))
|
||||
```
|
||||

|
||||
|
||||
### Colored background
|
||||
|
||||
```go
|
||||
color.Println(color.BlackBg("black background", color.Wht))
|
||||
color.Println(color.RedBg("red background"))
|
||||
color.Println(color.GreenBg("green background"))
|
||||
color.Println(color.YellowBg("yellow background"))
|
||||
color.Println(color.BlueBg("blue background"))
|
||||
color.Println(color.MagentaBg("magenta background"))
|
||||
color.Println(color.CyanBg("cyan background"))
|
||||
color.Println(color.WhiteBg("white background"))
|
||||
```
|
||||

|
||||
|
||||
### Emphasis
|
||||
|
||||
```go
|
||||
color.Println(color.Bold("bold"))
|
||||
color.Println(color.Dim("dim"))
|
||||
color.Println(color.Italic("italic"))
|
||||
color.Println(color.Underline("underline"))
|
||||
color.Println(color.Inverse("inverse"))
|
||||
color.Println(color.Hidden("hidden"))
|
||||
color.Println(color.Strikeout("strikeout"))
|
||||
```
|
||||

|
||||
|
||||
### Mix and match
|
||||
|
||||
```go
|
||||
color.Println(color.Green("bold green with white background", color.B, color.WhtBg))
|
||||
color.Println(color.Red("underline red", color.U))
|
||||
color.Println(color.Yellow("dim yellow", color.D))
|
||||
color.Println(color.Cyan("inverse cyan", color.In))
|
||||
color.Println(color.Blue("bold underline dim blue", color.B, color.U, color.D))
|
||||
```
|
||||

|
||||
|
||||
### Enable/Disable the package
|
||||
|
||||
```go
|
||||
color.Disable()
|
||||
color.Enable()
|
||||
```
|
||||
|
||||
### New instance
|
||||
|
||||
```go
|
||||
c := New()
|
||||
c.Green("green")
|
||||
```
|
||||
407
vendor/github.com/labstack/gommon/color/color.go
generated
vendored
Normal file
407
vendor/github.com/labstack/gommon/color/color.go
generated
vendored
Normal file
|
|
@ -0,0 +1,407 @@
|
|||
package color
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/mattn/go-colorable"
|
||||
"github.com/mattn/go-isatty"
|
||||
)
|
||||
|
||||
type (
|
||||
inner func(interface{}, []string, *Color) string
|
||||
)
|
||||
|
||||
// Color styles
|
||||
const (
|
||||
// Blk Black text style
|
||||
Blk = "30"
|
||||
// Rd red text style
|
||||
Rd = "31"
|
||||
// Grn green text style
|
||||
Grn = "32"
|
||||
// Yel yellow text style
|
||||
Yel = "33"
|
||||
// Blu blue text style
|
||||
Blu = "34"
|
||||
// Mgn magenta text style
|
||||
Mgn = "35"
|
||||
// Cyn cyan text style
|
||||
Cyn = "36"
|
||||
// Wht white text style
|
||||
Wht = "37"
|
||||
// Gry grey text style
|
||||
Gry = "90"
|
||||
|
||||
// BlkBg black background style
|
||||
BlkBg = "40"
|
||||
// RdBg red background style
|
||||
RdBg = "41"
|
||||
// GrnBg green background style
|
||||
GrnBg = "42"
|
||||
// YelBg yellow background style
|
||||
YelBg = "43"
|
||||
// BluBg blue background style
|
||||
BluBg = "44"
|
||||
// MgnBg magenta background style
|
||||
MgnBg = "45"
|
||||
// CynBg cyan background style
|
||||
CynBg = "46"
|
||||
// WhtBg white background style
|
||||
WhtBg = "47"
|
||||
|
||||
// R reset emphasis style
|
||||
R = "0"
|
||||
// B bold emphasis style
|
||||
B = "1"
|
||||
// D dim emphasis style
|
||||
D = "2"
|
||||
// I italic emphasis style
|
||||
I = "3"
|
||||
// U underline emphasis style
|
||||
U = "4"
|
||||
// In inverse emphasis style
|
||||
In = "7"
|
||||
// H hidden emphasis style
|
||||
H = "8"
|
||||
// S strikeout emphasis style
|
||||
S = "9"
|
||||
)
|
||||
|
||||
var (
|
||||
black = outer(Blk)
|
||||
red = outer(Rd)
|
||||
green = outer(Grn)
|
||||
yellow = outer(Yel)
|
||||
blue = outer(Blu)
|
||||
magenta = outer(Mgn)
|
||||
cyan = outer(Cyn)
|
||||
white = outer(Wht)
|
||||
grey = outer(Gry)
|
||||
|
||||
blackBg = outer(BlkBg)
|
||||
redBg = outer(RdBg)
|
||||
greenBg = outer(GrnBg)
|
||||
yellowBg = outer(YelBg)
|
||||
blueBg = outer(BluBg)
|
||||
magentaBg = outer(MgnBg)
|
||||
cyanBg = outer(CynBg)
|
||||
whiteBg = outer(WhtBg)
|
||||
|
||||
reset = outer(R)
|
||||
bold = outer(B)
|
||||
dim = outer(D)
|
||||
italic = outer(I)
|
||||
underline = outer(U)
|
||||
inverse = outer(In)
|
||||
hidden = outer(H)
|
||||
strikeout = outer(S)
|
||||
|
||||
global = New()
|
||||
)
|
||||
|
||||
func outer(n string) inner {
|
||||
return func(msg interface{}, styles []string, c *Color) string {
|
||||
// TODO: Drop fmt to boost performance?
|
||||
if c.disabled {
|
||||
return fmt.Sprintf("%v", msg)
|
||||
}
|
||||
|
||||
b := new(bytes.Buffer)
|
||||
b.WriteString("\x1b[")
|
||||
b.WriteString(n)
|
||||
for _, s := range styles {
|
||||
b.WriteString(";")
|
||||
b.WriteString(s)
|
||||
}
|
||||
b.WriteString("m")
|
||||
return fmt.Sprintf("%s%v\x1b[0m", b.String(), msg)
|
||||
}
|
||||
}
|
||||
|
||||
type (
|
||||
Color struct {
|
||||
output io.Writer
|
||||
disabled bool
|
||||
}
|
||||
)
|
||||
|
||||
// New creates a Color instance.
|
||||
func New() (c *Color) {
|
||||
c = new(Color)
|
||||
c.SetOutput(colorable.NewColorableStdout())
|
||||
return
|
||||
}
|
||||
|
||||
// Output returns the output.
|
||||
func (c *Color) Output() io.Writer {
|
||||
return c.output
|
||||
}
|
||||
|
||||
// SetOutput sets the output.
|
||||
func (c *Color) SetOutput(w io.Writer) {
|
||||
c.output = w
|
||||
if w, ok := w.(*os.File); !ok || !isatty.IsTerminal(w.Fd()) {
|
||||
c.disabled = true
|
||||
}
|
||||
}
|
||||
|
||||
// Disable disables the colors and styles.
|
||||
func (c *Color) Disable() {
|
||||
c.disabled = true
|
||||
}
|
||||
|
||||
// Enable enables the colors and styles.
|
||||
func (c *Color) Enable() {
|
||||
c.disabled = false
|
||||
}
|
||||
|
||||
// Print is analogous to `fmt.Print` with termial detection.
|
||||
func (c *Color) Print(args ...interface{}) {
|
||||
fmt.Fprint(c.output, args...)
|
||||
}
|
||||
|
||||
// Println is analogous to `fmt.Println` with termial detection.
|
||||
func (c *Color) Println(args ...interface{}) {
|
||||
fmt.Fprintln(c.output, args...)
|
||||
}
|
||||
|
||||
// Printf is analogous to `fmt.Printf` with termial detection.
|
||||
func (c *Color) Printf(format string, args ...interface{}) {
|
||||
fmt.Fprintf(c.output, format, args...)
|
||||
}
|
||||
|
||||
func (c *Color) Black(msg interface{}, styles ...string) string {
|
||||
return black(msg, styles, c)
|
||||
}
|
||||
|
||||
func (c *Color) Red(msg interface{}, styles ...string) string {
|
||||
return red(msg, styles, c)
|
||||
}
|
||||
|
||||
func (c *Color) Green(msg interface{}, styles ...string) string {
|
||||
return green(msg, styles, c)
|
||||
}
|
||||
|
||||
func (c *Color) Yellow(msg interface{}, styles ...string) string {
|
||||
return yellow(msg, styles, c)
|
||||
}
|
||||
|
||||
func (c *Color) Blue(msg interface{}, styles ...string) string {
|
||||
return blue(msg, styles, c)
|
||||
}
|
||||
|
||||
func (c *Color) Magenta(msg interface{}, styles ...string) string {
|
||||
return magenta(msg, styles, c)
|
||||
}
|
||||
|
||||
func (c *Color) Cyan(msg interface{}, styles ...string) string {
|
||||
return cyan(msg, styles, c)
|
||||
}
|
||||
|
||||
func (c *Color) White(msg interface{}, styles ...string) string {
|
||||
return white(msg, styles, c)
|
||||
}
|
||||
|
||||
func (c *Color) Grey(msg interface{}, styles ...string) string {
|
||||
return grey(msg, styles, c)
|
||||
}
|
||||
|
||||
func (c *Color) BlackBg(msg interface{}, styles ...string) string {
|
||||
return blackBg(msg, styles, c)
|
||||
}
|
||||
|
||||
func (c *Color) RedBg(msg interface{}, styles ...string) string {
|
||||
return redBg(msg, styles, c)
|
||||
}
|
||||
|
||||
func (c *Color) GreenBg(msg interface{}, styles ...string) string {
|
||||
return greenBg(msg, styles, c)
|
||||
}
|
||||
|
||||
func (c *Color) YellowBg(msg interface{}, styles ...string) string {
|
||||
return yellowBg(msg, styles, c)
|
||||
}
|
||||
|
||||
func (c *Color) BlueBg(msg interface{}, styles ...string) string {
|
||||
return blueBg(msg, styles, c)
|
||||
}
|
||||
|
||||
func (c *Color) MagentaBg(msg interface{}, styles ...string) string {
|
||||
return magentaBg(msg, styles, c)
|
||||
}
|
||||
|
||||
func (c *Color) CyanBg(msg interface{}, styles ...string) string {
|
||||
return cyanBg(msg, styles, c)
|
||||
}
|
||||
|
||||
func (c *Color) WhiteBg(msg interface{}, styles ...string) string {
|
||||
return whiteBg(msg, styles, c)
|
||||
}
|
||||
|
||||
func (c *Color) Reset(msg interface{}, styles ...string) string {
|
||||
return reset(msg, styles, c)
|
||||
}
|
||||
|
||||
func (c *Color) Bold(msg interface{}, styles ...string) string {
|
||||
return bold(msg, styles, c)
|
||||
}
|
||||
|
||||
func (c *Color) Dim(msg interface{}, styles ...string) string {
|
||||
return dim(msg, styles, c)
|
||||
}
|
||||
|
||||
func (c *Color) Italic(msg interface{}, styles ...string) string {
|
||||
return italic(msg, styles, c)
|
||||
}
|
||||
|
||||
func (c *Color) Underline(msg interface{}, styles ...string) string {
|
||||
return underline(msg, styles, c)
|
||||
}
|
||||
|
||||
func (c *Color) Inverse(msg interface{}, styles ...string) string {
|
||||
return inverse(msg, styles, c)
|
||||
}
|
||||
|
||||
func (c *Color) Hidden(msg interface{}, styles ...string) string {
|
||||
return hidden(msg, styles, c)
|
||||
}
|
||||
|
||||
func (c *Color) Strikeout(msg interface{}, styles ...string) string {
|
||||
return strikeout(msg, styles, c)
|
||||
}
|
||||
|
||||
// Output returns the output.
|
||||
func Output() io.Writer {
|
||||
return global.output
|
||||
}
|
||||
|
||||
// SetOutput sets the output.
|
||||
func SetOutput(w io.Writer) {
|
||||
global.SetOutput(w)
|
||||
}
|
||||
|
||||
func Disable() {
|
||||
global.Disable()
|
||||
}
|
||||
|
||||
func Enable() {
|
||||
global.Enable()
|
||||
}
|
||||
|
||||
// Print is analogous to `fmt.Print` with termial detection.
|
||||
func Print(args ...interface{}) {
|
||||
global.Print(args...)
|
||||
}
|
||||
|
||||
// Println is analogous to `fmt.Println` with termial detection.
|
||||
func Println(args ...interface{}) {
|
||||
global.Println(args...)
|
||||
}
|
||||
|
||||
// Printf is analogous to `fmt.Printf` with termial detection.
|
||||
func Printf(format string, args ...interface{}) {
|
||||
global.Printf(format, args...)
|
||||
}
|
||||
|
||||
func Black(msg interface{}, styles ...string) string {
|
||||
return global.Black(msg, styles...)
|
||||
}
|
||||
|
||||
func Red(msg interface{}, styles ...string) string {
|
||||
return global.Red(msg, styles...)
|
||||
}
|
||||
|
||||
func Green(msg interface{}, styles ...string) string {
|
||||
return global.Green(msg, styles...)
|
||||
}
|
||||
|
||||
func Yellow(msg interface{}, styles ...string) string {
|
||||
return global.Yellow(msg, styles...)
|
||||
}
|
||||
|
||||
func Blue(msg interface{}, styles ...string) string {
|
||||
return global.Blue(msg, styles...)
|
||||
}
|
||||
|
||||
func Magenta(msg interface{}, styles ...string) string {
|
||||
return global.Magenta(msg, styles...)
|
||||
}
|
||||
|
||||
func Cyan(msg interface{}, styles ...string) string {
|
||||
return global.Cyan(msg, styles...)
|
||||
}
|
||||
|
||||
func White(msg interface{}, styles ...string) string {
|
||||
return global.White(msg, styles...)
|
||||
}
|
||||
|
||||
func Grey(msg interface{}, styles ...string) string {
|
||||
return global.Grey(msg, styles...)
|
||||
}
|
||||
|
||||
func BlackBg(msg interface{}, styles ...string) string {
|
||||
return global.BlackBg(msg, styles...)
|
||||
}
|
||||
|
||||
func RedBg(msg interface{}, styles ...string) string {
|
||||
return global.RedBg(msg, styles...)
|
||||
}
|
||||
|
||||
func GreenBg(msg interface{}, styles ...string) string {
|
||||
return global.GreenBg(msg, styles...)
|
||||
}
|
||||
|
||||
func YellowBg(msg interface{}, styles ...string) string {
|
||||
return global.YellowBg(msg, styles...)
|
||||
}
|
||||
|
||||
func BlueBg(msg interface{}, styles ...string) string {
|
||||
return global.BlueBg(msg, styles...)
|
||||
}
|
||||
|
||||
func MagentaBg(msg interface{}, styles ...string) string {
|
||||
return global.MagentaBg(msg, styles...)
|
||||
}
|
||||
|
||||
func CyanBg(msg interface{}, styles ...string) string {
|
||||
return global.CyanBg(msg, styles...)
|
||||
}
|
||||
|
||||
func WhiteBg(msg interface{}, styles ...string) string {
|
||||
return global.WhiteBg(msg, styles...)
|
||||
}
|
||||
|
||||
func Reset(msg interface{}, styles ...string) string {
|
||||
return global.Reset(msg, styles...)
|
||||
}
|
||||
|
||||
func Bold(msg interface{}, styles ...string) string {
|
||||
return global.Bold(msg, styles...)
|
||||
}
|
||||
|
||||
func Dim(msg interface{}, styles ...string) string {
|
||||
return global.Dim(msg, styles...)
|
||||
}
|
||||
|
||||
func Italic(msg interface{}, styles ...string) string {
|
||||
return global.Italic(msg, styles...)
|
||||
}
|
||||
|
||||
func Underline(msg interface{}, styles ...string) string {
|
||||
return global.Underline(msg, styles...)
|
||||
}
|
||||
|
||||
func Inverse(msg interface{}, styles ...string) string {
|
||||
return global.Inverse(msg, styles...)
|
||||
}
|
||||
|
||||
func Hidden(msg interface{}, styles ...string) string {
|
||||
return global.Hidden(msg, styles...)
|
||||
}
|
||||
|
||||
func Strikeout(msg interface{}, styles ...string) string {
|
||||
return global.Strikeout(msg, styles...)
|
||||
}
|
||||
5
vendor/github.com/labstack/gommon/log/README.md
generated
vendored
Normal file
5
vendor/github.com/labstack/gommon/log/README.md
generated
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
## WORK IN PROGRESS
|
||||
|
||||
### Usage
|
||||
|
||||
[log_test.go](log_test.go)
|
||||
13
vendor/github.com/labstack/gommon/log/color.go
generated
vendored
Normal file
13
vendor/github.com/labstack/gommon/log/color.go
generated
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
// +build !appengine
|
||||
|
||||
package log
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/mattn/go-colorable"
|
||||
)
|
||||
|
||||
func output() io.Writer {
|
||||
return colorable.NewColorableStdout()
|
||||
}
|
||||
416
vendor/github.com/labstack/gommon/log/log.go
generated
vendored
Normal file
416
vendor/github.com/labstack/gommon/log/log.go
generated
vendored
Normal file
|
|
@ -0,0 +1,416 @@
|
|||
package log
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/mattn/go-isatty"
|
||||
"github.com/valyala/fasttemplate"
|
||||
|
||||
"github.com/labstack/gommon/color"
|
||||
)
|
||||
|
||||
type (
|
||||
Logger struct {
|
||||
prefix string
|
||||
level uint32
|
||||
skip int
|
||||
output io.Writer
|
||||
template *fasttemplate.Template
|
||||
levels []string
|
||||
color *color.Color
|
||||
bufferPool sync.Pool
|
||||
mutex sync.Mutex
|
||||
}
|
||||
|
||||
Lvl uint8
|
||||
|
||||
JSON map[string]interface{}
|
||||
)
|
||||
|
||||
const (
|
||||
DEBUG Lvl = iota + 1
|
||||
INFO
|
||||
WARN
|
||||
ERROR
|
||||
OFF
|
||||
panicLevel
|
||||
fatalLevel
|
||||
)
|
||||
|
||||
var (
|
||||
global = New("-")
|
||||
defaultHeader = `{"time":"${time_rfc3339_nano}","level":"${level}","prefix":"${prefix}",` +
|
||||
`"file":"${short_file}","line":"${line}"}`
|
||||
)
|
||||
|
||||
func init() {
|
||||
global.skip = 3
|
||||
}
|
||||
|
||||
func New(prefix string) (l *Logger) {
|
||||
l = &Logger{
|
||||
level: uint32(INFO),
|
||||
skip: 2,
|
||||
prefix: prefix,
|
||||
template: l.newTemplate(defaultHeader),
|
||||
color: color.New(),
|
||||
bufferPool: sync.Pool{
|
||||
New: func() interface{} {
|
||||
return bytes.NewBuffer(make([]byte, 256))
|
||||
},
|
||||
},
|
||||
}
|
||||
l.initLevels()
|
||||
l.SetOutput(output())
|
||||
return
|
||||
}
|
||||
|
||||
func (l *Logger) initLevels() {
|
||||
l.levels = []string{
|
||||
"-",
|
||||
l.color.Blue("DEBUG"),
|
||||
l.color.Green("INFO"),
|
||||
l.color.Yellow("WARN"),
|
||||
l.color.Red("ERROR"),
|
||||
"",
|
||||
l.color.Yellow("PANIC", color.U),
|
||||
l.color.Red("FATAL", color.U),
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Logger) newTemplate(format string) *fasttemplate.Template {
|
||||
return fasttemplate.New(format, "${", "}")
|
||||
}
|
||||
|
||||
func (l *Logger) DisableColor() {
|
||||
l.color.Disable()
|
||||
l.initLevels()
|
||||
}
|
||||
|
||||
func (l *Logger) EnableColor() {
|
||||
l.color.Enable()
|
||||
l.initLevels()
|
||||
}
|
||||
|
||||
func (l *Logger) Prefix() string {
|
||||
return l.prefix
|
||||
}
|
||||
|
||||
func (l *Logger) SetPrefix(p string) {
|
||||
l.prefix = p
|
||||
}
|
||||
|
||||
func (l *Logger) Level() Lvl {
|
||||
return Lvl(atomic.LoadUint32(&l.level))
|
||||
}
|
||||
|
||||
func (l *Logger) SetLevel(level Lvl) {
|
||||
atomic.StoreUint32(&l.level, uint32(level))
|
||||
}
|
||||
|
||||
func (l *Logger) Output() io.Writer {
|
||||
return l.output
|
||||
}
|
||||
|
||||
func (l *Logger) SetOutput(w io.Writer) {
|
||||
l.output = w
|
||||
if w, ok := w.(*os.File); !ok || !isatty.IsTerminal(w.Fd()) {
|
||||
l.DisableColor()
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Logger) Color() *color.Color {
|
||||
return l.color
|
||||
}
|
||||
|
||||
func (l *Logger) SetHeader(h string) {
|
||||
l.template = l.newTemplate(h)
|
||||
}
|
||||
|
||||
func (l *Logger) Print(i ...interface{}) {
|
||||
l.log(0, "", i...)
|
||||
// fmt.Fprintln(l.output, i...)
|
||||
}
|
||||
|
||||
func (l *Logger) Printf(format string, args ...interface{}) {
|
||||
l.log(0, format, args...)
|
||||
}
|
||||
|
||||
func (l *Logger) Printj(j JSON) {
|
||||
l.log(0, "json", j)
|
||||
}
|
||||
|
||||
func (l *Logger) Debug(i ...interface{}) {
|
||||
l.log(DEBUG, "", i...)
|
||||
}
|
||||
|
||||
func (l *Logger) Debugf(format string, args ...interface{}) {
|
||||
l.log(DEBUG, format, args...)
|
||||
}
|
||||
|
||||
func (l *Logger) Debugj(j JSON) {
|
||||
l.log(DEBUG, "json", j)
|
||||
}
|
||||
|
||||
func (l *Logger) Info(i ...interface{}) {
|
||||
l.log(INFO, "", i...)
|
||||
}
|
||||
|
||||
func (l *Logger) Infof(format string, args ...interface{}) {
|
||||
l.log(INFO, format, args...)
|
||||
}
|
||||
|
||||
func (l *Logger) Infoj(j JSON) {
|
||||
l.log(INFO, "json", j)
|
||||
}
|
||||
|
||||
func (l *Logger) Warn(i ...interface{}) {
|
||||
l.log(WARN, "", i...)
|
||||
}
|
||||
|
||||
func (l *Logger) Warnf(format string, args ...interface{}) {
|
||||
l.log(WARN, format, args...)
|
||||
}
|
||||
|
||||
func (l *Logger) Warnj(j JSON) {
|
||||
l.log(WARN, "json", j)
|
||||
}
|
||||
|
||||
func (l *Logger) Error(i ...interface{}) {
|
||||
l.log(ERROR, "", i...)
|
||||
}
|
||||
|
||||
func (l *Logger) Errorf(format string, args ...interface{}) {
|
||||
l.log(ERROR, format, args...)
|
||||
}
|
||||
|
||||
func (l *Logger) Errorj(j JSON) {
|
||||
l.log(ERROR, "json", j)
|
||||
}
|
||||
|
||||
func (l *Logger) Fatal(i ...interface{}) {
|
||||
l.log(fatalLevel, "", i...)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func (l *Logger) Fatalf(format string, args ...interface{}) {
|
||||
l.log(fatalLevel, format, args...)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func (l *Logger) Fatalj(j JSON) {
|
||||
l.log(fatalLevel, "json", j)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func (l *Logger) Panic(i ...interface{}) {
|
||||
l.log(panicLevel, "", i...)
|
||||
panic(fmt.Sprint(i...))
|
||||
}
|
||||
|
||||
func (l *Logger) Panicf(format string, args ...interface{}) {
|
||||
l.log(panicLevel, format, args...)
|
||||
panic(fmt.Sprintf(format, args...))
|
||||
}
|
||||
|
||||
func (l *Logger) Panicj(j JSON) {
|
||||
l.log(panicLevel, "json", j)
|
||||
panic(j)
|
||||
}
|
||||
|
||||
func DisableColor() {
|
||||
global.DisableColor()
|
||||
}
|
||||
|
||||
func EnableColor() {
|
||||
global.EnableColor()
|
||||
}
|
||||
|
||||
func Prefix() string {
|
||||
return global.Prefix()
|
||||
}
|
||||
|
||||
func SetPrefix(p string) {
|
||||
global.SetPrefix(p)
|
||||
}
|
||||
|
||||
func Level() Lvl {
|
||||
return global.Level()
|
||||
}
|
||||
|
||||
func SetLevel(level Lvl) {
|
||||
global.SetLevel(level)
|
||||
}
|
||||
|
||||
func Output() io.Writer {
|
||||
return global.Output()
|
||||
}
|
||||
|
||||
func SetOutput(w io.Writer) {
|
||||
global.SetOutput(w)
|
||||
}
|
||||
|
||||
func SetHeader(h string) {
|
||||
global.SetHeader(h)
|
||||
}
|
||||
|
||||
func Print(i ...interface{}) {
|
||||
global.Print(i...)
|
||||
}
|
||||
|
||||
func Printf(format string, args ...interface{}) {
|
||||
global.Printf(format, args...)
|
||||
}
|
||||
|
||||
func Printj(j JSON) {
|
||||
global.Printj(j)
|
||||
}
|
||||
|
||||
func Debug(i ...interface{}) {
|
||||
global.Debug(i...)
|
||||
}
|
||||
|
||||
func Debugf(format string, args ...interface{}) {
|
||||
global.Debugf(format, args...)
|
||||
}
|
||||
|
||||
func Debugj(j JSON) {
|
||||
global.Debugj(j)
|
||||
}
|
||||
|
||||
func Info(i ...interface{}) {
|
||||
global.Info(i...)
|
||||
}
|
||||
|
||||
func Infof(format string, args ...interface{}) {
|
||||
global.Infof(format, args...)
|
||||
}
|
||||
|
||||
func Infoj(j JSON) {
|
||||
global.Infoj(j)
|
||||
}
|
||||
|
||||
func Warn(i ...interface{}) {
|
||||
global.Warn(i...)
|
||||
}
|
||||
|
||||
func Warnf(format string, args ...interface{}) {
|
||||
global.Warnf(format, args...)
|
||||
}
|
||||
|
||||
func Warnj(j JSON) {
|
||||
global.Warnj(j)
|
||||
}
|
||||
|
||||
func Error(i ...interface{}) {
|
||||
global.Error(i...)
|
||||
}
|
||||
|
||||
func Errorf(format string, args ...interface{}) {
|
||||
global.Errorf(format, args...)
|
||||
}
|
||||
|
||||
func Errorj(j JSON) {
|
||||
global.Errorj(j)
|
||||
}
|
||||
|
||||
func Fatal(i ...interface{}) {
|
||||
global.Fatal(i...)
|
||||
}
|
||||
|
||||
func Fatalf(format string, args ...interface{}) {
|
||||
global.Fatalf(format, args...)
|
||||
}
|
||||
|
||||
func Fatalj(j JSON) {
|
||||
global.Fatalj(j)
|
||||
}
|
||||
|
||||
func Panic(i ...interface{}) {
|
||||
global.Panic(i...)
|
||||
}
|
||||
|
||||
func Panicf(format string, args ...interface{}) {
|
||||
global.Panicf(format, args...)
|
||||
}
|
||||
|
||||
func Panicj(j JSON) {
|
||||
global.Panicj(j)
|
||||
}
|
||||
|
||||
func (l *Logger) log(level Lvl, format string, args ...interface{}) {
|
||||
if level >= l.Level() || level == 0 {
|
||||
buf := l.bufferPool.Get().(*bytes.Buffer)
|
||||
buf.Reset()
|
||||
defer l.bufferPool.Put(buf)
|
||||
_, file, line, _ := runtime.Caller(l.skip)
|
||||
message := ""
|
||||
|
||||
if format == "" {
|
||||
message = fmt.Sprint(args...)
|
||||
} else if format == "json" {
|
||||
b, err := json.Marshal(args[0])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
message = string(b)
|
||||
} else {
|
||||
message = fmt.Sprintf(format, args...)
|
||||
}
|
||||
|
||||
_, err := l.template.ExecuteFunc(buf, func(w io.Writer, tag string) (int, error) {
|
||||
switch tag {
|
||||
case "time_rfc3339":
|
||||
return w.Write([]byte(time.Now().Format(time.RFC3339)))
|
||||
case "time_rfc3339_nano":
|
||||
return w.Write([]byte(time.Now().Format(time.RFC3339Nano)))
|
||||
case "level":
|
||||
return w.Write([]byte(l.levels[level]))
|
||||
case "prefix":
|
||||
return w.Write([]byte(l.prefix))
|
||||
case "long_file":
|
||||
return w.Write([]byte(file))
|
||||
case "short_file":
|
||||
return w.Write([]byte(path.Base(file)))
|
||||
case "line":
|
||||
return w.Write([]byte(strconv.Itoa(line)))
|
||||
}
|
||||
return 0, nil
|
||||
})
|
||||
|
||||
if err == nil {
|
||||
s := buf.String()
|
||||
i := buf.Len() - 1
|
||||
if s[i] == '}' {
|
||||
// JSON header
|
||||
buf.Truncate(i)
|
||||
buf.WriteByte(',')
|
||||
if format == "json" {
|
||||
buf.WriteString(message[1:])
|
||||
} else {
|
||||
buf.WriteString(`"message":`)
|
||||
buf.WriteString(strconv.Quote(message))
|
||||
buf.WriteString(`}`)
|
||||
}
|
||||
} else {
|
||||
// Text header
|
||||
buf.WriteByte(' ')
|
||||
buf.WriteString(message)
|
||||
}
|
||||
buf.WriteByte('\n')
|
||||
l.mutex.Lock()
|
||||
defer l.mutex.Unlock()
|
||||
l.output.Write(buf.Bytes())
|
||||
}
|
||||
}
|
||||
}
|
||||
12
vendor/github.com/labstack/gommon/log/white.go
generated
vendored
Normal file
12
vendor/github.com/labstack/gommon/log/white.go
generated
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
// +build appengine
|
||||
|
||||
package log
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
func output() io.Writer {
|
||||
return os.Stdout
|
||||
}
|
||||
9
vendor/github.com/mattn/go-colorable/.travis.yml
generated
vendored
Normal file
9
vendor/github.com/mattn/go-colorable/.travis.yml
generated
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
language: go
|
||||
go:
|
||||
- tip
|
||||
|
||||
before_install:
|
||||
- go get github.com/mattn/goveralls
|
||||
- go get golang.org/x/tools/cmd/cover
|
||||
script:
|
||||
- $HOME/gopath/bin/goveralls -repotoken xnXqRGwgW3SXIguzxf90ZSK1GPYZPaGrw
|
||||
21
vendor/github.com/mattn/go-colorable/LICENSE
generated
vendored
Normal file
21
vendor/github.com/mattn/go-colorable/LICENSE
generated
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Yasuhiro Matsumoto
|
||||
|
||||
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.
|
||||
48
vendor/github.com/mattn/go-colorable/README.md
generated
vendored
Normal file
48
vendor/github.com/mattn/go-colorable/README.md
generated
vendored
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
# go-colorable
|
||||
|
||||
[](http://godoc.org/github.com/mattn/go-colorable)
|
||||
[](https://travis-ci.org/mattn/go-colorable)
|
||||
[](https://coveralls.io/github/mattn/go-colorable?branch=master)
|
||||
[](https://goreportcard.com/report/mattn/go-colorable)
|
||||
|
||||
Colorable writer for windows.
|
||||
|
||||
For example, most of logger packages doesn't show colors on windows. (I know we can do it with ansicon. But I don't want.)
|
||||
This package is possible to handle escape sequence for ansi color on windows.
|
||||
|
||||
## Too Bad!
|
||||
|
||||

|
||||
|
||||
|
||||
## So Good!
|
||||
|
||||

|
||||
|
||||
## Usage
|
||||
|
||||
```go
|
||||
logrus.SetFormatter(&logrus.TextFormatter{ForceColors: true})
|
||||
logrus.SetOutput(colorable.NewColorableStdout())
|
||||
|
||||
logrus.Info("succeeded")
|
||||
logrus.Warn("not correct")
|
||||
logrus.Error("something error")
|
||||
logrus.Fatal("panic")
|
||||
```
|
||||
|
||||
You can compile above code on non-windows OSs.
|
||||
|
||||
## Installation
|
||||
|
||||
```
|
||||
$ go get github.com/mattn/go-colorable
|
||||
```
|
||||
|
||||
# License
|
||||
|
||||
MIT
|
||||
|
||||
# Author
|
||||
|
||||
Yasuhiro Matsumoto (a.k.a mattn)
|
||||
29
vendor/github.com/mattn/go-colorable/colorable_appengine.go
generated
vendored
Normal file
29
vendor/github.com/mattn/go-colorable/colorable_appengine.go
generated
vendored
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
// +build appengine
|
||||
|
||||
package colorable
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
|
||||
_ "github.com/mattn/go-isatty"
|
||||
)
|
||||
|
||||
// NewColorable returns new instance of Writer which handles escape sequence.
|
||||
func NewColorable(file *os.File) io.Writer {
|
||||
if file == nil {
|
||||
panic("nil passed instead of *os.File to NewColorable()")
|
||||
}
|
||||
|
||||
return file
|
||||
}
|
||||
|
||||
// NewColorableStdout returns new instance of Writer which handles escape sequence for stdout.
|
||||
func NewColorableStdout() io.Writer {
|
||||
return os.Stdout
|
||||
}
|
||||
|
||||
// NewColorableStderr returns new instance of Writer which handles escape sequence for stderr.
|
||||
func NewColorableStderr() io.Writer {
|
||||
return os.Stderr
|
||||
}
|
||||
30
vendor/github.com/mattn/go-colorable/colorable_others.go
generated
vendored
Normal file
30
vendor/github.com/mattn/go-colorable/colorable_others.go
generated
vendored
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
// +build !windows
|
||||
// +build !appengine
|
||||
|
||||
package colorable
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
|
||||
_ "github.com/mattn/go-isatty"
|
||||
)
|
||||
|
||||
// NewColorable returns new instance of Writer which handles escape sequence.
|
||||
func NewColorable(file *os.File) io.Writer {
|
||||
if file == nil {
|
||||
panic("nil passed instead of *os.File to NewColorable()")
|
||||
}
|
||||
|
||||
return file
|
||||
}
|
||||
|
||||
// NewColorableStdout returns new instance of Writer which handles escape sequence for stdout.
|
||||
func NewColorableStdout() io.Writer {
|
||||
return os.Stdout
|
||||
}
|
||||
|
||||
// NewColorableStderr returns new instance of Writer which handles escape sequence for stderr.
|
||||
func NewColorableStderr() io.Writer {
|
||||
return os.Stderr
|
||||
}
|
||||
1005
vendor/github.com/mattn/go-colorable/colorable_windows.go
generated
vendored
Normal file
1005
vendor/github.com/mattn/go-colorable/colorable_windows.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
3
vendor/github.com/mattn/go-colorable/go.mod
generated
vendored
Normal file
3
vendor/github.com/mattn/go-colorable/go.mod
generated
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
module github.com/mattn/go-colorable
|
||||
|
||||
require github.com/mattn/go-isatty v0.0.8
|
||||
4
vendor/github.com/mattn/go-colorable/go.sum
generated
vendored
Normal file
4
vendor/github.com/mattn/go-colorable/go.sum
generated
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
github.com/mattn/go-isatty v0.0.5 h1:tHXDdz1cpzGaovsTB+TVB8q90WEokoVmfMqoVcrLUgw=
|
||||
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
55
vendor/github.com/mattn/go-colorable/noncolorable.go
generated
vendored
Normal file
55
vendor/github.com/mattn/go-colorable/noncolorable.go
generated
vendored
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
package colorable
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
)
|
||||
|
||||
// NonColorable holds writer but removes escape sequence.
|
||||
type NonColorable struct {
|
||||
out io.Writer
|
||||
}
|
||||
|
||||
// NewNonColorable returns new instance of Writer which removes escape sequence from Writer.
|
||||
func NewNonColorable(w io.Writer) io.Writer {
|
||||
return &NonColorable{out: w}
|
||||
}
|
||||
|
||||
// Write writes data on console
|
||||
func (w *NonColorable) Write(data []byte) (n int, err error) {
|
||||
er := bytes.NewReader(data)
|
||||
var bw [1]byte
|
||||
loop:
|
||||
for {
|
||||
c1, err := er.ReadByte()
|
||||
if err != nil {
|
||||
break loop
|
||||
}
|
||||
if c1 != 0x1b {
|
||||
bw[0] = c1
|
||||
w.out.Write(bw[:])
|
||||
continue
|
||||
}
|
||||
c2, err := er.ReadByte()
|
||||
if err != nil {
|
||||
break loop
|
||||
}
|
||||
if c2 != 0x5b {
|
||||
continue
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
for {
|
||||
c, err := er.ReadByte()
|
||||
if err != nil {
|
||||
break loop
|
||||
}
|
||||
if ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '@' {
|
||||
break
|
||||
}
|
||||
buf.Write([]byte(string(c)))
|
||||
}
|
||||
}
|
||||
|
||||
return len(data), nil
|
||||
}
|
||||
13
vendor/github.com/mattn/go-isatty/.travis.yml
generated
vendored
Normal file
13
vendor/github.com/mattn/go-isatty/.travis.yml
generated
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
language: go
|
||||
go:
|
||||
- tip
|
||||
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
|
||||
before_install:
|
||||
- go get github.com/mattn/goveralls
|
||||
- go get golang.org/x/tools/cmd/cover
|
||||
script:
|
||||
- $HOME/gopath/bin/goveralls -repotoken 3gHdORO5k5ziZcWMBxnd9LrMZaJs8m9x5
|
||||
9
vendor/github.com/mattn/go-isatty/LICENSE
generated
vendored
Normal file
9
vendor/github.com/mattn/go-isatty/LICENSE
generated
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
Copyright (c) Yasuhiro MATSUMOTO <mattn.jp@gmail.com>
|
||||
|
||||
MIT License (Expat)
|
||||
|
||||
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.
|
||||
50
vendor/github.com/mattn/go-isatty/README.md
generated
vendored
Normal file
50
vendor/github.com/mattn/go-isatty/README.md
generated
vendored
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
# go-isatty
|
||||
|
||||
[](http://godoc.org/github.com/mattn/go-isatty)
|
||||
[](https://travis-ci.org/mattn/go-isatty)
|
||||
[](https://coveralls.io/github/mattn/go-isatty?branch=master)
|
||||
[](https://goreportcard.com/report/mattn/go-isatty)
|
||||
|
||||
isatty for golang
|
||||
|
||||
## Usage
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/mattn/go-isatty"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
if isatty.IsTerminal(os.Stdout.Fd()) {
|
||||
fmt.Println("Is Terminal")
|
||||
} else if isatty.IsCygwinTerminal(os.Stdout.Fd()) {
|
||||
fmt.Println("Is Cygwin/MSYS2 Terminal")
|
||||
} else {
|
||||
fmt.Println("Is Not Terminal")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Installation
|
||||
|
||||
```
|
||||
$ go get github.com/mattn/go-isatty
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
|
||||
## Author
|
||||
|
||||
Yasuhiro Matsumoto (a.k.a mattn)
|
||||
|
||||
## Thanks
|
||||
|
||||
* k-takata: base idea for IsCygwinTerminal
|
||||
|
||||
https://github.com/k-takata/go-iscygpty
|
||||
2
vendor/github.com/mattn/go-isatty/doc.go
generated
vendored
Normal file
2
vendor/github.com/mattn/go-isatty/doc.go
generated
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
// Package isatty implements interface to isatty
|
||||
package isatty
|
||||
5
vendor/github.com/mattn/go-isatty/go.mod
generated
vendored
Normal file
5
vendor/github.com/mattn/go-isatty/go.mod
generated
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
module github.com/mattn/go-isatty
|
||||
|
||||
require golang.org/x/sys v0.0.0-20191008105621-543471e840be
|
||||
|
||||
go 1.14
|
||||
4
vendor/github.com/mattn/go-isatty/go.sum
generated
vendored
Normal file
4
vendor/github.com/mattn/go-isatty/go.sum
generated
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ=
|
||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be h1:QAcqgptGM8IQBC9K/RC4o+O9YmqEm0diQn9QmZw/0mU=
|
||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
23
vendor/github.com/mattn/go-isatty/isatty_android.go
generated
vendored
Normal file
23
vendor/github.com/mattn/go-isatty/isatty_android.go
generated
vendored
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
// +build android
|
||||
|
||||
package isatty
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const ioctlReadTermios = syscall.TCGETS
|
||||
|
||||
// IsTerminal return true if the file descriptor is terminal.
|
||||
func IsTerminal(fd uintptr) bool {
|
||||
var termios syscall.Termios
|
||||
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
|
||||
return err == 0
|
||||
}
|
||||
|
||||
// IsCygwinTerminal return true if the file descriptor is a cygwin or msys2
|
||||
// terminal. This is also always false on this environment.
|
||||
func IsCygwinTerminal(fd uintptr) bool {
|
||||
return false
|
||||
}
|
||||
24
vendor/github.com/mattn/go-isatty/isatty_bsd.go
generated
vendored
Normal file
24
vendor/github.com/mattn/go-isatty/isatty_bsd.go
generated
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
// +build darwin freebsd openbsd netbsd dragonfly
|
||||
// +build !appengine
|
||||
|
||||
package isatty
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const ioctlReadTermios = syscall.TIOCGETA
|
||||
|
||||
// IsTerminal return true if the file descriptor is terminal.
|
||||
func IsTerminal(fd uintptr) bool {
|
||||
var termios syscall.Termios
|
||||
_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
|
||||
return err == 0
|
||||
}
|
||||
|
||||
// IsCygwinTerminal return true if the file descriptor is a cygwin or msys2
|
||||
// terminal. This is also always false on this environment.
|
||||
func IsCygwinTerminal(fd uintptr) bool {
|
||||
return false
|
||||
}
|
||||
15
vendor/github.com/mattn/go-isatty/isatty_others.go
generated
vendored
Normal file
15
vendor/github.com/mattn/go-isatty/isatty_others.go
generated
vendored
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
// +build appengine js nacl
|
||||
|
||||
package isatty
|
||||
|
||||
// IsTerminal returns true if the file descriptor is terminal which
|
||||
// is always false on js and appengine classic which is a sandboxed PaaS.
|
||||
func IsTerminal(fd uintptr) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsCygwinTerminal() return true if the file descriptor is a cygwin or msys2
|
||||
// terminal. This is also always false on this environment.
|
||||
func IsCygwinTerminal(fd uintptr) bool {
|
||||
return false
|
||||
}
|
||||
22
vendor/github.com/mattn/go-isatty/isatty_plan9.go
generated
vendored
Normal file
22
vendor/github.com/mattn/go-isatty/isatty_plan9.go
generated
vendored
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
// +build plan9
|
||||
|
||||
package isatty
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// IsTerminal returns true if the given file descriptor is a terminal.
|
||||
func IsTerminal(fd uintptr) bool {
|
||||
path, err := syscall.Fd2path(fd)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return path == "/dev/cons" || path == "/mnt/term/dev/cons"
|
||||
}
|
||||
|
||||
// IsCygwinTerminal return true if the file descriptor is a cygwin or msys2
|
||||
// terminal. This is also always false on this environment.
|
||||
func IsCygwinTerminal(fd uintptr) bool {
|
||||
return false
|
||||
}
|
||||
22
vendor/github.com/mattn/go-isatty/isatty_solaris.go
generated
vendored
Normal file
22
vendor/github.com/mattn/go-isatty/isatty_solaris.go
generated
vendored
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
// +build solaris
|
||||
// +build !appengine
|
||||
|
||||
package isatty
|
||||
|
||||
import (
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// IsTerminal returns true if the given file descriptor is a terminal.
|
||||
// see: http://src.illumos.org/source/xref/illumos-gate/usr/src/lib/libbc/libc/gen/common/isatty.c
|
||||
func IsTerminal(fd uintptr) bool {
|
||||
var termio unix.Termio
|
||||
err := unix.IoctlSetTermio(int(fd), unix.TCGETA, &termio)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// IsCygwinTerminal return true if the file descriptor is a cygwin or msys2
|
||||
// terminal. This is also always false on this environment.
|
||||
func IsCygwinTerminal(fd uintptr) bool {
|
||||
return false
|
||||
}
|
||||
19
vendor/github.com/mattn/go-isatty/isatty_tcgets.go
generated
vendored
Normal file
19
vendor/github.com/mattn/go-isatty/isatty_tcgets.go
generated
vendored
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
// +build linux aix
|
||||
// +build !appengine
|
||||
// +build !android
|
||||
|
||||
package isatty
|
||||
|
||||
import "golang.org/x/sys/unix"
|
||||
|
||||
// IsTerminal return true if the file descriptor is terminal.
|
||||
func IsTerminal(fd uintptr) bool {
|
||||
_, err := unix.IoctlGetTermios(int(fd), unix.TCGETS)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// IsCygwinTerminal return true if the file descriptor is a cygwin or msys2
|
||||
// terminal. This is also always false on this environment.
|
||||
func IsCygwinTerminal(fd uintptr) bool {
|
||||
return false
|
||||
}
|
||||
125
vendor/github.com/mattn/go-isatty/isatty_windows.go
generated
vendored
Normal file
125
vendor/github.com/mattn/go-isatty/isatty_windows.go
generated
vendored
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
// +build windows
|
||||
// +build !appengine
|
||||
|
||||
package isatty
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
"syscall"
|
||||
"unicode/utf16"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
objectNameInfo uintptr = 1
|
||||
fileNameInfo = 2
|
||||
fileTypePipe = 3
|
||||
)
|
||||
|
||||
var (
|
||||
kernel32 = syscall.NewLazyDLL("kernel32.dll")
|
||||
ntdll = syscall.NewLazyDLL("ntdll.dll")
|
||||
procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
|
||||
procGetFileInformationByHandleEx = kernel32.NewProc("GetFileInformationByHandleEx")
|
||||
procGetFileType = kernel32.NewProc("GetFileType")
|
||||
procNtQueryObject = ntdll.NewProc("NtQueryObject")
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Check if GetFileInformationByHandleEx is available.
|
||||
if procGetFileInformationByHandleEx.Find() != nil {
|
||||
procGetFileInformationByHandleEx = nil
|
||||
}
|
||||
}
|
||||
|
||||
// IsTerminal return true if the file descriptor is terminal.
|
||||
func IsTerminal(fd uintptr) bool {
|
||||
var st uint32
|
||||
r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, fd, uintptr(unsafe.Pointer(&st)), 0)
|
||||
return r != 0 && e == 0
|
||||
}
|
||||
|
||||
// Check pipe name is used for cygwin/msys2 pty.
|
||||
// Cygwin/MSYS2 PTY has a name like:
|
||||
// \{cygwin,msys}-XXXXXXXXXXXXXXXX-ptyN-{from,to}-master
|
||||
func isCygwinPipeName(name string) bool {
|
||||
token := strings.Split(name, "-")
|
||||
if len(token) < 5 {
|
||||
return false
|
||||
}
|
||||
|
||||
if token[0] != `\msys` &&
|
||||
token[0] != `\cygwin` &&
|
||||
token[0] != `\Device\NamedPipe\msys` &&
|
||||
token[0] != `\Device\NamedPipe\cygwin` {
|
||||
return false
|
||||
}
|
||||
|
||||
if token[1] == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(token[2], "pty") {
|
||||
return false
|
||||
}
|
||||
|
||||
if token[3] != `from` && token[3] != `to` {
|
||||
return false
|
||||
}
|
||||
|
||||
if token[4] != "master" {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// getFileNameByHandle use the undocomented ntdll NtQueryObject to get file full name from file handler
|
||||
// since GetFileInformationByHandleEx is not avilable under windows Vista and still some old fashion
|
||||
// guys are using Windows XP, this is a workaround for those guys, it will also work on system from
|
||||
// Windows vista to 10
|
||||
// see https://stackoverflow.com/a/18792477 for details
|
||||
func getFileNameByHandle(fd uintptr) (string, error) {
|
||||
if procNtQueryObject == nil {
|
||||
return "", errors.New("ntdll.dll: NtQueryObject not supported")
|
||||
}
|
||||
|
||||
var buf [4 + syscall.MAX_PATH]uint16
|
||||
var result int
|
||||
r, _, e := syscall.Syscall6(procNtQueryObject.Addr(), 5,
|
||||
fd, objectNameInfo, uintptr(unsafe.Pointer(&buf)), uintptr(2*len(buf)), uintptr(unsafe.Pointer(&result)), 0)
|
||||
if r != 0 {
|
||||
return "", e
|
||||
}
|
||||
return string(utf16.Decode(buf[4 : 4+buf[0]/2])), nil
|
||||
}
|
||||
|
||||
// IsCygwinTerminal() return true if the file descriptor is a cygwin or msys2
|
||||
// terminal.
|
||||
func IsCygwinTerminal(fd uintptr) bool {
|
||||
if procGetFileInformationByHandleEx == nil {
|
||||
name, err := getFileNameByHandle(fd)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return isCygwinPipeName(name)
|
||||
}
|
||||
|
||||
// Cygwin/msys's pty is a pipe.
|
||||
ft, _, e := syscall.Syscall(procGetFileType.Addr(), 1, fd, 0, 0)
|
||||
if ft != fileTypePipe || e != 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
var buf [2 + syscall.MAX_PATH]uint16
|
||||
r, _, e := syscall.Syscall6(procGetFileInformationByHandleEx.Addr(),
|
||||
4, fd, fileNameInfo, uintptr(unsafe.Pointer(&buf)),
|
||||
uintptr(len(buf)*2), 0, 0)
|
||||
if r == 0 || e != 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
l := *(*uint32)(unsafe.Pointer(&buf))
|
||||
return isCygwinPipeName(string(utf16.Decode(buf[2 : 2+l/2])))
|
||||
}
|
||||
24
vendor/github.com/pkg/errors/.gitignore
generated
vendored
Normal file
24
vendor/github.com/pkg/errors/.gitignore
generated
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
|
||||
# Folders
|
||||
_obj
|
||||
_test
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
[568vq].out
|
||||
|
||||
*.cgo1.go
|
||||
*.cgo2.c
|
||||
_cgo_defun.c
|
||||
_cgo_gotypes.go
|
||||
_cgo_export.*
|
||||
|
||||
_testmain.go
|
||||
|
||||
*.exe
|
||||
*.test
|
||||
*.prof
|
||||
10
vendor/github.com/pkg/errors/.travis.yml
generated
vendored
Normal file
10
vendor/github.com/pkg/errors/.travis.yml
generated
vendored
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
language: go
|
||||
go_import_path: github.com/pkg/errors
|
||||
go:
|
||||
- 1.11.x
|
||||
- 1.12.x
|
||||
- 1.13.x
|
||||
- tip
|
||||
|
||||
script:
|
||||
- make check
|
||||
23
vendor/github.com/pkg/errors/LICENSE
generated
vendored
Normal file
23
vendor/github.com/pkg/errors/LICENSE
generated
vendored
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
Copyright (c) 2015, Dave Cheney <dave@cheney.net>
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* 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.
|
||||
|
||||
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 HOLDER 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.
|
||||
44
vendor/github.com/pkg/errors/Makefile
generated
vendored
Normal file
44
vendor/github.com/pkg/errors/Makefile
generated
vendored
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
PKGS := github.com/pkg/errors
|
||||
SRCDIRS := $(shell go list -f '{{.Dir}}' $(PKGS))
|
||||
GO := go
|
||||
|
||||
check: test vet gofmt misspell unconvert staticcheck ineffassign unparam
|
||||
|
||||
test:
|
||||
$(GO) test $(PKGS)
|
||||
|
||||
vet: | test
|
||||
$(GO) vet $(PKGS)
|
||||
|
||||
staticcheck:
|
||||
$(GO) get honnef.co/go/tools/cmd/staticcheck
|
||||
staticcheck -checks all $(PKGS)
|
||||
|
||||
misspell:
|
||||
$(GO) get github.com/client9/misspell/cmd/misspell
|
||||
misspell \
|
||||
-locale GB \
|
||||
-error \
|
||||
*.md *.go
|
||||
|
||||
unconvert:
|
||||
$(GO) get github.com/mdempsky/unconvert
|
||||
unconvert -v $(PKGS)
|
||||
|
||||
ineffassign:
|
||||
$(GO) get github.com/gordonklaus/ineffassign
|
||||
find $(SRCDIRS) -name '*.go' | xargs ineffassign
|
||||
|
||||
pedantic: check errcheck
|
||||
|
||||
unparam:
|
||||
$(GO) get mvdan.cc/unparam
|
||||
unparam ./...
|
||||
|
||||
errcheck:
|
||||
$(GO) get github.com/kisielk/errcheck
|
||||
errcheck $(PKGS)
|
||||
|
||||
gofmt:
|
||||
@echo Checking code is gofmted
|
||||
@test -z "$(shell gofmt -s -l -d -e $(SRCDIRS) | tee /dev/stderr)"
|
||||
59
vendor/github.com/pkg/errors/README.md
generated
vendored
Normal file
59
vendor/github.com/pkg/errors/README.md
generated
vendored
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
# errors [](https://travis-ci.org/pkg/errors) [](https://ci.appveyor.com/project/davecheney/errors/branch/master) [](http://godoc.org/github.com/pkg/errors) [](https://goreportcard.com/report/github.com/pkg/errors) [](https://sourcegraph.com/github.com/pkg/errors?badge)
|
||||
|
||||
Package errors provides simple error handling primitives.
|
||||
|
||||
`go get github.com/pkg/errors`
|
||||
|
||||
The traditional error handling idiom in Go is roughly akin to
|
||||
```go
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
```
|
||||
which applied recursively up the call stack results in error reports without context or debugging information. The errors package allows programmers to add context to the failure path in their code in a way that does not destroy the original value of the error.
|
||||
|
||||
## Adding context to an error
|
||||
|
||||
The errors.Wrap function returns a new error that adds context to the original error. For example
|
||||
```go
|
||||
_, err := ioutil.ReadAll(r)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "read failed")
|
||||
}
|
||||
```
|
||||
## Retrieving the cause of an error
|
||||
|
||||
Using `errors.Wrap` constructs a stack of errors, adding context to the preceding error. Depending on the nature of the error it may be necessary to reverse the operation of errors.Wrap to retrieve the original error for inspection. Any error value which implements this interface can be inspected by `errors.Cause`.
|
||||
```go
|
||||
type causer interface {
|
||||
Cause() error
|
||||
}
|
||||
```
|
||||
`errors.Cause` will recursively retrieve the topmost error which does not implement `causer`, which is assumed to be the original cause. For example:
|
||||
```go
|
||||
switch err := errors.Cause(err).(type) {
|
||||
case *MyError:
|
||||
// handle specifically
|
||||
default:
|
||||
// unknown error
|
||||
}
|
||||
```
|
||||
|
||||
[Read the package documentation for more information](https://godoc.org/github.com/pkg/errors).
|
||||
|
||||
## Roadmap
|
||||
|
||||
With the upcoming [Go2 error proposals](https://go.googlesource.com/proposal/+/master/design/go2draft.md) this package is moving into maintenance mode. The roadmap for a 1.0 release is as follows:
|
||||
|
||||
- 0.9. Remove pre Go 1.9 and Go 1.10 support, address outstanding pull requests (if possible)
|
||||
- 1.0. Final release.
|
||||
|
||||
## Contributing
|
||||
|
||||
Because of the Go2 errors changes, this package is not accepting proposals for new functionality. With that said, we welcome pull requests, bug fixes and issue reports.
|
||||
|
||||
Before sending a PR, please discuss your change by raising an issue.
|
||||
|
||||
## License
|
||||
|
||||
BSD-2-Clause
|
||||
32
vendor/github.com/pkg/errors/appveyor.yml
generated
vendored
Normal file
32
vendor/github.com/pkg/errors/appveyor.yml
generated
vendored
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
version: build-{build}.{branch}
|
||||
|
||||
clone_folder: C:\gopath\src\github.com\pkg\errors
|
||||
shallow_clone: true # for startup speed
|
||||
|
||||
environment:
|
||||
GOPATH: C:\gopath
|
||||
|
||||
platform:
|
||||
- x64
|
||||
|
||||
# http://www.appveyor.com/docs/installed-software
|
||||
install:
|
||||
# some helpful output for debugging builds
|
||||
- go version
|
||||
- go env
|
||||
# pre-installed MinGW at C:\MinGW is 32bit only
|
||||
# but MSYS2 at C:\msys64 has mingw64
|
||||
- set PATH=C:\msys64\mingw64\bin;%PATH%
|
||||
- gcc --version
|
||||
- g++ --version
|
||||
|
||||
build_script:
|
||||
- go install -v ./...
|
||||
|
||||
test_script:
|
||||
- set PATH=C:\gopath\bin;%PATH%
|
||||
- go test -v ./...
|
||||
|
||||
#artifacts:
|
||||
# - path: '%GOPATH%\bin\*.exe'
|
||||
deploy: off
|
||||
288
vendor/github.com/pkg/errors/errors.go
generated
vendored
Normal file
288
vendor/github.com/pkg/errors/errors.go
generated
vendored
Normal file
|
|
@ -0,0 +1,288 @@
|
|||
// Package errors provides simple error handling primitives.
|
||||
//
|
||||
// The traditional error handling idiom in Go is roughly akin to
|
||||
//
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
//
|
||||
// which when applied recursively up the call stack results in error reports
|
||||
// without context or debugging information. The errors package allows
|
||||
// programmers to add context to the failure path in their code in a way
|
||||
// that does not destroy the original value of the error.
|
||||
//
|
||||
// Adding context to an error
|
||||
//
|
||||
// The errors.Wrap function returns a new error that adds context to the
|
||||
// original error by recording a stack trace at the point Wrap is called,
|
||||
// together with the supplied message. For example
|
||||
//
|
||||
// _, err := ioutil.ReadAll(r)
|
||||
// if err != nil {
|
||||
// return errors.Wrap(err, "read failed")
|
||||
// }
|
||||
//
|
||||
// If additional control is required, the errors.WithStack and
|
||||
// errors.WithMessage functions destructure errors.Wrap into its component
|
||||
// operations: annotating an error with a stack trace and with a message,
|
||||
// respectively.
|
||||
//
|
||||
// Retrieving the cause of an error
|
||||
//
|
||||
// Using errors.Wrap constructs a stack of errors, adding context to the
|
||||
// preceding error. Depending on the nature of the error it may be necessary
|
||||
// to reverse the operation of errors.Wrap to retrieve the original error
|
||||
// for inspection. Any error value which implements this interface
|
||||
//
|
||||
// type causer interface {
|
||||
// Cause() error
|
||||
// }
|
||||
//
|
||||
// can be inspected by errors.Cause. errors.Cause will recursively retrieve
|
||||
// the topmost error that does not implement causer, which is assumed to be
|
||||
// the original cause. For example:
|
||||
//
|
||||
// switch err := errors.Cause(err).(type) {
|
||||
// case *MyError:
|
||||
// // handle specifically
|
||||
// default:
|
||||
// // unknown error
|
||||
// }
|
||||
//
|
||||
// Although the causer interface is not exported by this package, it is
|
||||
// considered a part of its stable public interface.
|
||||
//
|
||||
// Formatted printing of errors
|
||||
//
|
||||
// All error values returned from this package implement fmt.Formatter and can
|
||||
// be formatted by the fmt package. The following verbs are supported:
|
||||
//
|
||||
// %s print the error. If the error has a Cause it will be
|
||||
// printed recursively.
|
||||
// %v see %s
|
||||
// %+v extended format. Each Frame of the error's StackTrace will
|
||||
// be printed in detail.
|
||||
//
|
||||
// Retrieving the stack trace of an error or wrapper
|
||||
//
|
||||
// New, Errorf, Wrap, and Wrapf record a stack trace at the point they are
|
||||
// invoked. This information can be retrieved with the following interface:
|
||||
//
|
||||
// type stackTracer interface {
|
||||
// StackTrace() errors.StackTrace
|
||||
// }
|
||||
//
|
||||
// The returned errors.StackTrace type is defined as
|
||||
//
|
||||
// type StackTrace []Frame
|
||||
//
|
||||
// The Frame type represents a call site in the stack trace. Frame supports
|
||||
// the fmt.Formatter interface that can be used for printing information about
|
||||
// the stack trace of this error. For example:
|
||||
//
|
||||
// if err, ok := err.(stackTracer); ok {
|
||||
// for _, f := range err.StackTrace() {
|
||||
// fmt.Printf("%+s:%d\n", f, f)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Although the stackTracer interface is not exported by this package, it is
|
||||
// considered a part of its stable public interface.
|
||||
//
|
||||
// See the documentation for Frame.Format for more details.
|
||||
package errors
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
// New returns an error with the supplied message.
|
||||
// New also records the stack trace at the point it was called.
|
||||
func New(message string) error {
|
||||
return &fundamental{
|
||||
msg: message,
|
||||
stack: callers(),
|
||||
}
|
||||
}
|
||||
|
||||
// Errorf formats according to a format specifier and returns the string
|
||||
// as a value that satisfies error.
|
||||
// Errorf also records the stack trace at the point it was called.
|
||||
func Errorf(format string, args ...interface{}) error {
|
||||
return &fundamental{
|
||||
msg: fmt.Sprintf(format, args...),
|
||||
stack: callers(),
|
||||
}
|
||||
}
|
||||
|
||||
// fundamental is an error that has a message and a stack, but no caller.
|
||||
type fundamental struct {
|
||||
msg string
|
||||
*stack
|
||||
}
|
||||
|
||||
func (f *fundamental) Error() string { return f.msg }
|
||||
|
||||
func (f *fundamental) Format(s fmt.State, verb rune) {
|
||||
switch verb {
|
||||
case 'v':
|
||||
if s.Flag('+') {
|
||||
io.WriteString(s, f.msg)
|
||||
f.stack.Format(s, verb)
|
||||
return
|
||||
}
|
||||
fallthrough
|
||||
case 's':
|
||||
io.WriteString(s, f.msg)
|
||||
case 'q':
|
||||
fmt.Fprintf(s, "%q", f.msg)
|
||||
}
|
||||
}
|
||||
|
||||
// WithStack annotates err with a stack trace at the point WithStack was called.
|
||||
// If err is nil, WithStack returns nil.
|
||||
func WithStack(err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return &withStack{
|
||||
err,
|
||||
callers(),
|
||||
}
|
||||
}
|
||||
|
||||
type withStack struct {
|
||||
error
|
||||
*stack
|
||||
}
|
||||
|
||||
func (w *withStack) Cause() error { return w.error }
|
||||
|
||||
// Unwrap provides compatibility for Go 1.13 error chains.
|
||||
func (w *withStack) Unwrap() error { return w.error }
|
||||
|
||||
func (w *withStack) Format(s fmt.State, verb rune) {
|
||||
switch verb {
|
||||
case 'v':
|
||||
if s.Flag('+') {
|
||||
fmt.Fprintf(s, "%+v", w.Cause())
|
||||
w.stack.Format(s, verb)
|
||||
return
|
||||
}
|
||||
fallthrough
|
||||
case 's':
|
||||
io.WriteString(s, w.Error())
|
||||
case 'q':
|
||||
fmt.Fprintf(s, "%q", w.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// Wrap returns an error annotating err with a stack trace
|
||||
// at the point Wrap is called, and the supplied message.
|
||||
// If err is nil, Wrap returns nil.
|
||||
func Wrap(err error, message string) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
err = &withMessage{
|
||||
cause: err,
|
||||
msg: message,
|
||||
}
|
||||
return &withStack{
|
||||
err,
|
||||
callers(),
|
||||
}
|
||||
}
|
||||
|
||||
// Wrapf returns an error annotating err with a stack trace
|
||||
// at the point Wrapf is called, and the format specifier.
|
||||
// If err is nil, Wrapf returns nil.
|
||||
func Wrapf(err error, format string, args ...interface{}) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
err = &withMessage{
|
||||
cause: err,
|
||||
msg: fmt.Sprintf(format, args...),
|
||||
}
|
||||
return &withStack{
|
||||
err,
|
||||
callers(),
|
||||
}
|
||||
}
|
||||
|
||||
// WithMessage annotates err with a new message.
|
||||
// If err is nil, WithMessage returns nil.
|
||||
func WithMessage(err error, message string) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return &withMessage{
|
||||
cause: err,
|
||||
msg: message,
|
||||
}
|
||||
}
|
||||
|
||||
// WithMessagef annotates err with the format specifier.
|
||||
// If err is nil, WithMessagef returns nil.
|
||||
func WithMessagef(err error, format string, args ...interface{}) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return &withMessage{
|
||||
cause: err,
|
||||
msg: fmt.Sprintf(format, args...),
|
||||
}
|
||||
}
|
||||
|
||||
type withMessage struct {
|
||||
cause error
|
||||
msg string
|
||||
}
|
||||
|
||||
func (w *withMessage) Error() string { return w.msg + ": " + w.cause.Error() }
|
||||
func (w *withMessage) Cause() error { return w.cause }
|
||||
|
||||
// Unwrap provides compatibility for Go 1.13 error chains.
|
||||
func (w *withMessage) Unwrap() error { return w.cause }
|
||||
|
||||
func (w *withMessage) Format(s fmt.State, verb rune) {
|
||||
switch verb {
|
||||
case 'v':
|
||||
if s.Flag('+') {
|
||||
fmt.Fprintf(s, "%+v\n", w.Cause())
|
||||
io.WriteString(s, w.msg)
|
||||
return
|
||||
}
|
||||
fallthrough
|
||||
case 's', 'q':
|
||||
io.WriteString(s, w.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// Cause returns the underlying cause of the error, if possible.
|
||||
// An error value has a cause if it implements the following
|
||||
// interface:
|
||||
//
|
||||
// type causer interface {
|
||||
// Cause() error
|
||||
// }
|
||||
//
|
||||
// If the error does not implement Cause, the original error will
|
||||
// be returned. If the error is nil, nil will be returned without further
|
||||
// investigation.
|
||||
func Cause(err error) error {
|
||||
type causer interface {
|
||||
Cause() error
|
||||
}
|
||||
|
||||
for err != nil {
|
||||
cause, ok := err.(causer)
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
err = cause.Cause()
|
||||
}
|
||||
return err
|
||||
}
|
||||
38
vendor/github.com/pkg/errors/go113.go
generated
vendored
Normal file
38
vendor/github.com/pkg/errors/go113.go
generated
vendored
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
// +build go1.13
|
||||
|
||||
package errors
|
||||
|
||||
import (
|
||||
stderrors "errors"
|
||||
)
|
||||
|
||||
// Is reports whether any error in err's chain matches target.
|
||||
//
|
||||
// The chain consists of err itself followed by the sequence of errors obtained by
|
||||
// repeatedly calling Unwrap.
|
||||
//
|
||||
// An error is considered to match a target if it is equal to that target or if
|
||||
// it implements a method Is(error) bool such that Is(target) returns true.
|
||||
func Is(err, target error) bool { return stderrors.Is(err, target) }
|
||||
|
||||
// As finds the first error in err's chain that matches target, and if so, sets
|
||||
// target to that error value and returns true.
|
||||
//
|
||||
// The chain consists of err itself followed by the sequence of errors obtained by
|
||||
// repeatedly calling Unwrap.
|
||||
//
|
||||
// An error matches target if the error's concrete value is assignable to the value
|
||||
// pointed to by target, or if the error has a method As(interface{}) bool such that
|
||||
// As(target) returns true. In the latter case, the As method is responsible for
|
||||
// setting target.
|
||||
//
|
||||
// As will panic if target is not a non-nil pointer to either a type that implements
|
||||
// error, or to any interface type. As returns false if err is nil.
|
||||
func As(err error, target interface{}) bool { return stderrors.As(err, target) }
|
||||
|
||||
// Unwrap returns the result of calling the Unwrap method on err, if err's
|
||||
// type contains an Unwrap method returning error.
|
||||
// Otherwise, Unwrap returns nil.
|
||||
func Unwrap(err error) error {
|
||||
return stderrors.Unwrap(err)
|
||||
}
|
||||
177
vendor/github.com/pkg/errors/stack.go
generated
vendored
Normal file
177
vendor/github.com/pkg/errors/stack.go
generated
vendored
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
package errors
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"path"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Frame represents a program counter inside a stack frame.
|
||||
// For historical reasons if Frame is interpreted as a uintptr
|
||||
// its value represents the program counter + 1.
|
||||
type Frame uintptr
|
||||
|
||||
// pc returns the program counter for this frame;
|
||||
// multiple frames may have the same PC value.
|
||||
func (f Frame) pc() uintptr { return uintptr(f) - 1 }
|
||||
|
||||
// file returns the full path to the file that contains the
|
||||
// function for this Frame's pc.
|
||||
func (f Frame) file() string {
|
||||
fn := runtime.FuncForPC(f.pc())
|
||||
if fn == nil {
|
||||
return "unknown"
|
||||
}
|
||||
file, _ := fn.FileLine(f.pc())
|
||||
return file
|
||||
}
|
||||
|
||||
// line returns the line number of source code of the
|
||||
// function for this Frame's pc.
|
||||
func (f Frame) line() int {
|
||||
fn := runtime.FuncForPC(f.pc())
|
||||
if fn == nil {
|
||||
return 0
|
||||
}
|
||||
_, line := fn.FileLine(f.pc())
|
||||
return line
|
||||
}
|
||||
|
||||
// name returns the name of this function, if known.
|
||||
func (f Frame) name() string {
|
||||
fn := runtime.FuncForPC(f.pc())
|
||||
if fn == nil {
|
||||
return "unknown"
|
||||
}
|
||||
return fn.Name()
|
||||
}
|
||||
|
||||
// Format formats the frame according to the fmt.Formatter interface.
|
||||
//
|
||||
// %s source file
|
||||
// %d source line
|
||||
// %n function name
|
||||
// %v equivalent to %s:%d
|
||||
//
|
||||
// Format accepts flags that alter the printing of some verbs, as follows:
|
||||
//
|
||||
// %+s function name and path of source file relative to the compile time
|
||||
// GOPATH separated by \n\t (<funcname>\n\t<path>)
|
||||
// %+v equivalent to %+s:%d
|
||||
func (f Frame) Format(s fmt.State, verb rune) {
|
||||
switch verb {
|
||||
case 's':
|
||||
switch {
|
||||
case s.Flag('+'):
|
||||
io.WriteString(s, f.name())
|
||||
io.WriteString(s, "\n\t")
|
||||
io.WriteString(s, f.file())
|
||||
default:
|
||||
io.WriteString(s, path.Base(f.file()))
|
||||
}
|
||||
case 'd':
|
||||
io.WriteString(s, strconv.Itoa(f.line()))
|
||||
case 'n':
|
||||
io.WriteString(s, funcname(f.name()))
|
||||
case 'v':
|
||||
f.Format(s, 's')
|
||||
io.WriteString(s, ":")
|
||||
f.Format(s, 'd')
|
||||
}
|
||||
}
|
||||
|
||||
// MarshalText formats a stacktrace Frame as a text string. The output is the
|
||||
// same as that of fmt.Sprintf("%+v", f), but without newlines or tabs.
|
||||
func (f Frame) MarshalText() ([]byte, error) {
|
||||
name := f.name()
|
||||
if name == "unknown" {
|
||||
return []byte(name), nil
|
||||
}
|
||||
return []byte(fmt.Sprintf("%s %s:%d", name, f.file(), f.line())), nil
|
||||
}
|
||||
|
||||
// StackTrace is stack of Frames from innermost (newest) to outermost (oldest).
|
||||
type StackTrace []Frame
|
||||
|
||||
// Format formats the stack of Frames according to the fmt.Formatter interface.
|
||||
//
|
||||
// %s lists source files for each Frame in the stack
|
||||
// %v lists the source file and line number for each Frame in the stack
|
||||
//
|
||||
// Format accepts flags that alter the printing of some verbs, as follows:
|
||||
//
|
||||
// %+v Prints filename, function, and line number for each Frame in the stack.
|
||||
func (st StackTrace) Format(s fmt.State, verb rune) {
|
||||
switch verb {
|
||||
case 'v':
|
||||
switch {
|
||||
case s.Flag('+'):
|
||||
for _, f := range st {
|
||||
io.WriteString(s, "\n")
|
||||
f.Format(s, verb)
|
||||
}
|
||||
case s.Flag('#'):
|
||||
fmt.Fprintf(s, "%#v", []Frame(st))
|
||||
default:
|
||||
st.formatSlice(s, verb)
|
||||
}
|
||||
case 's':
|
||||
st.formatSlice(s, verb)
|
||||
}
|
||||
}
|
||||
|
||||
// formatSlice will format this StackTrace into the given buffer as a slice of
|
||||
// Frame, only valid when called with '%s' or '%v'.
|
||||
func (st StackTrace) formatSlice(s fmt.State, verb rune) {
|
||||
io.WriteString(s, "[")
|
||||
for i, f := range st {
|
||||
if i > 0 {
|
||||
io.WriteString(s, " ")
|
||||
}
|
||||
f.Format(s, verb)
|
||||
}
|
||||
io.WriteString(s, "]")
|
||||
}
|
||||
|
||||
// stack represents a stack of program counters.
|
||||
type stack []uintptr
|
||||
|
||||
func (s *stack) Format(st fmt.State, verb rune) {
|
||||
switch verb {
|
||||
case 'v':
|
||||
switch {
|
||||
case st.Flag('+'):
|
||||
for _, pc := range *s {
|
||||
f := Frame(pc)
|
||||
fmt.Fprintf(st, "\n%+v", f)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *stack) StackTrace() StackTrace {
|
||||
f := make([]Frame, len(*s))
|
||||
for i := 0; i < len(f); i++ {
|
||||
f[i] = Frame((*s)[i])
|
||||
}
|
||||
return f
|
||||
}
|
||||
|
||||
func callers() *stack {
|
||||
const depth = 32
|
||||
var pcs [depth]uintptr
|
||||
n := runtime.Callers(3, pcs[:])
|
||||
var st stack = pcs[0:n]
|
||||
return &st
|
||||
}
|
||||
|
||||
// funcname removes the path prefix component of a function's name reported by func.Name().
|
||||
func funcname(name string) string {
|
||||
i := strings.LastIndex(name, "/")
|
||||
name = name[i+1:]
|
||||
i = strings.Index(name, ".")
|
||||
return name[i+1:]
|
||||
}
|
||||
78
vendor/github.com/stretchr/testify/assert/assertion_format.go
generated
vendored
78
vendor/github.com/stretchr/testify/assert/assertion_format.go
generated
vendored
|
|
@ -32,7 +32,8 @@ func Containsf(t TestingT, s interface{}, contains interface{}, msg string, args
|
|||
return Contains(t, s, contains, append([]interface{}{msg}, args...)...)
|
||||
}
|
||||
|
||||
// DirExistsf checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists.
|
||||
// DirExistsf checks whether a directory exists in the given path. It also fails
|
||||
// if the path is a file rather a directory or there is an error checking whether it exists.
|
||||
func DirExistsf(t TestingT, path string, msg string, args ...interface{}) bool {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
|
|
@ -160,7 +161,8 @@ func Falsef(t TestingT, value bool, msg string, args ...interface{}) bool {
|
|||
return False(t, value, append([]interface{}{msg}, args...)...)
|
||||
}
|
||||
|
||||
// FileExistsf checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file.
|
||||
// FileExistsf checks whether a file exists in the given path. It also fails if
|
||||
// the path points to a directory or there is an error when trying to check the file.
|
||||
func FileExistsf(t TestingT, path string, msg string, args ...interface{}) bool {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
|
|
@ -267,7 +269,7 @@ func Implementsf(t TestingT, interfaceObject interface{}, object interface{}, ms
|
|||
|
||||
// InDeltaf asserts that the two numerals are within delta of each other.
|
||||
//
|
||||
// assert.InDeltaf(t, math.Pi, (22 / 7.0, "error message %s", "formatted"), 0.01)
|
||||
// assert.InDeltaf(t, math.Pi, 22/7.0, 0.01, "error message %s", "formatted")
|
||||
func InDeltaf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
|
|
@ -325,14 +327,6 @@ func JSONEqf(t TestingT, expected string, actual string, msg string, args ...int
|
|||
return JSONEq(t, expected, actual, append([]interface{}{msg}, args...)...)
|
||||
}
|
||||
|
||||
// YAMLEqf asserts that two YAML strings are equivalent.
|
||||
func YAMLEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) bool {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
return YAMLEq(t, expected, actual, append([]interface{}{msg}, args...)...)
|
||||
}
|
||||
|
||||
// Lenf asserts that the specified object has specific length.
|
||||
// Lenf also fails if the object has a type that len() not accept.
|
||||
//
|
||||
|
|
@ -369,6 +363,17 @@ func LessOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args .
|
|||
return LessOrEqual(t, e1, e2, append([]interface{}{msg}, args...)...)
|
||||
}
|
||||
|
||||
// Neverf asserts that the given condition doesn't satisfy in waitFor time,
|
||||
// periodically checking the target function each tick.
|
||||
//
|
||||
// assert.Neverf(t, func() bool { return false; }, time.Second, 10*time.Millisecond, "error message %s", "formatted")
|
||||
func Neverf(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
return Never(t, condition, waitFor, tick, append([]interface{}{msg}, args...)...)
|
||||
}
|
||||
|
||||
// Nilf asserts that the specified object is nil.
|
||||
//
|
||||
// assert.Nilf(t, err, "error message %s", "formatted")
|
||||
|
|
@ -379,6 +384,15 @@ func Nilf(t TestingT, object interface{}, msg string, args ...interface{}) bool
|
|||
return Nil(t, object, append([]interface{}{msg}, args...)...)
|
||||
}
|
||||
|
||||
// NoDirExistsf checks whether a directory does not exist in the given path.
|
||||
// It fails if the path points to an existing _directory_ only.
|
||||
func NoDirExistsf(t TestingT, path string, msg string, args ...interface{}) bool {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
return NoDirExists(t, path, append([]interface{}{msg}, args...)...)
|
||||
}
|
||||
|
||||
// NoErrorf asserts that a function returned no error (i.e. `nil`).
|
||||
//
|
||||
// actualObj, err := SomeFunction()
|
||||
|
|
@ -392,6 +406,15 @@ func NoErrorf(t TestingT, err error, msg string, args ...interface{}) bool {
|
|||
return NoError(t, err, append([]interface{}{msg}, args...)...)
|
||||
}
|
||||
|
||||
// NoFileExistsf checks whether a file does not exist in a given path. It fails
|
||||
// if the path points to an existing _file_ only.
|
||||
func NoFileExistsf(t TestingT, path string, msg string, args ...interface{}) bool {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
return NoFileExists(t, path, append([]interface{}{msg}, args...)...)
|
||||
}
|
||||
|
||||
// NotContainsf asserts that the specified string, list(array, slice...) or map does NOT contain the
|
||||
// specified substring or element.
|
||||
//
|
||||
|
|
@ -462,6 +485,19 @@ func NotRegexpf(t TestingT, rx interface{}, str interface{}, msg string, args ..
|
|||
return NotRegexp(t, rx, str, append([]interface{}{msg}, args...)...)
|
||||
}
|
||||
|
||||
// NotSamef asserts that two pointers do not reference the same object.
|
||||
//
|
||||
// assert.NotSamef(t, ptr1, ptr2, "error message %s", "formatted")
|
||||
//
|
||||
// Both arguments must be pointer variables. Pointer variable sameness is
|
||||
// determined based on the equality of both type and value.
|
||||
func NotSamef(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
return NotSame(t, expected, actual, append([]interface{}{msg}, args...)...)
|
||||
}
|
||||
|
||||
// NotSubsetf asserts that the specified list(array, slice...) contains not all
|
||||
// elements given in the specified subset(array, slice...).
|
||||
//
|
||||
|
|
@ -491,6 +527,18 @@ func Panicsf(t TestingT, f PanicTestFunc, msg string, args ...interface{}) bool
|
|||
return Panics(t, f, append([]interface{}{msg}, args...)...)
|
||||
}
|
||||
|
||||
// PanicsWithErrorf asserts that the code inside the specified PanicTestFunc
|
||||
// panics, and that the recovered panic value is an error that satisfies the
|
||||
// EqualError comparison.
|
||||
//
|
||||
// assert.PanicsWithErrorf(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted")
|
||||
func PanicsWithErrorf(t TestingT, errString string, f PanicTestFunc, msg string, args ...interface{}) bool {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
return PanicsWithError(t, errString, f, append([]interface{}{msg}, args...)...)
|
||||
}
|
||||
|
||||
// PanicsWithValuef asserts that the code inside the specified PanicTestFunc panics, and that
|
||||
// the recovered panic value equals the expected panic value.
|
||||
//
|
||||
|
|
@ -557,6 +605,14 @@ func WithinDurationf(t TestingT, expected time.Time, actual time.Time, delta tim
|
|||
return WithinDuration(t, expected, actual, delta, append([]interface{}{msg}, args...)...)
|
||||
}
|
||||
|
||||
// YAMLEqf asserts that two YAML strings are equivalent.
|
||||
func YAMLEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) bool {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
return YAMLEq(t, expected, actual, append([]interface{}{msg}, args...)...)
|
||||
}
|
||||
|
||||
// Zerof asserts that i is the zero value for its type.
|
||||
func Zerof(t TestingT, i interface{}, msg string, args ...interface{}) bool {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
|
|
|
|||
156
vendor/github.com/stretchr/testify/assert/assertion_forward.go
generated
vendored
156
vendor/github.com/stretchr/testify/assert/assertion_forward.go
generated
vendored
|
|
@ -53,7 +53,8 @@ func (a *Assertions) Containsf(s interface{}, contains interface{}, msg string,
|
|||
return Containsf(a.t, s, contains, msg, args...)
|
||||
}
|
||||
|
||||
// DirExists checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists.
|
||||
// DirExists checks whether a directory exists in the given path. It also fails
|
||||
// if the path is a file rather a directory or there is an error checking whether it exists.
|
||||
func (a *Assertions) DirExists(path string, msgAndArgs ...interface{}) bool {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
|
|
@ -61,7 +62,8 @@ func (a *Assertions) DirExists(path string, msgAndArgs ...interface{}) bool {
|
|||
return DirExists(a.t, path, msgAndArgs...)
|
||||
}
|
||||
|
||||
// DirExistsf checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists.
|
||||
// DirExistsf checks whether a directory exists in the given path. It also fails
|
||||
// if the path is a file rather a directory or there is an error checking whether it exists.
|
||||
func (a *Assertions) DirExistsf(path string, msg string, args ...interface{}) bool {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
|
|
@ -309,7 +311,8 @@ func (a *Assertions) Falsef(value bool, msg string, args ...interface{}) bool {
|
|||
return Falsef(a.t, value, msg, args...)
|
||||
}
|
||||
|
||||
// FileExists checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file.
|
||||
// FileExists checks whether a file exists in the given path. It also fails if
|
||||
// the path points to a directory or there is an error when trying to check the file.
|
||||
func (a *Assertions) FileExists(path string, msgAndArgs ...interface{}) bool {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
|
|
@ -317,7 +320,8 @@ func (a *Assertions) FileExists(path string, msgAndArgs ...interface{}) bool {
|
|||
return FileExists(a.t, path, msgAndArgs...)
|
||||
}
|
||||
|
||||
// FileExistsf checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file.
|
||||
// FileExistsf checks whether a file exists in the given path. It also fails if
|
||||
// the path points to a directory or there is an error when trying to check the file.
|
||||
func (a *Assertions) FileExistsf(path string, msg string, args ...interface{}) bool {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
|
|
@ -521,7 +525,7 @@ func (a *Assertions) Implementsf(interfaceObject interface{}, object interface{}
|
|||
|
||||
// InDelta asserts that the two numerals are within delta of each other.
|
||||
//
|
||||
// a.InDelta(math.Pi, (22 / 7.0), 0.01)
|
||||
// a.InDelta(math.Pi, 22/7.0, 0.01)
|
||||
func (a *Assertions) InDelta(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
|
|
@ -563,7 +567,7 @@ func (a *Assertions) InDeltaSlicef(expected interface{}, actual interface{}, del
|
|||
|
||||
// InDeltaf asserts that the two numerals are within delta of each other.
|
||||
//
|
||||
// a.InDeltaf(math.Pi, (22 / 7.0, "error message %s", "formatted"), 0.01)
|
||||
// a.InDeltaf(math.Pi, 22/7.0, 0.01, "error message %s", "formatted")
|
||||
func (a *Assertions) InDeltaf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
|
|
@ -639,22 +643,6 @@ func (a *Assertions) JSONEqf(expected string, actual string, msg string, args ..
|
|||
return JSONEqf(a.t, expected, actual, msg, args...)
|
||||
}
|
||||
|
||||
// YAMLEq asserts that two YAML strings are equivalent.
|
||||
func (a *Assertions) YAMLEq(expected string, actual string, msgAndArgs ...interface{}) bool {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
return YAMLEq(a.t, expected, actual, msgAndArgs...)
|
||||
}
|
||||
|
||||
// YAMLEqf asserts that two YAML strings are equivalent.
|
||||
func (a *Assertions) YAMLEqf(expected string, actual string, msg string, args ...interface{}) bool {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
return YAMLEqf(a.t, expected, actual, msg, args...)
|
||||
}
|
||||
|
||||
// Len asserts that the specified object has specific length.
|
||||
// Len also fails if the object has a type that len() not accept.
|
||||
//
|
||||
|
|
@ -727,6 +715,28 @@ func (a *Assertions) Lessf(e1 interface{}, e2 interface{}, msg string, args ...i
|
|||
return Lessf(a.t, e1, e2, msg, args...)
|
||||
}
|
||||
|
||||
// Never asserts that the given condition doesn't satisfy in waitFor time,
|
||||
// periodically checking the target function each tick.
|
||||
//
|
||||
// a.Never(func() bool { return false; }, time.Second, 10*time.Millisecond)
|
||||
func (a *Assertions) Never(condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
return Never(a.t, condition, waitFor, tick, msgAndArgs...)
|
||||
}
|
||||
|
||||
// Neverf asserts that the given condition doesn't satisfy in waitFor time,
|
||||
// periodically checking the target function each tick.
|
||||
//
|
||||
// a.Neverf(func() bool { return false; }, time.Second, 10*time.Millisecond, "error message %s", "formatted")
|
||||
func (a *Assertions) Neverf(condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
return Neverf(a.t, condition, waitFor, tick, msg, args...)
|
||||
}
|
||||
|
||||
// Nil asserts that the specified object is nil.
|
||||
//
|
||||
// a.Nil(err)
|
||||
|
|
@ -747,6 +757,24 @@ func (a *Assertions) Nilf(object interface{}, msg string, args ...interface{}) b
|
|||
return Nilf(a.t, object, msg, args...)
|
||||
}
|
||||
|
||||
// NoDirExists checks whether a directory does not exist in the given path.
|
||||
// It fails if the path points to an existing _directory_ only.
|
||||
func (a *Assertions) NoDirExists(path string, msgAndArgs ...interface{}) bool {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
return NoDirExists(a.t, path, msgAndArgs...)
|
||||
}
|
||||
|
||||
// NoDirExistsf checks whether a directory does not exist in the given path.
|
||||
// It fails if the path points to an existing _directory_ only.
|
||||
func (a *Assertions) NoDirExistsf(path string, msg string, args ...interface{}) bool {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
return NoDirExistsf(a.t, path, msg, args...)
|
||||
}
|
||||
|
||||
// NoError asserts that a function returned no error (i.e. `nil`).
|
||||
//
|
||||
// actualObj, err := SomeFunction()
|
||||
|
|
@ -773,6 +801,24 @@ func (a *Assertions) NoErrorf(err error, msg string, args ...interface{}) bool {
|
|||
return NoErrorf(a.t, err, msg, args...)
|
||||
}
|
||||
|
||||
// NoFileExists checks whether a file does not exist in a given path. It fails
|
||||
// if the path points to an existing _file_ only.
|
||||
func (a *Assertions) NoFileExists(path string, msgAndArgs ...interface{}) bool {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
return NoFileExists(a.t, path, msgAndArgs...)
|
||||
}
|
||||
|
||||
// NoFileExistsf checks whether a file does not exist in a given path. It fails
|
||||
// if the path points to an existing _file_ only.
|
||||
func (a *Assertions) NoFileExistsf(path string, msg string, args ...interface{}) bool {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
return NoFileExistsf(a.t, path, msg, args...)
|
||||
}
|
||||
|
||||
// NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the
|
||||
// specified substring or element.
|
||||
//
|
||||
|
|
@ -913,6 +959,32 @@ func (a *Assertions) NotRegexpf(rx interface{}, str interface{}, msg string, arg
|
|||
return NotRegexpf(a.t, rx, str, msg, args...)
|
||||
}
|
||||
|
||||
// NotSame asserts that two pointers do not reference the same object.
|
||||
//
|
||||
// a.NotSame(ptr1, ptr2)
|
||||
//
|
||||
// Both arguments must be pointer variables. Pointer variable sameness is
|
||||
// determined based on the equality of both type and value.
|
||||
func (a *Assertions) NotSame(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
return NotSame(a.t, expected, actual, msgAndArgs...)
|
||||
}
|
||||
|
||||
// NotSamef asserts that two pointers do not reference the same object.
|
||||
//
|
||||
// a.NotSamef(ptr1, ptr2, "error message %s", "formatted")
|
||||
//
|
||||
// Both arguments must be pointer variables. Pointer variable sameness is
|
||||
// determined based on the equality of both type and value.
|
||||
func (a *Assertions) NotSamef(expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
return NotSamef(a.t, expected, actual, msg, args...)
|
||||
}
|
||||
|
||||
// NotSubset asserts that the specified list(array, slice...) contains not all
|
||||
// elements given in the specified subset(array, slice...).
|
||||
//
|
||||
|
|
@ -961,6 +1033,30 @@ func (a *Assertions) Panics(f PanicTestFunc, msgAndArgs ...interface{}) bool {
|
|||
return Panics(a.t, f, msgAndArgs...)
|
||||
}
|
||||
|
||||
// PanicsWithError asserts that the code inside the specified PanicTestFunc
|
||||
// panics, and that the recovered panic value is an error that satisfies the
|
||||
// EqualError comparison.
|
||||
//
|
||||
// a.PanicsWithError("crazy error", func(){ GoCrazy() })
|
||||
func (a *Assertions) PanicsWithError(errString string, f PanicTestFunc, msgAndArgs ...interface{}) bool {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
return PanicsWithError(a.t, errString, f, msgAndArgs...)
|
||||
}
|
||||
|
||||
// PanicsWithErrorf asserts that the code inside the specified PanicTestFunc
|
||||
// panics, and that the recovered panic value is an error that satisfies the
|
||||
// EqualError comparison.
|
||||
//
|
||||
// a.PanicsWithErrorf("crazy error", func(){ GoCrazy() }, "error message %s", "formatted")
|
||||
func (a *Assertions) PanicsWithErrorf(errString string, f PanicTestFunc, msg string, args ...interface{}) bool {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
return PanicsWithErrorf(a.t, errString, f, msg, args...)
|
||||
}
|
||||
|
||||
// PanicsWithValue asserts that the code inside the specified PanicTestFunc panics, and that
|
||||
// the recovered panic value equals the expected panic value.
|
||||
//
|
||||
|
|
@ -1103,6 +1199,22 @@ func (a *Assertions) WithinDurationf(expected time.Time, actual time.Time, delta
|
|||
return WithinDurationf(a.t, expected, actual, delta, msg, args...)
|
||||
}
|
||||
|
||||
// YAMLEq asserts that two YAML strings are equivalent.
|
||||
func (a *Assertions) YAMLEq(expected string, actual string, msgAndArgs ...interface{}) bool {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
return YAMLEq(a.t, expected, actual, msgAndArgs...)
|
||||
}
|
||||
|
||||
// YAMLEqf asserts that two YAML strings are equivalent.
|
||||
func (a *Assertions) YAMLEqf(expected string, actual string, msg string, args ...interface{}) bool {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
return YAMLEqf(a.t, expected, actual, msg, args...)
|
||||
}
|
||||
|
||||
// Zero asserts that i is the zero value for its type.
|
||||
func (a *Assertions) Zero(i interface{}, msgAndArgs ...interface{}) bool {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
|
|
|
|||
218
vendor/github.com/stretchr/testify/assert/assertions.go
generated
vendored
218
vendor/github.com/stretchr/testify/assert/assertions.go
generated
vendored
|
|
@ -11,6 +11,7 @@ import (
|
|||
"reflect"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"runtime/debug"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode"
|
||||
|
|
@ -21,7 +22,7 @@ import (
|
|||
yaml "gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
//go:generate go run ../_codegen/main.go -output-package=assert -template=assertion_format.go.tmpl
|
||||
//go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=assert -template=assertion_format.go.tmpl"
|
||||
|
||||
// TestingT is an interface wrapper around *testing.T
|
||||
type TestingT interface {
|
||||
|
|
@ -351,6 +352,19 @@ func Equal(t TestingT, expected, actual interface{}, msgAndArgs ...interface{})
|
|||
|
||||
}
|
||||
|
||||
// validateEqualArgs checks whether provided arguments can be safely used in the
|
||||
// Equal/NotEqual functions.
|
||||
func validateEqualArgs(expected, actual interface{}) error {
|
||||
if expected == nil && actual == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if isFunction(expected) || isFunction(actual) {
|
||||
return errors.New("cannot take func type as argument")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Same asserts that two pointers reference the same object.
|
||||
//
|
||||
// assert.Same(t, ptr1, ptr2)
|
||||
|
|
@ -362,18 +376,7 @@ func Same(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) b
|
|||
h.Helper()
|
||||
}
|
||||
|
||||
expectedPtr, actualPtr := reflect.ValueOf(expected), reflect.ValueOf(actual)
|
||||
if expectedPtr.Kind() != reflect.Ptr || actualPtr.Kind() != reflect.Ptr {
|
||||
return Fail(t, "Invalid operation: both arguments must be pointers", msgAndArgs...)
|
||||
}
|
||||
|
||||
expectedType, actualType := reflect.TypeOf(expected), reflect.TypeOf(actual)
|
||||
if expectedType != actualType {
|
||||
return Fail(t, fmt.Sprintf("Pointer expected to be of type %v, but was %v",
|
||||
expectedType, actualType), msgAndArgs...)
|
||||
}
|
||||
|
||||
if expected != actual {
|
||||
if !samePointers(expected, actual) {
|
||||
return Fail(t, fmt.Sprintf("Not same: \n"+
|
||||
"expected: %p %#v\n"+
|
||||
"actual : %p %#v", expected, expected, actual, actual), msgAndArgs...)
|
||||
|
|
@ -382,6 +385,42 @@ func Same(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) b
|
|||
return true
|
||||
}
|
||||
|
||||
// NotSame asserts that two pointers do not reference the same object.
|
||||
//
|
||||
// assert.NotSame(t, ptr1, ptr2)
|
||||
//
|
||||
// Both arguments must be pointer variables. Pointer variable sameness is
|
||||
// determined based on the equality of both type and value.
|
||||
func NotSame(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
|
||||
if samePointers(expected, actual) {
|
||||
return Fail(t, fmt.Sprintf(
|
||||
"Expected and actual point to the same object: %p %#v",
|
||||
expected, expected), msgAndArgs...)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// samePointers compares two generic interface objects and returns whether
|
||||
// they point to the same object
|
||||
func samePointers(first, second interface{}) bool {
|
||||
firstPtr, secondPtr := reflect.ValueOf(first), reflect.ValueOf(second)
|
||||
if firstPtr.Kind() != reflect.Ptr || secondPtr.Kind() != reflect.Ptr {
|
||||
return false
|
||||
}
|
||||
|
||||
firstType, secondType := reflect.TypeOf(first), reflect.TypeOf(second)
|
||||
if firstType != secondType {
|
||||
return false
|
||||
}
|
||||
|
||||
// compare pointer addresses
|
||||
return first == second
|
||||
}
|
||||
|
||||
// formatUnequalValues takes two values of arbitrary types and returns string
|
||||
// representations appropriate to be presented to the user.
|
||||
//
|
||||
|
|
@ -393,9 +432,11 @@ func formatUnequalValues(expected, actual interface{}) (e string, a string) {
|
|||
return fmt.Sprintf("%T(%#v)", expected, expected),
|
||||
fmt.Sprintf("%T(%#v)", actual, actual)
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%#v", expected),
|
||||
fmt.Sprintf("%#v", actual)
|
||||
switch expected.(type) {
|
||||
case time.Duration:
|
||||
return fmt.Sprintf("%v", expected), fmt.Sprintf("%v", actual)
|
||||
}
|
||||
return fmt.Sprintf("%#v", expected), fmt.Sprintf("%#v", actual)
|
||||
}
|
||||
|
||||
// EqualValues asserts that two objects are equal or convertable to the same types
|
||||
|
|
@ -901,15 +942,17 @@ func Condition(t TestingT, comp Comparison, msgAndArgs ...interface{}) bool {
|
|||
type PanicTestFunc func()
|
||||
|
||||
// didPanic returns true if the function passed to it panics. Otherwise, it returns false.
|
||||
func didPanic(f PanicTestFunc) (bool, interface{}) {
|
||||
func didPanic(f PanicTestFunc) (bool, interface{}, string) {
|
||||
|
||||
didPanic := false
|
||||
var message interface{}
|
||||
var stack string
|
||||
func() {
|
||||
|
||||
defer func() {
|
||||
if message = recover(); message != nil {
|
||||
didPanic = true
|
||||
stack = string(debug.Stack())
|
||||
}
|
||||
}()
|
||||
|
||||
|
|
@ -918,7 +961,7 @@ func didPanic(f PanicTestFunc) (bool, interface{}) {
|
|||
|
||||
}()
|
||||
|
||||
return didPanic, message
|
||||
return didPanic, message, stack
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -930,7 +973,7 @@ func Panics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool {
|
|||
h.Helper()
|
||||
}
|
||||
|
||||
if funcDidPanic, panicValue := didPanic(f); !funcDidPanic {
|
||||
if funcDidPanic, panicValue, _ := didPanic(f); !funcDidPanic {
|
||||
return Fail(t, fmt.Sprintf("func %#v should panic\n\tPanic value:\t%#v", f, panicValue), msgAndArgs...)
|
||||
}
|
||||
|
||||
|
|
@ -946,12 +989,34 @@ func PanicsWithValue(t TestingT, expected interface{}, f PanicTestFunc, msgAndAr
|
|||
h.Helper()
|
||||
}
|
||||
|
||||
funcDidPanic, panicValue := didPanic(f)
|
||||
funcDidPanic, panicValue, panickedStack := didPanic(f)
|
||||
if !funcDidPanic {
|
||||
return Fail(t, fmt.Sprintf("func %#v should panic\n\tPanic value:\t%#v", f, panicValue), msgAndArgs...)
|
||||
}
|
||||
if panicValue != expected {
|
||||
return Fail(t, fmt.Sprintf("func %#v should panic with value:\t%#v\n\tPanic value:\t%#v", f, expected, panicValue), msgAndArgs...)
|
||||
return Fail(t, fmt.Sprintf("func %#v should panic with value:\t%#v\n\tPanic value:\t%#v\n\tPanic stack:\t%s", f, expected, panicValue, panickedStack), msgAndArgs...)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// PanicsWithError asserts that the code inside the specified PanicTestFunc
|
||||
// panics, and that the recovered panic value is an error that satisfies the
|
||||
// EqualError comparison.
|
||||
//
|
||||
// assert.PanicsWithError(t, "crazy error", func(){ GoCrazy() })
|
||||
func PanicsWithError(t TestingT, errString string, f PanicTestFunc, msgAndArgs ...interface{}) bool {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
|
||||
funcDidPanic, panicValue, panickedStack := didPanic(f)
|
||||
if !funcDidPanic {
|
||||
return Fail(t, fmt.Sprintf("func %#v should panic\n\tPanic value:\t%#v", f, panicValue), msgAndArgs...)
|
||||
}
|
||||
panicErr, ok := panicValue.(error)
|
||||
if !ok || panicErr.Error() != errString {
|
||||
return Fail(t, fmt.Sprintf("func %#v should panic with error message:\t%#v\n\tPanic value:\t%#v\n\tPanic stack:\t%s", f, errString, panicValue, panickedStack), msgAndArgs...)
|
||||
}
|
||||
|
||||
return true
|
||||
|
|
@ -965,8 +1030,8 @@ func NotPanics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool {
|
|||
h.Helper()
|
||||
}
|
||||
|
||||
if funcDidPanic, panicValue := didPanic(f); funcDidPanic {
|
||||
return Fail(t, fmt.Sprintf("func %#v should not panic\n\tPanic value:\t%v", f, panicValue), msgAndArgs...)
|
||||
if funcDidPanic, panicValue, panickedStack := didPanic(f); funcDidPanic {
|
||||
return Fail(t, fmt.Sprintf("func %#v should not panic\n\tPanic value:\t%v\n\tPanic stack:\t%s", f, panicValue, panickedStack), msgAndArgs...)
|
||||
}
|
||||
|
||||
return true
|
||||
|
|
@ -1026,7 +1091,7 @@ func toFloat(x interface{}) (float64, bool) {
|
|||
|
||||
// InDelta asserts that the two numerals are within delta of each other.
|
||||
//
|
||||
// assert.InDelta(t, math.Pi, (22 / 7.0), 0.01)
|
||||
// assert.InDelta(t, math.Pi, 22/7.0, 0.01)
|
||||
func InDelta(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
|
|
@ -1314,7 +1379,8 @@ func NotZero(t TestingT, i interface{}, msgAndArgs ...interface{}) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
// FileExists checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file.
|
||||
// FileExists checks whether a file exists in the given path. It also fails if
|
||||
// the path points to a directory or there is an error when trying to check the file.
|
||||
func FileExists(t TestingT, path string, msgAndArgs ...interface{}) bool {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
|
|
@ -1332,7 +1398,24 @@ func FileExists(t TestingT, path string, msgAndArgs ...interface{}) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
// DirExists checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists.
|
||||
// NoFileExists checks whether a file does not exist in a given path. It fails
|
||||
// if the path points to an existing _file_ only.
|
||||
func NoFileExists(t TestingT, path string, msgAndArgs ...interface{}) bool {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
info, err := os.Lstat(path)
|
||||
if err != nil {
|
||||
return true
|
||||
}
|
||||
if info.IsDir() {
|
||||
return true
|
||||
}
|
||||
return Fail(t, fmt.Sprintf("file %q exists", path), msgAndArgs...)
|
||||
}
|
||||
|
||||
// DirExists checks whether a directory exists in the given path. It also fails
|
||||
// if the path is a file rather a directory or there is an error checking whether it exists.
|
||||
func DirExists(t TestingT, path string, msgAndArgs ...interface{}) bool {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
|
|
@ -1350,6 +1433,25 @@ func DirExists(t TestingT, path string, msgAndArgs ...interface{}) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
// NoDirExists checks whether a directory does not exist in the given path.
|
||||
// It fails if the path points to an existing _directory_ only.
|
||||
func NoDirExists(t TestingT, path string, msgAndArgs ...interface{}) bool {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
info, err := os.Lstat(path)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return true
|
||||
}
|
||||
return true
|
||||
}
|
||||
if !info.IsDir() {
|
||||
return true
|
||||
}
|
||||
return Fail(t, fmt.Sprintf("directory %q exists", path), msgAndArgs...)
|
||||
}
|
||||
|
||||
// JSONEq asserts that two JSON strings are equivalent.
|
||||
//
|
||||
// assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
|
||||
|
|
@ -1439,15 +1541,6 @@ func diff(expected interface{}, actual interface{}) string {
|
|||
return "\n\nDiff:\n" + diff
|
||||
}
|
||||
|
||||
// validateEqualArgs checks whether provided arguments can be safely used in the
|
||||
// Equal/NotEqual functions.
|
||||
func validateEqualArgs(expected, actual interface{}) error {
|
||||
if isFunction(expected) || isFunction(actual) {
|
||||
return errors.New("cannot take func type as argument")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func isFunction(arg interface{}) bool {
|
||||
if arg == nil {
|
||||
return false
|
||||
|
|
@ -1475,24 +1568,59 @@ func Eventually(t TestingT, condition func() bool, waitFor time.Duration, tick t
|
|||
h.Helper()
|
||||
}
|
||||
|
||||
ch := make(chan bool, 1)
|
||||
|
||||
timer := time.NewTimer(waitFor)
|
||||
ticker := time.NewTicker(tick)
|
||||
checkPassed := make(chan bool)
|
||||
defer timer.Stop()
|
||||
|
||||
ticker := time.NewTicker(tick)
|
||||
defer ticker.Stop()
|
||||
defer close(checkPassed)
|
||||
for {
|
||||
|
||||
for tick := ticker.C; ; {
|
||||
select {
|
||||
case <-timer.C:
|
||||
return Fail(t, "Condition never satisfied", msgAndArgs...)
|
||||
case result := <-checkPassed:
|
||||
if result {
|
||||
case <-tick:
|
||||
tick = nil
|
||||
go func() { ch <- condition() }()
|
||||
case v := <-ch:
|
||||
if v {
|
||||
return true
|
||||
}
|
||||
case <-ticker.C:
|
||||
go func() {
|
||||
checkPassed <- condition()
|
||||
}()
|
||||
tick = ticker.C
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Never asserts that the given condition doesn't satisfy in waitFor time,
|
||||
// periodically checking the target function each tick.
|
||||
//
|
||||
// assert.Never(t, func() bool { return false; }, time.Second, 10*time.Millisecond)
|
||||
func Never(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
|
||||
ch := make(chan bool, 1)
|
||||
|
||||
timer := time.NewTimer(waitFor)
|
||||
defer timer.Stop()
|
||||
|
||||
ticker := time.NewTicker(tick)
|
||||
defer ticker.Stop()
|
||||
|
||||
for tick := ticker.C; ; {
|
||||
select {
|
||||
case <-timer.C:
|
||||
return true
|
||||
case <-tick:
|
||||
tick = nil
|
||||
go func() { ch <- condition() }()
|
||||
case v := <-ch:
|
||||
if v {
|
||||
return Fail(t, "Condition satisfied", msgAndArgs...)
|
||||
}
|
||||
tick = ticker.C
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
2
vendor/github.com/stretchr/testify/assert/forward_assertions.go
generated
vendored
2
vendor/github.com/stretchr/testify/assert/forward_assertions.go
generated
vendored
|
|
@ -13,4 +13,4 @@ func New(t TestingT) *Assertions {
|
|||
}
|
||||
}
|
||||
|
||||
//go:generate go run ../_codegen/main.go -output-package=assert -template=assertion_forward.go.tmpl -include-format-funcs
|
||||
//go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=assert -template=assertion_forward.go.tmpl -include-format-funcs"
|
||||
|
|
|
|||
2
vendor/github.com/stretchr/testify/require/forward_requirements.go
generated
vendored
2
vendor/github.com/stretchr/testify/require/forward_requirements.go
generated
vendored
|
|
@ -13,4 +13,4 @@ func New(t TestingT) *Assertions {
|
|||
}
|
||||
}
|
||||
|
||||
//go:generate go run ../_codegen/main.go -output-package=require -template=require_forward.go.tmpl -include-format-funcs
|
||||
//go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=require -template=require_forward.go.tmpl -include-format-funcs"
|
||||
|
|
|
|||
210
vendor/github.com/stretchr/testify/require/require.go
generated
vendored
210
vendor/github.com/stretchr/testify/require/require.go
generated
vendored
|
|
@ -66,7 +66,8 @@ func Containsf(t TestingT, s interface{}, contains interface{}, msg string, args
|
|||
t.FailNow()
|
||||
}
|
||||
|
||||
// DirExists checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists.
|
||||
// DirExists checks whether a directory exists in the given path. It also fails
|
||||
// if the path is a file rather a directory or there is an error checking whether it exists.
|
||||
func DirExists(t TestingT, path string, msgAndArgs ...interface{}) {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
|
|
@ -77,7 +78,8 @@ func DirExists(t TestingT, path string, msgAndArgs ...interface{}) {
|
|||
t.FailNow()
|
||||
}
|
||||
|
||||
// DirExistsf checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists.
|
||||
// DirExistsf checks whether a directory exists in the given path. It also fails
|
||||
// if the path is a file rather a directory or there is an error checking whether it exists.
|
||||
func DirExistsf(t TestingT, path string, msg string, args ...interface{}) {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
|
|
@ -275,12 +277,12 @@ func Errorf(t TestingT, err error, msg string, args ...interface{}) {
|
|||
//
|
||||
// assert.Eventually(t, func() bool { return true; }, time.Second, 10*time.Millisecond)
|
||||
func Eventually(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) {
|
||||
if assert.Eventually(t, condition, waitFor, tick, msgAndArgs...) {
|
||||
return
|
||||
}
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
if assert.Eventually(t, condition, waitFor, tick, msgAndArgs...) {
|
||||
return
|
||||
}
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
|
|
@ -289,12 +291,12 @@ func Eventually(t TestingT, condition func() bool, waitFor time.Duration, tick t
|
|||
//
|
||||
// assert.Eventuallyf(t, func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted")
|
||||
func Eventuallyf(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) {
|
||||
if assert.Eventuallyf(t, condition, waitFor, tick, msg, args...) {
|
||||
return
|
||||
}
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
if assert.Eventuallyf(t, condition, waitFor, tick, msg, args...) {
|
||||
return
|
||||
}
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
|
|
@ -394,7 +396,8 @@ func Falsef(t TestingT, value bool, msg string, args ...interface{}) {
|
|||
t.FailNow()
|
||||
}
|
||||
|
||||
// FileExists checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file.
|
||||
// FileExists checks whether a file exists in the given path. It also fails if
|
||||
// the path points to a directory or there is an error when trying to check the file.
|
||||
func FileExists(t TestingT, path string, msgAndArgs ...interface{}) {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
|
|
@ -405,7 +408,8 @@ func FileExists(t TestingT, path string, msgAndArgs ...interface{}) {
|
|||
t.FailNow()
|
||||
}
|
||||
|
||||
// FileExistsf checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file.
|
||||
// FileExistsf checks whether a file exists in the given path. It also fails if
|
||||
// the path points to a directory or there is an error when trying to check the file.
|
||||
func FileExistsf(t TestingT, path string, msg string, args ...interface{}) {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
|
|
@ -660,7 +664,7 @@ func Implementsf(t TestingT, interfaceObject interface{}, object interface{}, ms
|
|||
|
||||
// InDelta asserts that the two numerals are within delta of each other.
|
||||
//
|
||||
// assert.InDelta(t, math.Pi, (22 / 7.0), 0.01)
|
||||
// assert.InDelta(t, math.Pi, 22/7.0, 0.01)
|
||||
func InDelta(t TestingT, expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
|
|
@ -717,7 +721,7 @@ func InDeltaSlicef(t TestingT, expected interface{}, actual interface{}, delta f
|
|||
|
||||
// InDeltaf asserts that the two numerals are within delta of each other.
|
||||
//
|
||||
// assert.InDeltaf(t, math.Pi, (22 / 7.0, "error message %s", "formatted"), 0.01)
|
||||
// assert.InDeltaf(t, math.Pi, 22/7.0, 0.01, "error message %s", "formatted")
|
||||
func InDeltaf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
|
|
@ -820,28 +824,6 @@ func JSONEqf(t TestingT, expected string, actual string, msg string, args ...int
|
|||
t.FailNow()
|
||||
}
|
||||
|
||||
// YAMLEq asserts that two YAML strings are equivalent.
|
||||
func YAMLEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
if assert.YAMLEq(t, expected, actual, msgAndArgs...) {
|
||||
return
|
||||
}
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
// YAMLEqf asserts that two YAML strings are equivalent.
|
||||
func YAMLEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
if assert.YAMLEqf(t, expected, actual, msg, args...) {
|
||||
return
|
||||
}
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
// Len asserts that the specified object has specific length.
|
||||
// Len also fails if the object has a type that len() not accept.
|
||||
//
|
||||
|
|
@ -932,6 +914,34 @@ func Lessf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...inter
|
|||
t.FailNow()
|
||||
}
|
||||
|
||||
// Never asserts that the given condition doesn't satisfy in waitFor time,
|
||||
// periodically checking the target function each tick.
|
||||
//
|
||||
// assert.Never(t, func() bool { return false; }, time.Second, 10*time.Millisecond)
|
||||
func Never(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
if assert.Never(t, condition, waitFor, tick, msgAndArgs...) {
|
||||
return
|
||||
}
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
// Neverf asserts that the given condition doesn't satisfy in waitFor time,
|
||||
// periodically checking the target function each tick.
|
||||
//
|
||||
// assert.Neverf(t, func() bool { return false; }, time.Second, 10*time.Millisecond, "error message %s", "formatted")
|
||||
func Neverf(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
if assert.Neverf(t, condition, waitFor, tick, msg, args...) {
|
||||
return
|
||||
}
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
// Nil asserts that the specified object is nil.
|
||||
//
|
||||
// assert.Nil(t, err)
|
||||
|
|
@ -958,6 +968,30 @@ func Nilf(t TestingT, object interface{}, msg string, args ...interface{}) {
|
|||
t.FailNow()
|
||||
}
|
||||
|
||||
// NoDirExists checks whether a directory does not exist in the given path.
|
||||
// It fails if the path points to an existing _directory_ only.
|
||||
func NoDirExists(t TestingT, path string, msgAndArgs ...interface{}) {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
if assert.NoDirExists(t, path, msgAndArgs...) {
|
||||
return
|
||||
}
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
// NoDirExistsf checks whether a directory does not exist in the given path.
|
||||
// It fails if the path points to an existing _directory_ only.
|
||||
func NoDirExistsf(t TestingT, path string, msg string, args ...interface{}) {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
if assert.NoDirExistsf(t, path, msg, args...) {
|
||||
return
|
||||
}
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
// NoError asserts that a function returned no error (i.e. `nil`).
|
||||
//
|
||||
// actualObj, err := SomeFunction()
|
||||
|
|
@ -990,6 +1024,30 @@ func NoErrorf(t TestingT, err error, msg string, args ...interface{}) {
|
|||
t.FailNow()
|
||||
}
|
||||
|
||||
// NoFileExists checks whether a file does not exist in a given path. It fails
|
||||
// if the path points to an existing _file_ only.
|
||||
func NoFileExists(t TestingT, path string, msgAndArgs ...interface{}) {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
if assert.NoFileExists(t, path, msgAndArgs...) {
|
||||
return
|
||||
}
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
// NoFileExistsf checks whether a file does not exist in a given path. It fails
|
||||
// if the path points to an existing _file_ only.
|
||||
func NoFileExistsf(t TestingT, path string, msg string, args ...interface{}) {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
if assert.NoFileExistsf(t, path, msg, args...) {
|
||||
return
|
||||
}
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
// NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the
|
||||
// specified substring or element.
|
||||
//
|
||||
|
|
@ -1166,6 +1224,38 @@ func NotRegexpf(t TestingT, rx interface{}, str interface{}, msg string, args ..
|
|||
t.FailNow()
|
||||
}
|
||||
|
||||
// NotSame asserts that two pointers do not reference the same object.
|
||||
//
|
||||
// assert.NotSame(t, ptr1, ptr2)
|
||||
//
|
||||
// Both arguments must be pointer variables. Pointer variable sameness is
|
||||
// determined based on the equality of both type and value.
|
||||
func NotSame(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
if assert.NotSame(t, expected, actual, msgAndArgs...) {
|
||||
return
|
||||
}
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
// NotSamef asserts that two pointers do not reference the same object.
|
||||
//
|
||||
// assert.NotSamef(t, ptr1, ptr2, "error message %s", "formatted")
|
||||
//
|
||||
// Both arguments must be pointer variables. Pointer variable sameness is
|
||||
// determined based on the equality of both type and value.
|
||||
func NotSamef(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
if assert.NotSamef(t, expected, actual, msg, args...) {
|
||||
return
|
||||
}
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
// NotSubset asserts that the specified list(array, slice...) contains not all
|
||||
// elements given in the specified subset(array, slice...).
|
||||
//
|
||||
|
|
@ -1229,6 +1319,36 @@ func Panics(t TestingT, f assert.PanicTestFunc, msgAndArgs ...interface{}) {
|
|||
t.FailNow()
|
||||
}
|
||||
|
||||
// PanicsWithError asserts that the code inside the specified PanicTestFunc
|
||||
// panics, and that the recovered panic value is an error that satisfies the
|
||||
// EqualError comparison.
|
||||
//
|
||||
// assert.PanicsWithError(t, "crazy error", func(){ GoCrazy() })
|
||||
func PanicsWithError(t TestingT, errString string, f assert.PanicTestFunc, msgAndArgs ...interface{}) {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
if assert.PanicsWithError(t, errString, f, msgAndArgs...) {
|
||||
return
|
||||
}
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
// PanicsWithErrorf asserts that the code inside the specified PanicTestFunc
|
||||
// panics, and that the recovered panic value is an error that satisfies the
|
||||
// EqualError comparison.
|
||||
//
|
||||
// assert.PanicsWithErrorf(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted")
|
||||
func PanicsWithErrorf(t TestingT, errString string, f assert.PanicTestFunc, msg string, args ...interface{}) {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
if assert.PanicsWithErrorf(t, errString, f, msg, args...) {
|
||||
return
|
||||
}
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
// PanicsWithValue asserts that the code inside the specified PanicTestFunc panics, and that
|
||||
// the recovered panic value equals the expected panic value.
|
||||
//
|
||||
|
|
@ -1410,6 +1530,28 @@ func WithinDurationf(t TestingT, expected time.Time, actual time.Time, delta tim
|
|||
t.FailNow()
|
||||
}
|
||||
|
||||
// YAMLEq asserts that two YAML strings are equivalent.
|
||||
func YAMLEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
if assert.YAMLEq(t, expected, actual, msgAndArgs...) {
|
||||
return
|
||||
}
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
// YAMLEqf asserts that two YAML strings are equivalent.
|
||||
func YAMLEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
if assert.YAMLEqf(t, expected, actual, msg, args...) {
|
||||
return
|
||||
}
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
// Zero asserts that i is the zero value for its type.
|
||||
func Zero(t TestingT, i interface{}, msgAndArgs ...interface{}) {
|
||||
if h, ok := t.(tHelper); ok {
|
||||
|
|
|
|||
156
vendor/github.com/stretchr/testify/require/require_forward.go
generated
vendored
156
vendor/github.com/stretchr/testify/require/require_forward.go
generated
vendored
|
|
@ -54,7 +54,8 @@ func (a *Assertions) Containsf(s interface{}, contains interface{}, msg string,
|
|||
Containsf(a.t, s, contains, msg, args...)
|
||||
}
|
||||
|
||||
// DirExists checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists.
|
||||
// DirExists checks whether a directory exists in the given path. It also fails
|
||||
// if the path is a file rather a directory or there is an error checking whether it exists.
|
||||
func (a *Assertions) DirExists(path string, msgAndArgs ...interface{}) {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
|
|
@ -62,7 +63,8 @@ func (a *Assertions) DirExists(path string, msgAndArgs ...interface{}) {
|
|||
DirExists(a.t, path, msgAndArgs...)
|
||||
}
|
||||
|
||||
// DirExistsf checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists.
|
||||
// DirExistsf checks whether a directory exists in the given path. It also fails
|
||||
// if the path is a file rather a directory or there is an error checking whether it exists.
|
||||
func (a *Assertions) DirExistsf(path string, msg string, args ...interface{}) {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
|
|
@ -310,7 +312,8 @@ func (a *Assertions) Falsef(value bool, msg string, args ...interface{}) {
|
|||
Falsef(a.t, value, msg, args...)
|
||||
}
|
||||
|
||||
// FileExists checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file.
|
||||
// FileExists checks whether a file exists in the given path. It also fails if
|
||||
// the path points to a directory or there is an error when trying to check the file.
|
||||
func (a *Assertions) FileExists(path string, msgAndArgs ...interface{}) {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
|
|
@ -318,7 +321,8 @@ func (a *Assertions) FileExists(path string, msgAndArgs ...interface{}) {
|
|||
FileExists(a.t, path, msgAndArgs...)
|
||||
}
|
||||
|
||||
// FileExistsf checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file.
|
||||
// FileExistsf checks whether a file exists in the given path. It also fails if
|
||||
// the path points to a directory or there is an error when trying to check the file.
|
||||
func (a *Assertions) FileExistsf(path string, msg string, args ...interface{}) {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
|
|
@ -522,7 +526,7 @@ func (a *Assertions) Implementsf(interfaceObject interface{}, object interface{}
|
|||
|
||||
// InDelta asserts that the two numerals are within delta of each other.
|
||||
//
|
||||
// a.InDelta(math.Pi, (22 / 7.0), 0.01)
|
||||
// a.InDelta(math.Pi, 22/7.0, 0.01)
|
||||
func (a *Assertions) InDelta(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
|
|
@ -564,7 +568,7 @@ func (a *Assertions) InDeltaSlicef(expected interface{}, actual interface{}, del
|
|||
|
||||
// InDeltaf asserts that the two numerals are within delta of each other.
|
||||
//
|
||||
// a.InDeltaf(math.Pi, (22 / 7.0, "error message %s", "formatted"), 0.01)
|
||||
// a.InDeltaf(math.Pi, 22/7.0, 0.01, "error message %s", "formatted")
|
||||
func (a *Assertions) InDeltaf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
|
|
@ -640,22 +644,6 @@ func (a *Assertions) JSONEqf(expected string, actual string, msg string, args ..
|
|||
JSONEqf(a.t, expected, actual, msg, args...)
|
||||
}
|
||||
|
||||
// YAMLEq asserts that two YAML strings are equivalent.
|
||||
func (a *Assertions) YAMLEq(expected string, actual string, msgAndArgs ...interface{}) {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
YAMLEq(a.t, expected, actual, msgAndArgs...)
|
||||
}
|
||||
|
||||
// YAMLEqf asserts that two YAML strings are equivalent.
|
||||
func (a *Assertions) YAMLEqf(expected string, actual string, msg string, args ...interface{}) {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
YAMLEqf(a.t, expected, actual, msg, args...)
|
||||
}
|
||||
|
||||
// Len asserts that the specified object has specific length.
|
||||
// Len also fails if the object has a type that len() not accept.
|
||||
//
|
||||
|
|
@ -728,6 +716,28 @@ func (a *Assertions) Lessf(e1 interface{}, e2 interface{}, msg string, args ...i
|
|||
Lessf(a.t, e1, e2, msg, args...)
|
||||
}
|
||||
|
||||
// Never asserts that the given condition doesn't satisfy in waitFor time,
|
||||
// periodically checking the target function each tick.
|
||||
//
|
||||
// a.Never(func() bool { return false; }, time.Second, 10*time.Millisecond)
|
||||
func (a *Assertions) Never(condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
Never(a.t, condition, waitFor, tick, msgAndArgs...)
|
||||
}
|
||||
|
||||
// Neverf asserts that the given condition doesn't satisfy in waitFor time,
|
||||
// periodically checking the target function each tick.
|
||||
//
|
||||
// a.Neverf(func() bool { return false; }, time.Second, 10*time.Millisecond, "error message %s", "formatted")
|
||||
func (a *Assertions) Neverf(condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
Neverf(a.t, condition, waitFor, tick, msg, args...)
|
||||
}
|
||||
|
||||
// Nil asserts that the specified object is nil.
|
||||
//
|
||||
// a.Nil(err)
|
||||
|
|
@ -748,6 +758,24 @@ func (a *Assertions) Nilf(object interface{}, msg string, args ...interface{}) {
|
|||
Nilf(a.t, object, msg, args...)
|
||||
}
|
||||
|
||||
// NoDirExists checks whether a directory does not exist in the given path.
|
||||
// It fails if the path points to an existing _directory_ only.
|
||||
func (a *Assertions) NoDirExists(path string, msgAndArgs ...interface{}) {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
NoDirExists(a.t, path, msgAndArgs...)
|
||||
}
|
||||
|
||||
// NoDirExistsf checks whether a directory does not exist in the given path.
|
||||
// It fails if the path points to an existing _directory_ only.
|
||||
func (a *Assertions) NoDirExistsf(path string, msg string, args ...interface{}) {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
NoDirExistsf(a.t, path, msg, args...)
|
||||
}
|
||||
|
||||
// NoError asserts that a function returned no error (i.e. `nil`).
|
||||
//
|
||||
// actualObj, err := SomeFunction()
|
||||
|
|
@ -774,6 +802,24 @@ func (a *Assertions) NoErrorf(err error, msg string, args ...interface{}) {
|
|||
NoErrorf(a.t, err, msg, args...)
|
||||
}
|
||||
|
||||
// NoFileExists checks whether a file does not exist in a given path. It fails
|
||||
// if the path points to an existing _file_ only.
|
||||
func (a *Assertions) NoFileExists(path string, msgAndArgs ...interface{}) {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
NoFileExists(a.t, path, msgAndArgs...)
|
||||
}
|
||||
|
||||
// NoFileExistsf checks whether a file does not exist in a given path. It fails
|
||||
// if the path points to an existing _file_ only.
|
||||
func (a *Assertions) NoFileExistsf(path string, msg string, args ...interface{}) {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
NoFileExistsf(a.t, path, msg, args...)
|
||||
}
|
||||
|
||||
// NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the
|
||||
// specified substring or element.
|
||||
//
|
||||
|
|
@ -914,6 +960,32 @@ func (a *Assertions) NotRegexpf(rx interface{}, str interface{}, msg string, arg
|
|||
NotRegexpf(a.t, rx, str, msg, args...)
|
||||
}
|
||||
|
||||
// NotSame asserts that two pointers do not reference the same object.
|
||||
//
|
||||
// a.NotSame(ptr1, ptr2)
|
||||
//
|
||||
// Both arguments must be pointer variables. Pointer variable sameness is
|
||||
// determined based on the equality of both type and value.
|
||||
func (a *Assertions) NotSame(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
NotSame(a.t, expected, actual, msgAndArgs...)
|
||||
}
|
||||
|
||||
// NotSamef asserts that two pointers do not reference the same object.
|
||||
//
|
||||
// a.NotSamef(ptr1, ptr2, "error message %s", "formatted")
|
||||
//
|
||||
// Both arguments must be pointer variables. Pointer variable sameness is
|
||||
// determined based on the equality of both type and value.
|
||||
func (a *Assertions) NotSamef(expected interface{}, actual interface{}, msg string, args ...interface{}) {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
NotSamef(a.t, expected, actual, msg, args...)
|
||||
}
|
||||
|
||||
// NotSubset asserts that the specified list(array, slice...) contains not all
|
||||
// elements given in the specified subset(array, slice...).
|
||||
//
|
||||
|
|
@ -962,6 +1034,30 @@ func (a *Assertions) Panics(f assert.PanicTestFunc, msgAndArgs ...interface{}) {
|
|||
Panics(a.t, f, msgAndArgs...)
|
||||
}
|
||||
|
||||
// PanicsWithError asserts that the code inside the specified PanicTestFunc
|
||||
// panics, and that the recovered panic value is an error that satisfies the
|
||||
// EqualError comparison.
|
||||
//
|
||||
// a.PanicsWithError("crazy error", func(){ GoCrazy() })
|
||||
func (a *Assertions) PanicsWithError(errString string, f assert.PanicTestFunc, msgAndArgs ...interface{}) {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
PanicsWithError(a.t, errString, f, msgAndArgs...)
|
||||
}
|
||||
|
||||
// PanicsWithErrorf asserts that the code inside the specified PanicTestFunc
|
||||
// panics, and that the recovered panic value is an error that satisfies the
|
||||
// EqualError comparison.
|
||||
//
|
||||
// a.PanicsWithErrorf("crazy error", func(){ GoCrazy() }, "error message %s", "formatted")
|
||||
func (a *Assertions) PanicsWithErrorf(errString string, f assert.PanicTestFunc, msg string, args ...interface{}) {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
PanicsWithErrorf(a.t, errString, f, msg, args...)
|
||||
}
|
||||
|
||||
// PanicsWithValue asserts that the code inside the specified PanicTestFunc panics, and that
|
||||
// the recovered panic value equals the expected panic value.
|
||||
//
|
||||
|
|
@ -1104,6 +1200,22 @@ func (a *Assertions) WithinDurationf(expected time.Time, actual time.Time, delta
|
|||
WithinDurationf(a.t, expected, actual, delta, msg, args...)
|
||||
}
|
||||
|
||||
// YAMLEq asserts that two YAML strings are equivalent.
|
||||
func (a *Assertions) YAMLEq(expected string, actual string, msgAndArgs ...interface{}) {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
YAMLEq(a.t, expected, actual, msgAndArgs...)
|
||||
}
|
||||
|
||||
// YAMLEqf asserts that two YAML strings are equivalent.
|
||||
func (a *Assertions) YAMLEqf(expected string, actual string, msg string, args ...interface{}) {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
h.Helper()
|
||||
}
|
||||
YAMLEqf(a.t, expected, actual, msg, args...)
|
||||
}
|
||||
|
||||
// Zero asserts that i is the zero value for its type.
|
||||
func (a *Assertions) Zero(i interface{}, msgAndArgs ...interface{}) {
|
||||
if h, ok := a.t.(tHelper); ok {
|
||||
|
|
|
|||
2
vendor/github.com/stretchr/testify/require/requirements.go
generated
vendored
2
vendor/github.com/stretchr/testify/require/requirements.go
generated
vendored
|
|
@ -26,4 +26,4 @@ type BoolAssertionFunc func(TestingT, bool, ...interface{})
|
|||
// for table driven tests.
|
||||
type ErrorAssertionFunc func(TestingT, error, ...interface{})
|
||||
|
||||
//go:generate go run ../_codegen/main.go -output-package=require -template=require.go.tmpl -include-format-funcs
|
||||
//go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=require -template=require.go.tmpl -include-format-funcs"
|
||||
|
|
|
|||
7
vendor/github.com/stretchr/testify/suite/suite.go
generated
vendored
7
vendor/github.com/stretchr/testify/suite/suite.go
generated
vendored
|
|
@ -7,6 +7,7 @@ import (
|
|||
"reflect"
|
||||
"regexp"
|
||||
"runtime/debug"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
|
@ -80,11 +81,12 @@ func (suite *Suite) Run(name string, subtest func()) bool {
|
|||
// Run takes a testing suite and runs all of the tests attached
|
||||
// to it.
|
||||
func Run(t *testing.T, suite TestingSuite) {
|
||||
testsSync := &sync.WaitGroup{}
|
||||
suite.SetT(t)
|
||||
defer failOnPanic(t)
|
||||
|
||||
suiteSetupDone := false
|
||||
|
||||
|
||||
methodFinder := reflect.TypeOf(suite)
|
||||
tests := []testing.InternalTest{}
|
||||
for index := 0; index < methodFinder.NumMethod(); index++ {
|
||||
|
|
@ -103,6 +105,7 @@ func Run(t *testing.T, suite TestingSuite) {
|
|||
}
|
||||
defer func() {
|
||||
if tearDownAllSuite, ok := suite.(TearDownAllSuite); ok {
|
||||
testsSync.Wait()
|
||||
tearDownAllSuite.TearDownSuite()
|
||||
}
|
||||
}()
|
||||
|
|
@ -111,6 +114,7 @@ func Run(t *testing.T, suite TestingSuite) {
|
|||
test := testing.InternalTest{
|
||||
Name: method.Name,
|
||||
F: func(t *testing.T) {
|
||||
defer testsSync.Done()
|
||||
parentT := suite.T()
|
||||
suite.SetT(t)
|
||||
defer failOnPanic(t)
|
||||
|
|
@ -134,6 +138,7 @@ func Run(t *testing.T, suite TestingSuite) {
|
|||
},
|
||||
}
|
||||
tests = append(tests, test)
|
||||
testsSync.Add(1)
|
||||
}
|
||||
runTests(t, tests)
|
||||
}
|
||||
|
|
|
|||
15
vendor/github.com/valyala/bytebufferpool/.travis.yml
generated
vendored
Normal file
15
vendor/github.com/valyala/bytebufferpool/.travis.yml
generated
vendored
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
language: go
|
||||
|
||||
go:
|
||||
- 1.6
|
||||
|
||||
script:
|
||||
# build test for supported platforms
|
||||
- GOOS=linux go build
|
||||
- GOOS=darwin go build
|
||||
- GOOS=freebsd go build
|
||||
- GOOS=windows go build
|
||||
- GOARCH=386 go build
|
||||
|
||||
# run tests on a standard platform
|
||||
- go test -v ./...
|
||||
22
vendor/github.com/valyala/bytebufferpool/LICENSE
generated
vendored
Normal file
22
vendor/github.com/valyala/bytebufferpool/LICENSE
generated
vendored
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Aliaksandr Valialkin, VertaMedia
|
||||
|
||||
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.
|
||||
|
||||
21
vendor/github.com/valyala/bytebufferpool/README.md
generated
vendored
Normal file
21
vendor/github.com/valyala/bytebufferpool/README.md
generated
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
[](https://travis-ci.org/valyala/bytebufferpool)
|
||||
[](http://godoc.org/github.com/valyala/bytebufferpool)
|
||||
[](http://goreportcard.com/report/valyala/bytebufferpool)
|
||||
|
||||
# bytebufferpool
|
||||
|
||||
An implementation of a pool of byte buffers with anti-memory-waste protection.
|
||||
|
||||
The pool may waste limited amount of memory due to fragmentation.
|
||||
This amount equals to the maximum total size of the byte buffers
|
||||
in concurrent use.
|
||||
|
||||
# Benchmark results
|
||||
Currently bytebufferpool is fastest and most effective buffer pool written in Go.
|
||||
|
||||
You can find results [here](https://omgnull.github.io/go-benchmark/buffer/).
|
||||
|
||||
# bytebufferpool users
|
||||
|
||||
* [fasthttp](https://github.com/valyala/fasthttp)
|
||||
* [quicktemplate](https://github.com/valyala/quicktemplate)
|
||||
111
vendor/github.com/valyala/bytebufferpool/bytebuffer.go
generated
vendored
Normal file
111
vendor/github.com/valyala/bytebufferpool/bytebuffer.go
generated
vendored
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
package bytebufferpool
|
||||
|
||||
import "io"
|
||||
|
||||
// ByteBuffer provides byte buffer, which can be used for minimizing
|
||||
// memory allocations.
|
||||
//
|
||||
// ByteBuffer may be used with functions appending data to the given []byte
|
||||
// slice. See example code for details.
|
||||
//
|
||||
// Use Get for obtaining an empty byte buffer.
|
||||
type ByteBuffer struct {
|
||||
|
||||
// B is a byte buffer to use in append-like workloads.
|
||||
// See example code for details.
|
||||
B []byte
|
||||
}
|
||||
|
||||
// Len returns the size of the byte buffer.
|
||||
func (b *ByteBuffer) Len() int {
|
||||
return len(b.B)
|
||||
}
|
||||
|
||||
// ReadFrom implements io.ReaderFrom.
|
||||
//
|
||||
// The function appends all the data read from r to b.
|
||||
func (b *ByteBuffer) ReadFrom(r io.Reader) (int64, error) {
|
||||
p := b.B
|
||||
nStart := int64(len(p))
|
||||
nMax := int64(cap(p))
|
||||
n := nStart
|
||||
if nMax == 0 {
|
||||
nMax = 64
|
||||
p = make([]byte, nMax)
|
||||
} else {
|
||||
p = p[:nMax]
|
||||
}
|
||||
for {
|
||||
if n == nMax {
|
||||
nMax *= 2
|
||||
bNew := make([]byte, nMax)
|
||||
copy(bNew, p)
|
||||
p = bNew
|
||||
}
|
||||
nn, err := r.Read(p[n:])
|
||||
n += int64(nn)
|
||||
if err != nil {
|
||||
b.B = p[:n]
|
||||
n -= nStart
|
||||
if err == io.EOF {
|
||||
return n, nil
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WriteTo implements io.WriterTo.
|
||||
func (b *ByteBuffer) WriteTo(w io.Writer) (int64, error) {
|
||||
n, err := w.Write(b.B)
|
||||
return int64(n), err
|
||||
}
|
||||
|
||||
// Bytes returns b.B, i.e. all the bytes accumulated in the buffer.
|
||||
//
|
||||
// The purpose of this function is bytes.Buffer compatibility.
|
||||
func (b *ByteBuffer) Bytes() []byte {
|
||||
return b.B
|
||||
}
|
||||
|
||||
// Write implements io.Writer - it appends p to ByteBuffer.B
|
||||
func (b *ByteBuffer) Write(p []byte) (int, error) {
|
||||
b.B = append(b.B, p...)
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
// WriteByte appends the byte c to the buffer.
|
||||
//
|
||||
// The purpose of this function is bytes.Buffer compatibility.
|
||||
//
|
||||
// The function always returns nil.
|
||||
func (b *ByteBuffer) WriteByte(c byte) error {
|
||||
b.B = append(b.B, c)
|
||||
return nil
|
||||
}
|
||||
|
||||
// WriteString appends s to ByteBuffer.B.
|
||||
func (b *ByteBuffer) WriteString(s string) (int, error) {
|
||||
b.B = append(b.B, s...)
|
||||
return len(s), nil
|
||||
}
|
||||
|
||||
// Set sets ByteBuffer.B to p.
|
||||
func (b *ByteBuffer) Set(p []byte) {
|
||||
b.B = append(b.B[:0], p...)
|
||||
}
|
||||
|
||||
// SetString sets ByteBuffer.B to s.
|
||||
func (b *ByteBuffer) SetString(s string) {
|
||||
b.B = append(b.B[:0], s...)
|
||||
}
|
||||
|
||||
// String returns string representation of ByteBuffer.B.
|
||||
func (b *ByteBuffer) String() string {
|
||||
return string(b.B)
|
||||
}
|
||||
|
||||
// Reset makes ByteBuffer.B empty.
|
||||
func (b *ByteBuffer) Reset() {
|
||||
b.B = b.B[:0]
|
||||
}
|
||||
7
vendor/github.com/valyala/bytebufferpool/doc.go
generated
vendored
Normal file
7
vendor/github.com/valyala/bytebufferpool/doc.go
generated
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
// Package bytebufferpool implements a pool of byte buffers
|
||||
// with anti-fragmentation protection.
|
||||
//
|
||||
// The pool may waste limited amount of memory due to fragmentation.
|
||||
// This amount equals to the maximum total size of the byte buffers
|
||||
// in concurrent use.
|
||||
package bytebufferpool
|
||||
151
vendor/github.com/valyala/bytebufferpool/pool.go
generated
vendored
Normal file
151
vendor/github.com/valyala/bytebufferpool/pool.go
generated
vendored
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
package bytebufferpool
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
const (
|
||||
minBitSize = 6 // 2**6=64 is a CPU cache line size
|
||||
steps = 20
|
||||
|
||||
minSize = 1 << minBitSize
|
||||
maxSize = 1 << (minBitSize + steps - 1)
|
||||
|
||||
calibrateCallsThreshold = 42000
|
||||
maxPercentile = 0.95
|
||||
)
|
||||
|
||||
// Pool represents byte buffer pool.
|
||||
//
|
||||
// Distinct pools may be used for distinct types of byte buffers.
|
||||
// Properly determined byte buffer types with their own pools may help reducing
|
||||
// memory waste.
|
||||
type Pool struct {
|
||||
calls [steps]uint64
|
||||
calibrating uint64
|
||||
|
||||
defaultSize uint64
|
||||
maxSize uint64
|
||||
|
||||
pool sync.Pool
|
||||
}
|
||||
|
||||
var defaultPool Pool
|
||||
|
||||
// Get returns an empty byte buffer from the pool.
|
||||
//
|
||||
// Got byte buffer may be returned to the pool via Put call.
|
||||
// This reduces the number of memory allocations required for byte buffer
|
||||
// management.
|
||||
func Get() *ByteBuffer { return defaultPool.Get() }
|
||||
|
||||
// Get returns new byte buffer with zero length.
|
||||
//
|
||||
// The byte buffer may be returned to the pool via Put after the use
|
||||
// in order to minimize GC overhead.
|
||||
func (p *Pool) Get() *ByteBuffer {
|
||||
v := p.pool.Get()
|
||||
if v != nil {
|
||||
return v.(*ByteBuffer)
|
||||
}
|
||||
return &ByteBuffer{
|
||||
B: make([]byte, 0, atomic.LoadUint64(&p.defaultSize)),
|
||||
}
|
||||
}
|
||||
|
||||
// Put returns byte buffer to the pool.
|
||||
//
|
||||
// ByteBuffer.B mustn't be touched after returning it to the pool.
|
||||
// Otherwise data races will occur.
|
||||
func Put(b *ByteBuffer) { defaultPool.Put(b) }
|
||||
|
||||
// Put releases byte buffer obtained via Get to the pool.
|
||||
//
|
||||
// The buffer mustn't be accessed after returning to the pool.
|
||||
func (p *Pool) Put(b *ByteBuffer) {
|
||||
idx := index(len(b.B))
|
||||
|
||||
if atomic.AddUint64(&p.calls[idx], 1) > calibrateCallsThreshold {
|
||||
p.calibrate()
|
||||
}
|
||||
|
||||
maxSize := int(atomic.LoadUint64(&p.maxSize))
|
||||
if maxSize == 0 || cap(b.B) <= maxSize {
|
||||
b.Reset()
|
||||
p.pool.Put(b)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Pool) calibrate() {
|
||||
if !atomic.CompareAndSwapUint64(&p.calibrating, 0, 1) {
|
||||
return
|
||||
}
|
||||
|
||||
a := make(callSizes, 0, steps)
|
||||
var callsSum uint64
|
||||
for i := uint64(0); i < steps; i++ {
|
||||
calls := atomic.SwapUint64(&p.calls[i], 0)
|
||||
callsSum += calls
|
||||
a = append(a, callSize{
|
||||
calls: calls,
|
||||
size: minSize << i,
|
||||
})
|
||||
}
|
||||
sort.Sort(a)
|
||||
|
||||
defaultSize := a[0].size
|
||||
maxSize := defaultSize
|
||||
|
||||
maxSum := uint64(float64(callsSum) * maxPercentile)
|
||||
callsSum = 0
|
||||
for i := 0; i < steps; i++ {
|
||||
if callsSum > maxSum {
|
||||
break
|
||||
}
|
||||
callsSum += a[i].calls
|
||||
size := a[i].size
|
||||
if size > maxSize {
|
||||
maxSize = size
|
||||
}
|
||||
}
|
||||
|
||||
atomic.StoreUint64(&p.defaultSize, defaultSize)
|
||||
atomic.StoreUint64(&p.maxSize, maxSize)
|
||||
|
||||
atomic.StoreUint64(&p.calibrating, 0)
|
||||
}
|
||||
|
||||
type callSize struct {
|
||||
calls uint64
|
||||
size uint64
|
||||
}
|
||||
|
||||
type callSizes []callSize
|
||||
|
||||
func (ci callSizes) Len() int {
|
||||
return len(ci)
|
||||
}
|
||||
|
||||
func (ci callSizes) Less(i, j int) bool {
|
||||
return ci[i].calls > ci[j].calls
|
||||
}
|
||||
|
||||
func (ci callSizes) Swap(i, j int) {
|
||||
ci[i], ci[j] = ci[j], ci[i]
|
||||
}
|
||||
|
||||
func index(n int) int {
|
||||
n--
|
||||
n >>= minBitSize
|
||||
idx := 0
|
||||
for n > 0 {
|
||||
n >>= 1
|
||||
idx++
|
||||
}
|
||||
if idx >= steps {
|
||||
idx = steps - 1
|
||||
}
|
||||
return idx
|
||||
}
|
||||
22
vendor/github.com/valyala/fasttemplate/LICENSE
generated
vendored
Normal file
22
vendor/github.com/valyala/fasttemplate/LICENSE
generated
vendored
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Aliaksandr Valialkin
|
||||
|
||||
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.
|
||||
|
||||
85
vendor/github.com/valyala/fasttemplate/README.md
generated
vendored
Normal file
85
vendor/github.com/valyala/fasttemplate/README.md
generated
vendored
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
fasttemplate
|
||||
============
|
||||
|
||||
Simple and fast template engine for Go.
|
||||
|
||||
Fasttemplate performs only a single task - it substitutes template placeholders
|
||||
with user-defined values. At high speed :)
|
||||
|
||||
Take a look at [quicktemplate](https://github.com/valyala/quicktemplate) if you need fast yet powerful html template engine.
|
||||
|
||||
*Please note that fasttemplate doesn't do any escaping on template values
|
||||
unlike [html/template](http://golang.org/pkg/html/template/) do. So values
|
||||
must be properly escaped before passing them to fasttemplate.*
|
||||
|
||||
Fasttemplate is faster than [text/template](http://golang.org/pkg/text/template/),
|
||||
[strings.Replace](http://golang.org/pkg/strings/#Replace),
|
||||
[strings.Replacer](http://golang.org/pkg/strings/#Replacer)
|
||||
and [fmt.Fprintf](https://golang.org/pkg/fmt/#Fprintf) on placeholders' substitution.
|
||||
|
||||
Below are benchmark results comparing fasttemplate performance to text/template,
|
||||
strings.Replace, strings.Replacer and fmt.Fprintf:
|
||||
|
||||
```
|
||||
$ go test -bench=. -benchmem
|
||||
PASS
|
||||
BenchmarkFmtFprintf-4 2000000 790 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkStringsReplace-4 500000 3474 ns/op 2112 B/op 14 allocs/op
|
||||
BenchmarkStringsReplacer-4 500000 2657 ns/op 2256 B/op 23 allocs/op
|
||||
BenchmarkTextTemplate-4 500000 3333 ns/op 336 B/op 19 allocs/op
|
||||
BenchmarkFastTemplateExecuteFunc-4 5000000 349 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkFastTemplateExecute-4 3000000 383 ns/op 0 B/op 0 allocs/op
|
||||
BenchmarkFastTemplateExecuteFuncString-4 3000000 549 ns/op 144 B/op 1 allocs/op
|
||||
BenchmarkFastTemplateExecuteString-4 3000000 572 ns/op 144 B/op 1 allocs/op
|
||||
BenchmarkFastTemplateExecuteTagFunc-4 2000000 743 ns/op 144 B/op 3 allocs/op
|
||||
```
|
||||
|
||||
|
||||
Docs
|
||||
====
|
||||
|
||||
See http://godoc.org/github.com/valyala/fasttemplate .
|
||||
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
```go
|
||||
template := "http://{{host}}/?q={{query}}&foo={{bar}}{{bar}}"
|
||||
t := fasttemplate.New(template, "{{", "}}")
|
||||
s := t.ExecuteString(map[string]interface{}{
|
||||
"host": "google.com",
|
||||
"query": url.QueryEscape("hello=world"),
|
||||
"bar": "foobar",
|
||||
})
|
||||
fmt.Printf("%s", s)
|
||||
|
||||
// Output:
|
||||
// http://google.com/?q=hello%3Dworld&foo=foobarfoobar
|
||||
```
|
||||
|
||||
|
||||
Advanced usage
|
||||
==============
|
||||
|
||||
```go
|
||||
template := "Hello, [user]! You won [prize]!!! [foobar]"
|
||||
t, err := fasttemplate.NewTemplate(template, "[", "]")
|
||||
if err != nil {
|
||||
log.Fatalf("unexpected error when parsing template: %s", err)
|
||||
}
|
||||
s := t.ExecuteFuncString(func(w io.Writer, tag string) (int, error) {
|
||||
switch tag {
|
||||
case "user":
|
||||
return w.Write([]byte("John"))
|
||||
case "prize":
|
||||
return w.Write([]byte("$100500"))
|
||||
default:
|
||||
return w.Write([]byte(fmt.Sprintf("[unknown tag %q]", tag)))
|
||||
}
|
||||
})
|
||||
fmt.Printf("%s", s)
|
||||
|
||||
// Output:
|
||||
// Hello, John! You won $100500!!! [unknown tag "foobar"]
|
||||
```
|
||||
3
vendor/github.com/valyala/fasttemplate/go.mod
generated
vendored
Normal file
3
vendor/github.com/valyala/fasttemplate/go.mod
generated
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
module github.com/valyala/fasttemplate
|
||||
|
||||
require github.com/valyala/bytebufferpool v1.0.0
|
||||
2
vendor/github.com/valyala/fasttemplate/go.sum
generated
vendored
Normal file
2
vendor/github.com/valyala/fasttemplate/go.sum
generated
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
317
vendor/github.com/valyala/fasttemplate/template.go
generated
vendored
Normal file
317
vendor/github.com/valyala/fasttemplate/template.go
generated
vendored
Normal file
|
|
@ -0,0 +1,317 @@
|
|||
// Package fasttemplate implements simple and fast template library.
|
||||
//
|
||||
// Fasttemplate is faster than text/template, strings.Replace
|
||||
// and strings.Replacer.
|
||||
//
|
||||
// Fasttemplate ideally fits for fast and simple placeholders' substitutions.
|
||||
package fasttemplate
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/valyala/bytebufferpool"
|
||||
"io"
|
||||
)
|
||||
|
||||
// ExecuteFunc calls f on each template tag (placeholder) occurrence.
|
||||
//
|
||||
// Returns the number of bytes written to w.
|
||||
//
|
||||
// This function is optimized for constantly changing templates.
|
||||
// Use Template.ExecuteFunc for frozen templates.
|
||||
func ExecuteFunc(template, startTag, endTag string, w io.Writer, f TagFunc) (int64, error) {
|
||||
s := unsafeString2Bytes(template)
|
||||
a := unsafeString2Bytes(startTag)
|
||||
b := unsafeString2Bytes(endTag)
|
||||
|
||||
var nn int64
|
||||
var ni int
|
||||
var err error
|
||||
for {
|
||||
n := bytes.Index(s, a)
|
||||
if n < 0 {
|
||||
break
|
||||
}
|
||||
ni, err = w.Write(s[:n])
|
||||
nn += int64(ni)
|
||||
if err != nil {
|
||||
return nn, err
|
||||
}
|
||||
|
||||
s = s[n+len(a):]
|
||||
n = bytes.Index(s, b)
|
||||
if n < 0 {
|
||||
// cannot find end tag - just write it to the output.
|
||||
ni, _ = w.Write(a)
|
||||
nn += int64(ni)
|
||||
break
|
||||
}
|
||||
|
||||
ni, err = f(w, unsafeBytes2String(s[:n]))
|
||||
nn += int64(ni)
|
||||
s = s[n+len(b):]
|
||||
}
|
||||
ni, err = w.Write(s)
|
||||
nn += int64(ni)
|
||||
|
||||
return nn, err
|
||||
}
|
||||
|
||||
// Execute substitutes template tags (placeholders) with the corresponding
|
||||
// values from the map m and writes the result to the given writer w.
|
||||
//
|
||||
// Substitution map m may contain values with the following types:
|
||||
// * []byte - the fastest value type
|
||||
// * string - convenient value type
|
||||
// * TagFunc - flexible value type
|
||||
//
|
||||
// Returns the number of bytes written to w.
|
||||
//
|
||||
// This function is optimized for constantly changing templates.
|
||||
// Use Template.Execute for frozen templates.
|
||||
func Execute(template, startTag, endTag string, w io.Writer, m map[string]interface{}) (int64, error) {
|
||||
return ExecuteFunc(template, startTag, endTag, w, func(w io.Writer, tag string) (int, error) { return stdTagFunc(w, tag, m) })
|
||||
}
|
||||
|
||||
// ExecuteFuncString calls f on each template tag (placeholder) occurrence
|
||||
// and substitutes it with the data written to TagFunc's w.
|
||||
//
|
||||
// Returns the resulting string.
|
||||
//
|
||||
// This function is optimized for constantly changing templates.
|
||||
// Use Template.ExecuteFuncString for frozen templates.
|
||||
func ExecuteFuncString(template, startTag, endTag string, f TagFunc) string {
|
||||
tagsCount := bytes.Count(unsafeString2Bytes(template), unsafeString2Bytes(startTag))
|
||||
if tagsCount == 0 {
|
||||
return template
|
||||
}
|
||||
|
||||
bb := byteBufferPool.Get()
|
||||
if _, err := ExecuteFunc(template, startTag, endTag, bb, f); err != nil {
|
||||
panic(fmt.Sprintf("unexpected error: %s", err))
|
||||
}
|
||||
s := string(bb.B)
|
||||
bb.Reset()
|
||||
byteBufferPool.Put(bb)
|
||||
return s
|
||||
}
|
||||
|
||||
var byteBufferPool bytebufferpool.Pool
|
||||
|
||||
// ExecuteString substitutes template tags (placeholders) with the corresponding
|
||||
// values from the map m and returns the result.
|
||||
//
|
||||
// Substitution map m may contain values with the following types:
|
||||
// * []byte - the fastest value type
|
||||
// * string - convenient value type
|
||||
// * TagFunc - flexible value type
|
||||
//
|
||||
// This function is optimized for constantly changing templates.
|
||||
// Use Template.ExecuteString for frozen templates.
|
||||
func ExecuteString(template, startTag, endTag string, m map[string]interface{}) string {
|
||||
return ExecuteFuncString(template, startTag, endTag, func(w io.Writer, tag string) (int, error) { return stdTagFunc(w, tag, m) })
|
||||
}
|
||||
|
||||
// Template implements simple template engine, which can be used for fast
|
||||
// tags' (aka placeholders) substitution.
|
||||
type Template struct {
|
||||
template string
|
||||
startTag string
|
||||
endTag string
|
||||
|
||||
texts [][]byte
|
||||
tags []string
|
||||
byteBufferPool bytebufferpool.Pool
|
||||
}
|
||||
|
||||
// New parses the given template using the given startTag and endTag
|
||||
// as tag start and tag end.
|
||||
//
|
||||
// The returned template can be executed by concurrently running goroutines
|
||||
// using Execute* methods.
|
||||
//
|
||||
// New panics if the given template cannot be parsed. Use NewTemplate instead
|
||||
// if template may contain errors.
|
||||
func New(template, startTag, endTag string) *Template {
|
||||
t, err := NewTemplate(template, startTag, endTag)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
// NewTemplate parses the given template using the given startTag and endTag
|
||||
// as tag start and tag end.
|
||||
//
|
||||
// The returned template can be executed by concurrently running goroutines
|
||||
// using Execute* methods.
|
||||
func NewTemplate(template, startTag, endTag string) (*Template, error) {
|
||||
var t Template
|
||||
err := t.Reset(template, startTag, endTag)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &t, nil
|
||||
}
|
||||
|
||||
// TagFunc can be used as a substitution value in the map passed to Execute*.
|
||||
// Execute* functions pass tag (placeholder) name in 'tag' argument.
|
||||
//
|
||||
// TagFunc must be safe to call from concurrently running goroutines.
|
||||
//
|
||||
// TagFunc must write contents to w and return the number of bytes written.
|
||||
type TagFunc func(w io.Writer, tag string) (int, error)
|
||||
|
||||
// Reset resets the template t to new one defined by
|
||||
// template, startTag and endTag.
|
||||
//
|
||||
// Reset allows Template object re-use.
|
||||
//
|
||||
// Reset may be called only if no other goroutines call t methods at the moment.
|
||||
func (t *Template) Reset(template, startTag, endTag string) error {
|
||||
// Keep these vars in t, so GC won't collect them and won't break
|
||||
// vars derived via unsafe*
|
||||
t.template = template
|
||||
t.startTag = startTag
|
||||
t.endTag = endTag
|
||||
t.texts = t.texts[:0]
|
||||
t.tags = t.tags[:0]
|
||||
|
||||
if len(startTag) == 0 {
|
||||
panic("startTag cannot be empty")
|
||||
}
|
||||
if len(endTag) == 0 {
|
||||
panic("endTag cannot be empty")
|
||||
}
|
||||
|
||||
s := unsafeString2Bytes(template)
|
||||
a := unsafeString2Bytes(startTag)
|
||||
b := unsafeString2Bytes(endTag)
|
||||
|
||||
tagsCount := bytes.Count(s, a)
|
||||
if tagsCount == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if tagsCount+1 > cap(t.texts) {
|
||||
t.texts = make([][]byte, 0, tagsCount+1)
|
||||
}
|
||||
if tagsCount > cap(t.tags) {
|
||||
t.tags = make([]string, 0, tagsCount)
|
||||
}
|
||||
|
||||
for {
|
||||
n := bytes.Index(s, a)
|
||||
if n < 0 {
|
||||
t.texts = append(t.texts, s)
|
||||
break
|
||||
}
|
||||
t.texts = append(t.texts, s[:n])
|
||||
|
||||
s = s[n+len(a):]
|
||||
n = bytes.Index(s, b)
|
||||
if n < 0 {
|
||||
return fmt.Errorf("Cannot find end tag=%q in the template=%q starting from %q", endTag, template, s)
|
||||
}
|
||||
|
||||
t.tags = append(t.tags, unsafeBytes2String(s[:n]))
|
||||
s = s[n+len(b):]
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ExecuteFunc calls f on each template tag (placeholder) occurrence.
|
||||
//
|
||||
// Returns the number of bytes written to w.
|
||||
//
|
||||
// This function is optimized for frozen templates.
|
||||
// Use ExecuteFunc for constantly changing templates.
|
||||
func (t *Template) ExecuteFunc(w io.Writer, f TagFunc) (int64, error) {
|
||||
var nn int64
|
||||
|
||||
n := len(t.texts) - 1
|
||||
if n == -1 {
|
||||
ni, err := w.Write(unsafeString2Bytes(t.template))
|
||||
return int64(ni), err
|
||||
}
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
ni, err := w.Write(t.texts[i])
|
||||
nn += int64(ni)
|
||||
if err != nil {
|
||||
return nn, err
|
||||
}
|
||||
|
||||
ni, err = f(w, t.tags[i])
|
||||
nn += int64(ni)
|
||||
if err != nil {
|
||||
return nn, err
|
||||
}
|
||||
}
|
||||
ni, err := w.Write(t.texts[n])
|
||||
nn += int64(ni)
|
||||
return nn, err
|
||||
}
|
||||
|
||||
// Execute substitutes template tags (placeholders) with the corresponding
|
||||
// values from the map m and writes the result to the given writer w.
|
||||
//
|
||||
// Substitution map m may contain values with the following types:
|
||||
// * []byte - the fastest value type
|
||||
// * string - convenient value type
|
||||
// * TagFunc - flexible value type
|
||||
//
|
||||
// Returns the number of bytes written to w.
|
||||
func (t *Template) Execute(w io.Writer, m map[string]interface{}) (int64, error) {
|
||||
return t.ExecuteFunc(w, func(w io.Writer, tag string) (int, error) { return stdTagFunc(w, tag, m) })
|
||||
}
|
||||
|
||||
// ExecuteFuncString calls f on each template tag (placeholder) occurrence
|
||||
// and substitutes it with the data written to TagFunc's w.
|
||||
//
|
||||
// Returns the resulting string.
|
||||
//
|
||||
// This function is optimized for frozen templates.
|
||||
// Use ExecuteFuncString for constantly changing templates.
|
||||
func (t *Template) ExecuteFuncString(f TagFunc) string {
|
||||
bb := t.byteBufferPool.Get()
|
||||
if _, err := t.ExecuteFunc(bb, f); err != nil {
|
||||
panic(fmt.Sprintf("unexpected error: %s", err))
|
||||
}
|
||||
s := string(bb.Bytes())
|
||||
bb.Reset()
|
||||
t.byteBufferPool.Put(bb)
|
||||
return s
|
||||
}
|
||||
|
||||
// ExecuteString substitutes template tags (placeholders) with the corresponding
|
||||
// values from the map m and returns the result.
|
||||
//
|
||||
// Substitution map m may contain values with the following types:
|
||||
// * []byte - the fastest value type
|
||||
// * string - convenient value type
|
||||
// * TagFunc - flexible value type
|
||||
//
|
||||
// This function is optimized for frozen templates.
|
||||
// Use ExecuteString for constantly changing templates.
|
||||
func (t *Template) ExecuteString(m map[string]interface{}) string {
|
||||
return t.ExecuteFuncString(func(w io.Writer, tag string) (int, error) { return stdTagFunc(w, tag, m) })
|
||||
}
|
||||
|
||||
func stdTagFunc(w io.Writer, tag string, m map[string]interface{}) (int, error) {
|
||||
v := m[tag]
|
||||
if v == nil {
|
||||
return 0, nil
|
||||
}
|
||||
switch value := v.(type) {
|
||||
case []byte:
|
||||
return w.Write(value)
|
||||
case string:
|
||||
return w.Write([]byte(value))
|
||||
case TagFunc:
|
||||
return value(w, tag)
|
||||
default:
|
||||
panic(fmt.Sprintf("tag=%q contains unexpected value type=%#v. Expected []byte, string or TagFunc", tag, v))
|
||||
}
|
||||
}
|
||||
22
vendor/github.com/valyala/fasttemplate/unsafe.go
generated
vendored
Normal file
22
vendor/github.com/valyala/fasttemplate/unsafe.go
generated
vendored
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
// +build !appengine
|
||||
|
||||
package fasttemplate
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func unsafeBytes2String(b []byte) string {
|
||||
return *(*string)(unsafe.Pointer(&b))
|
||||
}
|
||||
|
||||
func unsafeString2Bytes(s string) []byte {
|
||||
sh := (*reflect.StringHeader)(unsafe.Pointer(&s))
|
||||
bh := reflect.SliceHeader{
|
||||
Data: sh.Data,
|
||||
Len: sh.Len,
|
||||
Cap: sh.Len,
|
||||
}
|
||||
return *(*[]byte)(unsafe.Pointer(&bh))
|
||||
}
|
||||
11
vendor/github.com/valyala/fasttemplate/unsafe_gae.go
generated
vendored
Normal file
11
vendor/github.com/valyala/fasttemplate/unsafe_gae.go
generated
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
// +build appengine
|
||||
|
||||
package fasttemplate
|
||||
|
||||
func unsafeBytes2String(b []byte) string {
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func unsafeString2Bytes(s string) []byte {
|
||||
return []byte(s)
|
||||
}
|
||||
1097
vendor/golang.org/x/crypto/acme/acme.go
generated
vendored
Normal file
1097
vendor/golang.org/x/crypto/acme/acme.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
1249
vendor/golang.org/x/crypto/acme/autocert/autocert.go
generated
vendored
Normal file
1249
vendor/golang.org/x/crypto/acme/autocert/autocert.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue