diff options
149 files changed, 5077 insertions, 2271 deletions
@@ -2,11 +2,8 @@ module code.superseriousbusiness.org/gotosocial go 1.24.6 -// Replace go-swagger with our version that fixes (ours particularly) use of Go1.23 -replace github.com/go-swagger/go-swagger => codeberg.org/superseriousbusiness/go-swagger v0.32.3-gts-go1.23-fix - // Replace modernc/sqlite with our version that fixes the concurrency INTERRUPT issue -replace modernc.org/sqlite => gitlab.com/NyaaaWhatsUpDoc/sqlite v1.39.1-concurrency-workaround +replace modernc.org/sqlite => gitlab.com/NyaaaWhatsUpDoc/sqlite v1.40.0-concurrency-workaround require ( code.superseriousbusiness.org/activity v1.17.0 @@ -33,7 +30,7 @@ require ( codeberg.org/gruf/go-storage v0.3.1 codeberg.org/gruf/go-structr v0.9.13 github.com/DmitriyVTitov/size v1.5.0 - github.com/KimMachineGun/automemlimit v0.7.4 + github.com/KimMachineGun/automemlimit v0.7.5 github.com/SherClockHolmes/webpush-go v1.4.0 github.com/buckket/go-blurhash v1.1.0 github.com/coreos/go-oidc/v3 v3.16.0 @@ -62,7 +59,7 @@ require ( github.com/spf13/pflag v1.0.10 github.com/spf13/viper v1.21.0 github.com/stretchr/testify v1.11.1 - github.com/tdewolff/minify/v2 v2.24.4 + github.com/tdewolff/minify/v2 v2.24.5 github.com/temoto/robotstxt v1.1.2 github.com/tetratelabs/wazero v1.9.0 github.com/tomnomnom/linkheader v0.0.0-20250811210735-e5fe3b51442e @@ -89,7 +86,7 @@ require ( golang.org/x/text v0.30.0 gopkg.in/mcuadros/go-syslog.v2 v2.3.0 gopkg.in/yaml.v3 v3.0.1 - modernc.org/sqlite v1.39.1 + modernc.org/sqlite v1.40.0 mvdan.cc/xurls/v2 v2.6.0 ) @@ -100,9 +97,10 @@ require ( codeberg.org/gruf/go-mangler/v2 v2.0.6 // indirect codeberg.org/gruf/go-maps v1.0.4 // indirect codeberg.org/gruf/go-xunsafe v0.0.0-20250809104800-512a9df57d73 // indirect + dario.cat/mergo v1.0.2 // indirect github.com/Masterminds/goutils v1.1.1 // indirect - github.com/Masterminds/semver/v3 v3.2.1 // indirect - github.com/Masterminds/sprig/v3 v3.2.3 // indirect + github.com/Masterminds/semver/v3 v3.4.0 // indirect + github.com/Masterminds/sprig/v3 v3.3.0 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/aymerick/douceur v0.2.0 // indirect github.com/beorn7/perks v1.0.1 // indirect @@ -130,15 +128,15 @@ require ( github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/analysis v0.23.0 // indirect - github.com/go-openapi/errors v0.22.0 // indirect - github.com/go-openapi/inflect v0.21.0 // indirect - github.com/go-openapi/jsonpointer v0.21.0 // indirect + github.com/go-openapi/errors v0.22.2 // indirect + github.com/go-openapi/inflect v0.21.3 // indirect + github.com/go-openapi/jsonpointer v0.21.2 // indirect github.com/go-openapi/jsonreference v0.21.0 // indirect github.com/go-openapi/loads v0.22.0 // indirect github.com/go-openapi/runtime v0.28.0 // indirect github.com/go-openapi/spec v0.21.0 // indirect github.com/go-openapi/strfmt v0.23.0 // indirect - github.com/go-openapi/swag v0.23.0 // indirect + github.com/go-openapi/swag v0.23.1 // indirect github.com/go-openapi/validate v0.24.0 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect @@ -155,13 +153,12 @@ require ( github.com/gorilla/sessions v1.4.0 // indirect github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect - github.com/huandu/xstrings v1.4.0 // indirect - github.com/imdario/mergo v0.3.16 // indirect + github.com/huandu/xstrings v1.5.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect github.com/jackc/puddle/v2 v2.2.2 // indirect - github.com/jessevdk/go-flags v1.5.0 // indirect + github.com/jessevdk/go-flags v1.6.1 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect @@ -170,7 +167,7 @@ require ( github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect github.com/leodido/go-urn v1.4.0 // indirect - github.com/mailru/easyjson v0.7.7 // indirect + github.com/mailru/easyjson v0.9.0 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/minio/crc64nvme v1.0.2 // indirect github.com/minio/md5-simd v1.1.2 // indirect @@ -194,23 +191,23 @@ require ( github.com/puzpuzpuz/xsync/v3 v3.5.1 // indirect github.com/quasoft/memstore v0.0.0-20191010062613-2bce066d2b0b // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect - github.com/rogpeppe/go-internal v1.13.2-0.20241226121412-a5dc8ff20d0a // indirect + github.com/rogpeppe/go-internal v1.14.1 // indirect github.com/rs/xid v1.6.0 // indirect github.com/sagikazarmark/locafero v0.11.0 // indirect - github.com/shopspring/decimal v1.3.1 // indirect + github.com/shopspring/decimal v1.4.0 // indirect github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect github.com/spf13/afero v1.15.0 // indirect github.com/subosito/gotenv v1.6.0 // indirect - github.com/tdewolff/parse/v2 v2.8.4 // indirect + github.com/tdewolff/parse/v2 v2.8.5-0.20251020133559-0efcf90bef1a // indirect github.com/tinylib/msgp v1.3.0 // indirect github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc // indirect - github.com/toqueteos/webbrowser v1.2.0 // indirect + github.com/toqueteos/webbrowser v1.2.1 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.3.0 // indirect github.com/uptrace/opentelemetry-go-extra/otelsql v0.3.2 // indirect github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect - go.mongodb.org/mongo-driver v1.17.3 // indirect + go.mongodb.org/mongo-driver v1.17.4 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/contrib/bridges/prometheus v0.63.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0 // indirect @@ -58,19 +58,18 @@ codeberg.org/gruf/go-structr v0.9.13 h1:tTAR30OnSKrcvBomlGZdwE2nE+cfWhkX8UhX0GTA codeberg.org/gruf/go-structr v0.9.13/go.mod h1:sP2ZSjM5X5XKlxuhAbTKuVQm9DWbHsrQRuTl3MUwbHw= codeberg.org/gruf/go-xunsafe v0.0.0-20250809104800-512a9df57d73 h1:pRaOwIOS1WSZoPCAvE0H1zpv+D4gF37OVppybffqdI8= codeberg.org/gruf/go-xunsafe v0.0.0-20250809104800-512a9df57d73/go.mod h1:9wkq+dmHjUhB/0ZxDUWAwsWuXwwGyx5N1dDCB9hpWs8= -codeberg.org/superseriousbusiness/go-swagger v0.32.3-gts-go1.23-fix h1:k76/Th+bruqU/d+dB0Ru466ctTF2aVjKpisy/471ILE= -codeberg.org/superseriousbusiness/go-swagger v0.32.3-gts-go1.23-fix/go.mod h1:lAwO1nKff3qNRJYVQeTCl1am5pcNiiA2VyDf8TqzS24= +dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8= +dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA= github.com/DmitriyVTitov/size v1.5.0 h1:/PzqxYrOyOUX1BXj6J9OuVRVGe+66VL4D9FlUaW515g= github.com/DmitriyVTitov/size v1.5.0/go.mod h1:le6rNI4CoLQV1b9gzp1+3d7hMAD/uu2QcJ+aYbNgiU0= -github.com/KimMachineGun/automemlimit v0.7.4 h1:UY7QYOIfrr3wjjOAqahFmC3IaQCLWvur9nmfIn6LnWk= -github.com/KimMachineGun/automemlimit v0.7.4/go.mod h1:QZxpHaGOQoYvFhv/r4u3U0JTC2ZcOwbSr11UZF46UBM= +github.com/KimMachineGun/automemlimit v0.7.5 h1:RkbaC0MwhjL1ZuBKunGDjE/ggwAX43DwZrJqVwyveTk= +github.com/KimMachineGun/automemlimit v0.7.5/go.mod h1:QZxpHaGOQoYvFhv/r4u3U0JTC2ZcOwbSr11UZF46UBM= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= -github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= -github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0= -github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= -github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA= -github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM= +github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0= +github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= +github.com/Masterminds/sprig/v3 v3.3.0 h1:mQh0Yrg1XPo6vjYXgtf5OtijNAKJRNcTdOOGZe3tPhs= +github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSCzdgBfDb35Lz0= github.com/SherClockHolmes/webpush-go v1.4.0 h1:ocnzNKWN23T9nvHi6IfyrQjkIc0oJWv1B1pULsf9i3s= github.com/SherClockHolmes/webpush-go v1.4.0/go.mod h1:XSq8pKX11vNV8MJEMwjrlTkxhAj1zKfxmyhdV7Pd6UA= github.com/TylerBrock/colorjson v0.0.0-20200706003622-8a50f05110d2 h1:ZBbLwSJqkHBuFDA6DUhhse0IGJ7T5bemHyNILUjvOq4= @@ -170,12 +169,12 @@ github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-openapi/analysis v0.23.0 h1:aGday7OWupfMs+LbmLZG4k0MYXIANxcuBTYUC03zFCU= github.com/go-openapi/analysis v0.23.0/go.mod h1:9mz9ZWaSlV8TvjQHLl2mUW2PbZtemkE8yA5v22ohupo= -github.com/go-openapi/errors v0.22.0 h1:c4xY/OLxUBSTiepAg3j/MHuAv5mJhnf53LLMWFB+u/w= -github.com/go-openapi/errors v0.22.0/go.mod h1:J3DmZScxCDufmIMsdOuDHxJbdOGC0xtUynjIx092vXE= -github.com/go-openapi/inflect v0.21.0 h1:FoBjBTQEcbg2cJUWX6uwL9OyIW8eqc9k4KhN4lfbeYk= -github.com/go-openapi/inflect v0.21.0/go.mod h1:INezMuUu7SJQc2AyR3WO0DqqYUJSj8Kb4hBd7WtjlAw= -github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= -github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= +github.com/go-openapi/errors v0.22.2 h1:rdxhzcBUazEcGccKqbY1Y7NS8FDcMyIRr0934jrYnZg= +github.com/go-openapi/errors v0.22.2/go.mod h1:+n/5UdIqdVnLIJ6Q9Se8HNGUXYaY6CN8ImWzfi/Gzp0= +github.com/go-openapi/inflect v0.21.3 h1:TmQvw+9eLrsNp4X0BBQacEZZtAnzk2z1FaLdQQJsDiU= +github.com/go-openapi/inflect v0.21.3/go.mod h1:INezMuUu7SJQc2AyR3WO0DqqYUJSj8Kb4hBd7WtjlAw= +github.com/go-openapi/jsonpointer v0.21.2 h1:AqQaNADVwq/VnkCmQg6ogE+M3FOsKTytwges0JdwVuA= +github.com/go-openapi/jsonpointer v0.21.2/go.mod h1:50I1STOfbY1ycR8jGz8DaMeLCdXiI6aDteEdRNNzpdk= github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= github.com/go-openapi/loads v0.22.0 h1:ECPGd4jX1U6NApCGG1We+uEozOAvXvJSF4nnwHZ8Aco= @@ -186,8 +185,8 @@ github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9Z github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk= github.com/go-openapi/strfmt v0.23.0 h1:nlUS6BCqcnAk0pyhi9Y+kdDVZdZMHfEKQiS4HaMgO/c= github.com/go-openapi/strfmt v0.23.0/go.mod h1:NrtIpfKtWIygRkKVsxh7XQMDQW5HKQl6S5ik2elW+K4= -github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= -github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= +github.com/go-openapi/swag v0.23.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU= +github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0= github.com/go-openapi/validate v0.24.0 h1:LdfDKwNbpB6Vn40xhTdNZAnfLECL81w+VX3BumrGD58= github.com/go-openapi/validate v0.24.0/go.mod h1:iyeX1sEufmv3nPbBdX3ieNviWnOZaJ1+zquzJEf2BAQ= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= @@ -200,6 +199,8 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.28.0 h1:Q7ibns33JjyW48gHkuFT91qX48KG0ktULL6FgHdG688= github.com/go-playground/validator/v10 v10.28.0/go.mod h1:GoI6I1SjPBh9p7ykNE/yj3fFYbyDOpwMn5KXd+m2hUU= +github.com/go-swagger/go-swagger v0.33.1 h1:BdtmxCvMxkrYIGAyn/qXPi4j85mFTwG4c9ED/27jtq4= +github.com/go-swagger/go-swagger v0.33.1/go.mod h1:wJK762cSroJbM7hgJtKtbZxfevB3RSF3sC8/hK+kRwc= github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= @@ -232,7 +233,6 @@ github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs= github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= -github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= @@ -256,12 +256,8 @@ github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc h1:GN2Lv3MGO7AS6PrR github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc/go.mod h1:+JKpmjMGhpgPL+rXZ5nsZieVzvarn86asRlBg4uNGnk= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2/go.mod h1:pkJQ2tZHJ0aFOVEEot6oZmaVEZcRme73eIFmhiVuRWs= -github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= -github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU= -github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= -github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= -github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= -github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= +github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI= +github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/imkira/go-interpol v1.1.0 h1:KIiKr0VSG2CUW1hl1jpiyuzuJeKUUpC8iM1AIE7N1Vk= github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= @@ -275,8 +271,8 @@ github.com/jackc/pgx/v5 v5.7.6/go.mod h1:aruU7o91Tc2q2cFp5h4uP3f6ztExVpyVv88Xl/8 github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jessevdk/go-flags v1.5.0 h1:1jKYvbxEjfUl0fmqTCOfonvskHHXMjBySTLW4y9LFvc= -github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= +github.com/jessevdk/go-flags v1.6.1 h1:Cvu5U8UGrLay1rZfv/zP7iLpSHGUZ/Ou68T0iX1bBK4= +github.com/jessevdk/go-flags v1.6.1/go.mod h1:Mk8T1hIAWpOiJiHa9rJASDK2UGWji0EuPGBnNLMooyc= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= @@ -300,8 +296,8 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0 github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= +github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= @@ -316,7 +312,6 @@ github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34= github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM= github.com/minio/minio-go/v7 v7.0.95 h1:ywOUPg+PebTMTzn9VDsoFJy32ZuARN9zhB+K3IYEvYU= github.com/minio/minio-go/v7 v7.0.95/go.mod h1:wOOX3uxS334vImCNRVyIDdXX9OsXDm89ToynKgqUKlo= -github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= @@ -325,7 +320,6 @@ github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4 github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -378,8 +372,8 @@ github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qq github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/rogpeppe/go-internal v1.13.2-0.20241226121412-a5dc8ff20d0a h1:w3tdWGKbLGBPtR/8/oO74W6hmz0qE5q0z9aqSAewaaM= -github.com/rogpeppe/go-internal v1.13.2-0.20241226121412-a5dc8ff20d0a/go.mod h1:S8kfXMp+yh77OxPD4fdM6YUknrZpQxLhvxzS4gDHENY= +github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= +github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU= github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -389,9 +383,8 @@ github.com/sanity-io/litter v1.5.5 h1:iE+sBxPBzoK6uaEP5Lt3fHNgpKcHXc/A2HGETy0uJQ github.com/sanity-io/litter v1.5.5/go.mod h1:9gzJgR2i4ZpjZHsKvUXIRQVk7P+yM3e+jAF7bU2UI5U= github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= -github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= -github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8= -github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= +github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= github.com/smarty/assertions v1.15.0 h1:cR//PqUBUiQRakZWqBiFFQ9wb8emQGDb0HeGdqGByCY= github.com/smarty/assertions v1.15.0/go.mod h1:yABtdzeQs6l1brC900WlRNwj6ZR55d7B+E8C6HtKdec= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= @@ -402,7 +395,6 @@ github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrel github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U= github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg= -github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY= github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo= github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s= @@ -415,9 +407,7 @@ github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjb github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= @@ -426,10 +416,10 @@ github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= -github.com/tdewolff/minify/v2 v2.24.4 h1:pQyr6eWDa+RXtAoZg+6wurh0jB9ojqw/qc5LlU7/z6c= -github.com/tdewolff/minify/v2 v2.24.4/go.mod h1:iD9Qn7/brhKY9d0KLKMkZrqS8/bqxSxRKruBi7V6m+w= -github.com/tdewolff/parse/v2 v2.8.4 h1:A6slgBLGGDPBMGA28KQZfHpaKffuNvhOe7zSag+x/rw= -github.com/tdewolff/parse/v2 v2.8.4/go.mod h1:Hwlni2tiVNKyzR1o6nUs4FOF07URA+JLBLd6dlIXYqo= +github.com/tdewolff/minify/v2 v2.24.5 h1:ytxthX3xSxrK3Xx5B38flg5moCKs/dB8VwiD/RzJViU= +github.com/tdewolff/minify/v2 v2.24.5/go.mod h1:q09KtNnVai7TyEzGEZeWPAnK+c8Z+NI8prCXZW652bo= +github.com/tdewolff/parse/v2 v2.8.5-0.20251020133559-0efcf90bef1a h1:Rmq+utdraciok/97XHRweYdsAo/M4LOswpCboo3yvN4= +github.com/tdewolff/parse/v2 v2.8.5-0.20251020133559-0efcf90bef1a/go.mod h1:Hwlni2tiVNKyzR1o6nUs4FOF07URA+JLBLd6dlIXYqo= github.com/tdewolff/test v1.0.11 h1:FdLbwQVHxqG16SlkGveC0JVyrJN62COWTRyUFzfbtBE= github.com/tdewolff/test v1.0.11/go.mod h1:XPuWBzvdUzhCuxWO1ojpXsyzsA5bFoS3tO/Q3kFuTG8= github.com/temoto/robotstxt v1.1.2 h1:W2pOjSJ6SWvldyEuiFXNxz3xZ8aiWX5LbfDiOFd7Fxg= @@ -458,8 +448,8 @@ github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc h1:9lRDQMhESg+zvGYm github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc/go.mod h1:bciPuU6GHm1iF1pBvUfxfsH0Wmnc2VbpgvbI9ZWuIRs= github.com/tomnomnom/linkheader v0.0.0-20250811210735-e5fe3b51442e h1:tD38/4xg4nuQCASJ/JxcvCHNb46w0cdAaJfkzQOO1bA= github.com/tomnomnom/linkheader v0.0.0-20250811210735-e5fe3b51442e/go.mod h1:krvJ5AY/MjdPkTeRgMYbIDhbbbVvnPQPzsIsDJO8xrY= -github.com/toqueteos/webbrowser v1.2.0 h1:tVP/gpK69Fx+qMJKsLE7TD8LuGWPnEV71wBN9rrstGQ= -github.com/toqueteos/webbrowser v1.2.0/go.mod h1:XWoZq4cyp9WeUeak7w7LXRUQf1F1ATJMir8RTqb4ayM= +github.com/toqueteos/webbrowser v1.2.1 h1:O7IsnnU7XQyJ1nHMRfAktUUJOAZD3aQyUVnxzhWphCg= +github.com/toqueteos/webbrowser v1.2.1/go.mod h1:XWoZq4cyp9WeUeak7w7LXRUQf1F1ATJMir8RTqb4ayM= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go/codec v1.3.0 h1:Qd2W2sQawAfG8XSvzwhBeoGq71zXOC/Q1E9y/wUcsUA= @@ -503,10 +493,10 @@ github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDf github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/goldmark v1.7.13 h1:GPddIs617DnBLFFVJFgpo1aBfe/4xcvMc3SB5t/D0pA= github.com/yuin/goldmark v1.7.13/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg= -gitlab.com/NyaaaWhatsUpDoc/sqlite v1.39.1-concurrency-workaround h1:ptkkB4Z76pmpmLE7vmp5BVOfO5o5+Kt0eGFhNbvVxjA= -gitlab.com/NyaaaWhatsUpDoc/sqlite v1.39.1-concurrency-workaround/go.mod h1:9fjQZ0mB1LLP0GYrp39oOJXx/I2sxEnZtzCmEQIKvGE= -go.mongodb.org/mongo-driver v1.17.3 h1:TQyXhnsWfWtgAhMtOgtYHMTkZIfBTpMTsMnd9ZBeHxQ= -go.mongodb.org/mongo-driver v1.17.3/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ= +gitlab.com/NyaaaWhatsUpDoc/sqlite v1.40.0-concurrency-workaround h1:RCxabWH2xbAyFjBsvmX/IC/HVJf48co9QZphvMb93wo= +gitlab.com/NyaaaWhatsUpDoc/sqlite v1.40.0-concurrency-workaround/go.mod h1:9fjQZ0mB1LLP0GYrp39oOJXx/I2sxEnZtzCmEQIKvGE= +go.mongodb.org/mongo-driver v1.17.4 h1:jUorfmVzljjr0FLzYQsGP8cgN/qzzxlY9Vh0C9KFXVw= +go.mongodb.org/mongo-driver v1.17.4/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/contrib/bridges/prometheus v0.63.0 h1:/Rij/t18Y7rUayNg7Id6rPrEnHgorxYabm2E6wUdPP4= @@ -565,7 +555,6 @@ golang.org/x/arch v0.22.0 h1:c/Zle32i5ttqRXjdLyyHZESLD/bB90DCU1g9l/0YBDI= golang.org/x/arch v0.22.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= @@ -592,7 +581,6 @@ golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= @@ -614,11 +602,9 @@ golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -631,7 +617,6 @@ golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= @@ -643,7 +628,6 @@ golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= @@ -677,7 +661,6 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/mcuadros/go-syslog.v2 v2.3.0 h1:kcsiS+WsTKyIEPABJBJtoG0KkOS6yzvJ+/eZlhD79kk= gopkg.in/mcuadros/go-syslog.v2 v2.3.0/go.mod h1:l5LPIyOOyIdQquNg+oU6Z3524YwrcqEm0aKH+5zpt2U= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= diff --git a/vendor/github.com/imdario/mergo/.deepsource.toml b/vendor/dario.cat/mergo/.deepsource.toml index 8a0681af8..a8bc979e0 100644 --- a/vendor/github.com/imdario/mergo/.deepsource.toml +++ b/vendor/dario.cat/mergo/.deepsource.toml @@ -9,4 +9,4 @@ name = "go" enabled = true [analyzers.meta] - import_path = "github.com/imdario/mergo"
\ No newline at end of file + import_path = "dario.cat/mergo"
\ No newline at end of file diff --git a/vendor/github.com/imdario/mergo/.gitignore b/vendor/dario.cat/mergo/.gitignore index 529c3412b..45ad0f1ae 100644 --- a/vendor/github.com/imdario/mergo/.gitignore +++ b/vendor/dario.cat/mergo/.gitignore @@ -13,6 +13,9 @@ # Output of the go coverage tool, specifically when used with LiteIDE *.out +# Golang/Intellij +.idea + # Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736 .glide/ diff --git a/vendor/github.com/imdario/mergo/.travis.yml b/vendor/dario.cat/mergo/.travis.yml index d324c43ba..d324c43ba 100644 --- a/vendor/github.com/imdario/mergo/.travis.yml +++ b/vendor/dario.cat/mergo/.travis.yml diff --git a/vendor/github.com/imdario/mergo/CODE_OF_CONDUCT.md b/vendor/dario.cat/mergo/CODE_OF_CONDUCT.md index 469b44907..469b44907 100644 --- a/vendor/github.com/imdario/mergo/CODE_OF_CONDUCT.md +++ b/vendor/dario.cat/mergo/CODE_OF_CONDUCT.md diff --git a/vendor/github.com/imdario/mergo/CONTRIBUTING.md b/vendor/dario.cat/mergo/CONTRIBUTING.md index 0a1ff9f94..0a1ff9f94 100644 --- a/vendor/github.com/imdario/mergo/CONTRIBUTING.md +++ b/vendor/dario.cat/mergo/CONTRIBUTING.md diff --git a/vendor/dario.cat/mergo/FUNDING.json b/vendor/dario.cat/mergo/FUNDING.json new file mode 100644 index 000000000..0585e1fe1 --- /dev/null +++ b/vendor/dario.cat/mergo/FUNDING.json @@ -0,0 +1,7 @@ +{ + "drips": { + "ethereum": { + "ownedBy": "0x6160020e7102237aC41bdb156e94401692D76930" + } + } +} diff --git a/vendor/github.com/imdario/mergo/LICENSE b/vendor/dario.cat/mergo/LICENSE index 686680298..686680298 100644 --- a/vendor/github.com/imdario/mergo/LICENSE +++ b/vendor/dario.cat/mergo/LICENSE diff --git a/vendor/github.com/imdario/mergo/README.md b/vendor/dario.cat/mergo/README.md index ffbbb62c7..0e4a59afd 100644 --- a/vendor/github.com/imdario/mergo/README.md +++ b/vendor/dario.cat/mergo/README.md @@ -44,77 +44,59 @@ Also a lovely [comune](http://en.wikipedia.org/wiki/Mergo) (municipality) in the ## Status -It is ready for production use. [It is used in several projects by Docker, Google, The Linux Foundation, VMWare, Shopify, Microsoft, etc](https://github.com/imdario/mergo#mergo-in-the-wild). +Mergo is stable and frozen, ready for production. Check a short list of the projects using at large scale it [here](https://github.com/imdario/mergo#mergo-in-the-wild). -### Important note +No new features are accepted. They will be considered for a future v2 that improves the implementation and fixes bugs for corner cases. + +### Important notes + +#### 1.0.0 + +In [1.0.0](//github.com/imdario/mergo/releases/tag/1.0.0) Mergo moves to a vanity URL `dario.cat/mergo`. No more v1 versions will be released. + +If the vanity URL is causing issues in your project due to a dependency pulling Mergo - it isn't a direct dependency in your project - it is recommended to use [replace](https://github.com/golang/go/wiki/Modules#when-should-i-use-the-replace-directive) to pin the version to the last one with the old import URL: + +``` +replace github.com/imdario/mergo => github.com/imdario/mergo v0.3.16 +``` + +#### 0.3.9 Please keep in mind that a problematic PR broke [0.3.9](//github.com/imdario/mergo/releases/tag/0.3.9). I reverted it in [0.3.10](//github.com/imdario/mergo/releases/tag/0.3.10), and I consider it stable but not bug-free. Also, this version adds support for go modules. Keep in mind that in [0.3.2](//github.com/imdario/mergo/releases/tag/0.3.2), Mergo changed `Merge()`and `Map()` signatures to support [transformers](#transformers). I added an optional/variadic argument so that it won't break the existing code. -If you were using Mergo before April 6th, 2015, please check your project works as intended after updating your local copy with ```go get -u github.com/imdario/mergo```. I apologize for any issue caused by its previous behavior and any future bug that Mergo could cause in existing projects after the change (release 0.2.0). +If you were using Mergo before April 6th, 2015, please check your project works as intended after updating your local copy with ```go get -u dario.cat/mergo```. I apologize for any issue caused by its previous behavior and any future bug that Mergo could cause in existing projects after the change (release 0.2.0). ### Donations If Mergo is useful to you, consider buying me a coffee, a beer, or making a monthly donation to allow me to keep building great free software. :heart_eyes: -<a href='https://ko-fi.com/B0B58839' target='_blank'><img height='36' style='border:0px;height:36px;' src='https://az743702.vo.msecnd.net/cdn/kofi1.png?v=0' border='0' alt='Buy Me a Coffee at ko-fi.com' /></a> <a href="https://liberapay.com/dario/donate"><img alt="Donate using Liberapay" src="https://liberapay.com/assets/widgets/donate.svg"></a> <a href='https://github.com/sponsors/imdario' target='_blank'><img alt="Become my sponsor" src="https://img.shields.io/github/sponsors/imdario?style=for-the-badge" /></a> ### Mergo in the wild -- [moby/moby](https://github.com/moby/moby) -- [kubernetes/kubernetes](https://github.com/kubernetes/kubernetes) -- [vmware/dispatch](https://github.com/vmware/dispatch) -- [Shopify/themekit](https://github.com/Shopify/themekit) -- [imdario/zas](https://github.com/imdario/zas) -- [matcornic/hermes](https://github.com/matcornic/hermes) -- [OpenBazaar/openbazaar-go](https://github.com/OpenBazaar/openbazaar-go) -- [kataras/iris](https://github.com/kataras/iris) -- [michaelsauter/crane](https://github.com/michaelsauter/crane) -- [go-task/task](https://github.com/go-task/task) -- [sensu/uchiwa](https://github.com/sensu/uchiwa) -- [ory/hydra](https://github.com/ory/hydra) -- [sisatech/vcli](https://github.com/sisatech/vcli) -- [dairycart/dairycart](https://github.com/dairycart/dairycart) -- [projectcalico/felix](https://github.com/projectcalico/felix) -- [resin-os/balena](https://github.com/resin-os/balena) -- [go-kivik/kivik](https://github.com/go-kivik/kivik) -- [Telefonica/govice](https://github.com/Telefonica/govice) -- [supergiant/supergiant](supergiant/supergiant) -- [SergeyTsalkov/brooce](https://github.com/SergeyTsalkov/brooce) -- [soniah/dnsmadeeasy](https://github.com/soniah/dnsmadeeasy) -- [ohsu-comp-bio/funnel](https://github.com/ohsu-comp-bio/funnel) -- [EagerIO/Stout](https://github.com/EagerIO/Stout) -- [lynndylanhurley/defsynth-api](https://github.com/lynndylanhurley/defsynth-api) -- [russross/canvasassignments](https://github.com/russross/canvasassignments) -- [rdegges/cryptly-api](https://github.com/rdegges/cryptly-api) -- [casualjim/exeggutor](https://github.com/casualjim/exeggutor) -- [divshot/gitling](https://github.com/divshot/gitling) -- [RWJMurphy/gorl](https://github.com/RWJMurphy/gorl) -- [andrerocker/deploy42](https://github.com/andrerocker/deploy42) -- [elwinar/rambler](https://github.com/elwinar/rambler) -- [tmaiaroto/gopartman](https://github.com/tmaiaroto/gopartman) -- [jfbus/impressionist](https://github.com/jfbus/impressionist) -- [Jmeyering/zealot](https://github.com/Jmeyering/zealot) -- [godep-migrator/rigger-host](https://github.com/godep-migrator/rigger-host) -- [Dronevery/MultiwaySwitch-Go](https://github.com/Dronevery/MultiwaySwitch-Go) -- [thoas/picfit](https://github.com/thoas/picfit) -- [mantasmatelis/whooplist-server](https://github.com/mantasmatelis/whooplist-server) -- [jnuthong/item_search](https://github.com/jnuthong/item_search) -- [bukalapak/snowboard](https://github.com/bukalapak/snowboard) -- [containerssh/containerssh](https://github.com/containerssh/containerssh) -- [goreleaser/goreleaser](https://github.com/goreleaser/goreleaser) -- [tjpnz/structbot](https://github.com/tjpnz/structbot) +Mergo is used by [thousands](https://deps.dev/go/dario.cat%2Fmergo/v1.0.0/dependents) [of](https://deps.dev/go/github.com%2Fimdario%2Fmergo/v0.3.16/dependents) [projects](https://deps.dev/go/github.com%2Fimdario%2Fmergo/v0.3.12), including: + +* [containerd/containerd](https://github.com/containerd/containerd) +* [datadog/datadog-agent](https://github.com/datadog/datadog-agent) +* [docker/cli/](https://github.com/docker/cli/) +* [goreleaser/goreleaser](https://github.com/goreleaser/goreleaser) +* [go-micro/go-micro](https://github.com/go-micro/go-micro) +* [grafana/loki](https://github.com/grafana/loki) +* [masterminds/sprig](github.com/Masterminds/sprig) +* [moby/moby](https://github.com/moby/moby) +* [slackhq/nebula](https://github.com/slackhq/nebula) +* [volcano-sh/volcano](https://github.com/volcano-sh/volcano) ## Install - go get github.com/imdario/mergo + go get dario.cat/mergo // use in your .go code import ( - "github.com/imdario/mergo" + "dario.cat/mergo" ) ## Usage @@ -135,6 +117,39 @@ if err := mergo.Merge(&dst, src, mergo.WithOverride); err != nil { } ``` +If you need to override pointers, so the source pointer's value is assigned to the destination's pointer, you must use `WithoutDereference`: + +```go +package main + +import ( + "fmt" + + "dario.cat/mergo" +) + +type Foo struct { + A *string + B int64 +} + +func main() { + first := "first" + second := "second" + src := Foo{ + A: &first, + B: 2, + } + + dest := Foo{ + A: &second, + B: 1, + } + + mergo.Merge(&dest, src, mergo.WithOverride, mergo.WithoutDereference) +} +``` + Additionally, you can map a `map[string]interface{}` to a struct (and otherwise, from struct to map), following the same restrictions as in `Merge()`. Keys are capitalized to find each corresponding exported field. ```go @@ -152,7 +167,7 @@ package main import ( "fmt" - "github.com/imdario/mergo" + "dario.cat/mergo" ) type Foo struct { @@ -175,10 +190,6 @@ func main() { } ``` -Note: if test are failing due missing package, please execute: - - go get gopkg.in/yaml.v3 - ### Transformers Transformers allow to merge specific types differently than in the default behavior. In other words, now you can customize how some types are merged. For example, `time.Time` is a struct; it doesn't have zero value but IsZero can return true because it has fields with zero value. How can we merge a non-zero `time.Time`? @@ -188,9 +199,9 @@ package main import ( "fmt" - "github.com/imdario/mergo" - "reflect" - "time" + "dario.cat/mergo" + "reflect" + "time" ) type timeTransformer struct { diff --git a/vendor/github.com/imdario/mergo/SECURITY.md b/vendor/dario.cat/mergo/SECURITY.md index a5de61f77..3788fcc1c 100644 --- a/vendor/github.com/imdario/mergo/SECURITY.md +++ b/vendor/dario.cat/mergo/SECURITY.md @@ -4,8 +4,8 @@ | Version | Supported | | ------- | ------------------ | -| 0.3.x | :white_check_mark: | -| < 0.3 | :x: | +| 1.x.x | :white_check_mark: | +| < 1.0 | :x: | ## Security contact information diff --git a/vendor/github.com/imdario/mergo/doc.go b/vendor/dario.cat/mergo/doc.go index fcd985f99..7d96ec054 100644 --- a/vendor/github.com/imdario/mergo/doc.go +++ b/vendor/dario.cat/mergo/doc.go @@ -8,30 +8,36 @@ A helper to merge structs and maps in Golang. Useful for configuration default v Mergo merges same-type structs and maps by setting default values in zero-value fields. Mergo won't merge unexported (private) fields. It will do recursively any exported one. It also won't merge structs inside maps (because they are not addressable using Go reflection). -Status +# Status It is ready for production use. It is used in several projects by Docker, Google, The Linux Foundation, VMWare, Shopify, etc. -Important note +# Important notes + +1.0.0 + +In 1.0.0 Mergo moves to a vanity URL `dario.cat/mergo`. + +0.3.9 Please keep in mind that a problematic PR broke 0.3.9. We reverted it in 0.3.10. We consider 0.3.10 as stable but not bug-free. . Also, this version adds suppot for go modules. Keep in mind that in 0.3.2, Mergo changed Merge() and Map() signatures to support transformers. We added an optional/variadic argument so that it won't break the existing code. -If you were using Mergo before April 6th, 2015, please check your project works as intended after updating your local copy with go get -u github.com/imdario/mergo. I apologize for any issue caused by its previous behavior and any future bug that Mergo could cause in existing projects after the change (release 0.2.0). +If you were using Mergo before April 6th, 2015, please check your project works as intended after updating your local copy with go get -u dario.cat/mergo. I apologize for any issue caused by its previous behavior and any future bug that Mergo could cause in existing projects after the change (release 0.2.0). -Install +# Install Do your usual installation procedure: - go get github.com/imdario/mergo + go get dario.cat/mergo - // use in your .go code - import ( - "github.com/imdario/mergo" - ) + // use in your .go code + import ( + "dario.cat/mergo" + ) -Usage +# Usage You can only merge same-type structs with exported fields initialized as zero value of their type and same-types maps. Mergo won't merge unexported (private) fields but will do recursively any exported one. It won't merge empty structs value as they are zero values too. Also, maps will be merged recursively except for structs inside maps (because they are not addressable using Go reflection). @@ -59,7 +65,7 @@ Here is a nice example: import ( "fmt" - "github.com/imdario/mergo" + "dario.cat/mergo" ) type Foo struct { @@ -81,7 +87,7 @@ Here is a nice example: // {two 2} } -Transformers +# Transformers Transformers allow to merge specific types differently than in the default behavior. In other words, now you can customize how some types are merged. For example, time.Time is a struct; it doesn't have zero value but IsZero can return true because it has fields with zero value. How can we merge a non-zero time.Time? @@ -89,9 +95,9 @@ Transformers allow to merge specific types differently than in the default behav import ( "fmt" - "github.com/imdario/mergo" - "reflect" - "time" + "dario.cat/mergo" + "reflect" + "time" ) type timeTransformer struct { @@ -127,17 +133,16 @@ Transformers allow to merge specific types differently than in the default behav // { 2018-01-12 01:15:00 +0000 UTC m=+0.000000001 } } -Contact me +# Contact me If I can help you, you have an idea or you are using Mergo in your projects, don't hesitate to drop me a line (or a pull request): https://twitter.com/im_dario -About +# About Written by Dario Castañé: https://da.rio.hn -License +# License BSD 3-Clause license, as Go language. - */ package mergo diff --git a/vendor/github.com/imdario/mergo/map.go b/vendor/dario.cat/mergo/map.go index b50d5c2a4..759b4f74f 100644 --- a/vendor/github.com/imdario/mergo/map.go +++ b/vendor/dario.cat/mergo/map.go @@ -58,7 +58,7 @@ func deepMap(dst, src reflect.Value, visited map[uintptr]*visit, depth int, conf } fieldName := field.Name fieldName = changeInitialCase(fieldName, unicode.ToLower) - if v, ok := dstMap[fieldName]; !ok || (isEmptyValue(reflect.ValueOf(v), !config.ShouldNotDereference) || overwrite) { + if _, ok := dstMap[fieldName]; !ok || (!isEmptyValue(reflect.ValueOf(src.Field(i).Interface()), !config.ShouldNotDereference) && overwrite) || config.overwriteWithEmptyValue { dstMap[fieldName] = src.Field(i).Interface() } } diff --git a/vendor/github.com/imdario/mergo/merge.go b/vendor/dario.cat/mergo/merge.go index 0ef9b2138..fd47c95b2 100644 --- a/vendor/github.com/imdario/mergo/merge.go +++ b/vendor/dario.cat/mergo/merge.go @@ -269,7 +269,7 @@ func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, co if err = deepMerge(dst.Elem(), src.Elem(), visited, depth+1, config); err != nil { return } - } else { + } else if src.Elem().Kind() != reflect.Struct { if overwriteWithEmptySrc || (overwrite && !src.IsNil()) || dst.IsNil() { dst.Set(src) } diff --git a/vendor/github.com/imdario/mergo/mergo.go b/vendor/dario.cat/mergo/mergo.go index 0a721e2d8..0a721e2d8 100644 --- a/vendor/github.com/imdario/mergo/mergo.go +++ b/vendor/dario.cat/mergo/mergo.go diff --git a/vendor/github.com/KimMachineGun/automemlimit/memlimit/cgroups.go b/vendor/github.com/KimMachineGun/automemlimit/memlimit/cgroups.go index 81559e3bf..2f0a84043 100644 --- a/vendor/github.com/KimMachineGun/automemlimit/memlimit/cgroups.go +++ b/vendor/github.com/KimMachineGun/automemlimit/memlimit/cgroups.go @@ -103,8 +103,8 @@ func getMemoryLimitV2(chs []cgroupHierarchy, mis []mountInfo) (uint64, error) { return 0, err } - // retrieve the memory limit from the memory.max file - return readMemoryLimitV2FromPath(filepath.Join(cgroupPath, "memory.max")) + // retrieve the memory limit from the memory.max recursively. + return walkCgroupV2Hierarchy(cgroupPath, mountPoint) } // readMemoryLimitV2FromPath reads the memory limit for cgroup v2 from the given path. @@ -131,6 +131,39 @@ func readMemoryLimitV2FromPath(path string) (uint64, error) { return limit, nil } +// walkCgroupV2Hierarchy walks up the cgroup v2 hierarchy to find the most restrictive memory limit. +func walkCgroupV2Hierarchy(cgroupPath, mountPoint string) (uint64, error) { + var ( + found = false + minLimit uint64 = math.MaxUint64 + currentPath = cgroupPath + ) + for { + limit, err := readMemoryLimitV2FromPath(filepath.Join(currentPath, "memory.max")) + if err != nil && !errors.Is(err, ErrNoLimit) { + return 0, err + } else if err == nil { + found = true + minLimit = min(minLimit, limit) + } + + if currentPath == mountPoint { + break + } + + parent := filepath.Dir(currentPath) + if parent == currentPath { + break + } + currentPath = parent + } + if !found { + return 0, ErrNoLimit + } + + return minLimit, nil +} + // getMemoryLimitV1 retrieves the memory limit from the cgroup v1 controller. func getMemoryLimitV1(chs []cgroupHierarchy, mis []mountInfo) (uint64, error) { // find the cgroup v1 path for the memory controller. diff --git a/vendor/github.com/Masterminds/semver/v3/CHANGELOG.md b/vendor/github.com/Masterminds/semver/v3/CHANGELOG.md index f12626423..fabe5e43d 100644 --- a/vendor/github.com/Masterminds/semver/v3/CHANGELOG.md +++ b/vendor/github.com/Masterminds/semver/v3/CHANGELOG.md @@ -1,5 +1,59 @@ # Changelog +## 3.4.0 (2025-06-27) + +### Added + +- #268: Added property to Constraints to include prereleases for Check and Validate + +### Changed + +- #263: Updated Go testing for 1.24, 1.23, and 1.22 +- #269: Updated the error message handling for message case and wrapping errors +- #266: Restore the ability to have leading 0's when parsing with NewVersion. + Opt-out of this by setting CoerceNewVersion to false. + +### Fixed + +- #257: Fixed the CodeQL link (thanks @dmitris) +- #262: Restored detailed errors when failed to parse with NewVersion. Opt-out + of this by setting DetailedNewVersionErrors to false for faster performance. +- #267: Handle pre-releases for an "and" group if one constraint includes them + +## 3.3.1 (2024-11-19) + +### Fixed + +- #253: Fix for allowing some version that were invalid + +## 3.3.0 (2024-08-27) + +### Added + +- #238: Add LessThanEqual and GreaterThanEqual functions (thanks @grosser) +- #213: nil version equality checking (thanks @KnutZuidema) + +### Changed + +- #241: Simplify StrictNewVersion parsing (thanks @grosser) +- Testing support up through Go 1.23 +- Minimum version set to 1.21 as this is what's tested now +- Fuzz testing now supports caching + +## 3.2.1 (2023-04-10) + +### Changed + +- #198: Improved testing around pre-release names +- #200: Improved code scanning with addition of CodeQL +- #201: Testing now includes Go 1.20. Go 1.17 has been dropped +- #202: Migrated Fuzz testing to Go built-in Fuzzing. CI runs daily +- #203: Docs updated for security details + +### Fixed + +- #199: Fixed issue with range transformations + ## 3.2.0 (2022-11-28) ### Added @@ -109,7 +163,7 @@ functions. These are described in the added and changed sections below. - #78: Fix unchecked error in example code (thanks @ravron) - #70: Fix the handling of pre-releases and the 0.0.0 release edge case - #97: Fixed copyright file for proper display on GitHub -- #107: Fix handling prerelease when sorting alphanum and num +- #107: Fix handling prerelease when sorting alphanum and num - #109: Fixed where Validate sometimes returns wrong message on error ## 1.4.2 (2018-04-10) diff --git a/vendor/github.com/Masterminds/semver/v3/Makefile b/vendor/github.com/Masterminds/semver/v3/Makefile index 0e7b5c713..9ca87a2c7 100644 --- a/vendor/github.com/Masterminds/semver/v3/Makefile +++ b/vendor/github.com/Masterminds/semver/v3/Makefile @@ -19,6 +19,7 @@ test-cover: .PHONY: fuzz fuzz: @echo "==> Running Fuzz Tests" + go env GOCACHE go test -fuzz=FuzzNewVersion -fuzztime=15s . go test -fuzz=FuzzStrictNewVersion -fuzztime=15s . go test -fuzz=FuzzNewConstraint -fuzztime=15s . @@ -27,4 +28,4 @@ $(GOLANGCI_LINT): # Install golangci-lint. The configuration for it is in the .golangci.yml # file in the root of the repository echo ${GOPATH} - curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(GOPATH)/bin v1.17.1 + curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(GOPATH)/bin v1.56.2 diff --git a/vendor/github.com/Masterminds/semver/v3/README.md b/vendor/github.com/Masterminds/semver/v3/README.md index eab8cac3b..2f56c676a 100644 --- a/vendor/github.com/Masterminds/semver/v3/README.md +++ b/vendor/github.com/Masterminds/semver/v3/README.md @@ -13,12 +13,9 @@ Active](https://masterminds.github.io/stability/active.svg)](https://masterminds [](https://pkg.go.dev/github.com/Masterminds/semver/v3) [](https://goreportcard.com/report/github.com/Masterminds/semver) -If you are looking for a command line tool for version comparisons please see -[vert](https://github.com/Masterminds/vert) which uses this library. - ## Package Versions -Note, import `github.com/github.com/Masterminds/semver/v3` to use the latest version. +Note, import `github.com/Masterminds/semver/v3` to use the latest version. There are three major versions fo the `semver` package. @@ -53,6 +50,18 @@ other versions, convert the version back into a string, and get the original string. Getting the original string is useful if the semantic version was coerced into a valid form. +There are package level variables that affect how `NewVersion` handles parsing. + +- `CoerceNewVersion` is `true` by default. When set to `true` it coerces non-compliant + versions into SemVer. For example, allowing a leading 0 in a major, minor, or patch + part. This enables the use of CalVer in versions even when not compliant with SemVer. + When set to `false` less coercion work is done. +- `DetailedNewVersionErrors` provides more detailed errors. It only has an affect when + `CoerceNewVersion` is set to `false`. When `DetailedNewVersionErrors` is set to `true` + it can provide some more insight into why a version is invalid. Setting + `DetailedNewVersionErrors` to `false` is faster on performance but provides less + detailed error messages if a version fails to parse. + ## Sorting Semantic Versions A set of versions can be sorted using the `sort` package from the standard library. @@ -80,12 +89,12 @@ There are two methods for comparing versions. One uses comparison methods on differences to notes between these two methods of comparison. 1. When two versions are compared using functions such as `Compare`, `LessThan`, - and others it will follow the specification and always include prereleases + and others it will follow the specification and always include pre-releases within the comparison. It will provide an answer that is valid with the comparison section of the spec at https://semver.org/#spec-item-11 2. When constraint checking is used for checks or validation it will follow a different set of rules that are common for ranges with tools like npm/js - and Rust/Cargo. This includes considering prereleases to be invalid if the + and Rust/Cargo. This includes considering pre-releases to be invalid if the ranges does not include one. If you want to have it include pre-releases a simple solution is to include `-0` in your range. 3. Constraint ranges can have some complex rules including the shorthand use of @@ -113,7 +122,7 @@ v, err := semver.NewVersion("1.3") if err != nil { // Handle version not being parsable. } -// Check if the version meets the constraints. The a variable will be true. +// Check if the version meets the constraints. The variable a will be true. a := c.Check(v) ``` @@ -137,20 +146,20 @@ The basic comparisons are: ### Working With Prerelease Versions Pre-releases, for those not familiar with them, are used for software releases -prior to stable or generally available releases. Examples of prereleases include -development, alpha, beta, and release candidate releases. A prerelease may be +prior to stable or generally available releases. Examples of pre-releases include +development, alpha, beta, and release candidate releases. A pre-release may be a version such as `1.2.3-beta.1` while the stable release would be `1.2.3`. In the -order of precedence, prereleases come before their associated releases. In this +order of precedence, pre-releases come before their associated releases. In this example `1.2.3-beta.1 < 1.2.3`. -According to the Semantic Version specification prereleases may not be +According to the Semantic Version specification, pre-releases may not be API compliant with their release counterpart. It says, > A pre-release version indicates that the version is unstable and might not satisfy the intended compatibility requirements as denoted by its associated normal version. -SemVer comparisons using constraints without a prerelease comparator will skip -prerelease versions. For example, `>=1.2.3` will skip prereleases when looking -at a list of releases while `>=1.2.3-0` will evaluate and find prereleases. +SemVer's comparisons using constraints without a pre-release comparator will skip +pre-release versions. For example, `>=1.2.3` will skip pre-releases when looking +at a list of releases while `>=1.2.3-0` will evaluate and find pre-releases. The reason for the `0` as a pre-release version in the example comparison is because pre-releases can only contain ASCII alphanumerics and hyphens (along with @@ -163,6 +172,10 @@ means `>=1.2.3-BETA` will return `1.2.3-alpha`. What you might expect from case sensitivity doesn't apply here. This is due to ASCII sort ordering which is what the spec specifies. +The `Constraints` instance returned from `semver.NewConstraint()` has a property +`IncludePrerelease` that, when set to true, will return prerelease versions when calls +to `Check()` and `Validate()` are made. + ### Hyphen Range Comparisons There are multiple methods to handle ranges and the first is hyphens ranges. @@ -171,6 +184,9 @@ These look like: * `1.2 - 1.4.5` which is equivalent to `>= 1.2 <= 1.4.5` * `2.3.4 - 4.5` which is equivalent to `>= 2.3.4 <= 4.5` +Note that `1.2-1.4.5` without whitespace is parsed completely differently; it's +parsed as a single constraint `1.2.0` with _prerelease_ `1.4.5`. + ### Wildcards In Comparisons The `x`, `X`, and `*` characters can be used as a wildcard character. This works @@ -250,7 +266,7 @@ or [create a pull request](https://github.com/Masterminds/semver/pulls). Security is an important consideration for this project. The project currently uses the following tools to help discover security issues: -* [CodeQL](https://github.com/Masterminds/semver) +* [CodeQL](https://codeql.github.com) * [gosec](https://github.com/securego/gosec) * Daily Fuzz testing diff --git a/vendor/github.com/Masterminds/semver/v3/constraints.go b/vendor/github.com/Masterminds/semver/v3/constraints.go index 8461c7ed9..8b7a10f83 100644 --- a/vendor/github.com/Masterminds/semver/v3/constraints.go +++ b/vendor/github.com/Masterminds/semver/v3/constraints.go @@ -12,6 +12,13 @@ import ( // checked against. type Constraints struct { constraints [][]*constraint + containsPre []bool + + // IncludePrerelease specifies if pre-releases should be included in + // the results. Note, if a constraint range has a prerelease than + // prereleases will be included for that AND group even if this is + // set to false. + IncludePrerelease bool } // NewConstraint returns a Constraints instance that a Version instance can @@ -22,11 +29,10 @@ func NewConstraint(c string) (*Constraints, error) { c = rewriteRange(c) ors := strings.Split(c, "||") - or := make([][]*constraint, len(ors)) + lenors := len(ors) + or := make([][]*constraint, lenors) + hasPre := make([]bool, lenors) for k, v := range ors { - - // TODO: Find a way to validate and fetch all the constraints in a simpler form - // Validate the segment if !validConstraintRegex.MatchString(v) { return nil, fmt.Errorf("improper constraint: %s", v) @@ -43,12 +49,22 @@ func NewConstraint(c string) (*Constraints, error) { return nil, err } + // If one of the constraints has a prerelease record this. + // This information is used when checking all in an "and" + // group to ensure they all check for prereleases. + if pc.con.pre != "" { + hasPre[k] = true + } + result[i] = pc } or[k] = result } - o := &Constraints{constraints: or} + o := &Constraints{ + constraints: or, + containsPre: hasPre, + } return o, nil } @@ -57,10 +73,10 @@ func (cs Constraints) Check(v *Version) bool { // TODO(mattfarina): For v4 of this library consolidate the Check and Validate // functions as the underlying functions make that possible now. // loop over the ORs and check the inner ANDs - for _, o := range cs.constraints { + for i, o := range cs.constraints { joy := true for _, c := range o { - if check, _ := c.check(v); !check { + if check, _ := c.check(v, (cs.IncludePrerelease || cs.containsPre[i])); !check { joy = false break } @@ -83,12 +99,12 @@ func (cs Constraints) Validate(v *Version) (bool, []error) { // Capture the prerelease message only once. When it happens the first time // this var is marked var prerelesase bool - for _, o := range cs.constraints { + for i, o := range cs.constraints { joy := true for _, c := range o { // Before running the check handle the case there the version is // a prerelease and the check is not searching for prereleases. - if c.con.pre == "" && v.pre != "" { + if !(cs.IncludePrerelease || cs.containsPre[i]) && v.pre != "" { if !prerelesase { em := fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v) e = append(e, em) @@ -98,7 +114,7 @@ func (cs Constraints) Validate(v *Version) (bool, []error) { } else { - if _, err := c.check(v); err != nil { + if _, err := c.check(v, (cs.IncludePrerelease || cs.containsPre[i])); err != nil { e = append(e, err) joy = false } @@ -227,8 +243,8 @@ type constraint struct { } // Check if a version meets the constraint -func (c *constraint) check(v *Version) (bool, error) { - return constraintOps[c.origfunc](v, c) +func (c *constraint) check(v *Version, includePre bool) (bool, error) { + return constraintOps[c.origfunc](v, c, includePre) } // String prints an individual constraint into a string @@ -236,7 +252,7 @@ func (c *constraint) string() string { return c.origfunc + c.orig } -type cfunc func(v *Version, c *constraint) (bool, error) +type cfunc func(v *Version, c *constraint, includePre bool) (bool, error) func parseConstraint(c string) (*constraint, error) { if len(c) > 0 { @@ -272,7 +288,7 @@ func parseConstraint(c string) (*constraint, error) { // The constraintRegex should catch any regex parsing errors. So, // we should never get here. - return nil, errors.New("constraint Parser Error") + return nil, errors.New("constraint parser error") } cs.con = con @@ -290,7 +306,7 @@ func parseConstraint(c string) (*constraint, error) { // The constraintRegex should catch any regex parsing errors. So, // we should never get here. - return nil, errors.New("constraint Parser Error") + return nil, errors.New("constraint parser error") } cs := &constraint{ @@ -305,16 +321,14 @@ func parseConstraint(c string) (*constraint, error) { } // Constraint functions -func constraintNotEqual(v *Version, c *constraint) (bool, error) { - if c.dirty { - - // If there is a pre-release on the version but the constraint isn't looking - // for them assume that pre-releases are not compatible. See issue 21 for - // more details. - if v.Prerelease() != "" && c.con.Prerelease() == "" { - return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v) - } +func constraintNotEqual(v *Version, c *constraint, includePre bool) (bool, error) { + // The existence of prereleases is checked at the group level and passed in. + // Exit early if the version has a prerelease but those are to be ignored. + if v.Prerelease() != "" && !includePre { + return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v) + } + if c.dirty { if c.con.Major() != v.Major() { return true, nil } @@ -345,12 +359,11 @@ func constraintNotEqual(v *Version, c *constraint) (bool, error) { return true, nil } -func constraintGreaterThan(v *Version, c *constraint) (bool, error) { +func constraintGreaterThan(v *Version, c *constraint, includePre bool) (bool, error) { - // If there is a pre-release on the version but the constraint isn't looking - // for them assume that pre-releases are not compatible. See issue 21 for - // more details. - if v.Prerelease() != "" && c.con.Prerelease() == "" { + // The existence of prereleases is checked at the group level and passed in. + // Exit early if the version has a prerelease but those are to be ignored. + if v.Prerelease() != "" && !includePre { return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v) } @@ -391,11 +404,10 @@ func constraintGreaterThan(v *Version, c *constraint) (bool, error) { return false, fmt.Errorf("%s is less than or equal to %s", v, c.orig) } -func constraintLessThan(v *Version, c *constraint) (bool, error) { - // If there is a pre-release on the version but the constraint isn't looking - // for them assume that pre-releases are not compatible. See issue 21 for - // more details. - if v.Prerelease() != "" && c.con.Prerelease() == "" { +func constraintLessThan(v *Version, c *constraint, includePre bool) (bool, error) { + // The existence of prereleases is checked at the group level and passed in. + // Exit early if the version has a prerelease but those are to be ignored. + if v.Prerelease() != "" && !includePre { return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v) } @@ -406,12 +418,11 @@ func constraintLessThan(v *Version, c *constraint) (bool, error) { return false, fmt.Errorf("%s is greater than or equal to %s", v, c.orig) } -func constraintGreaterThanEqual(v *Version, c *constraint) (bool, error) { +func constraintGreaterThanEqual(v *Version, c *constraint, includePre bool) (bool, error) { - // If there is a pre-release on the version but the constraint isn't looking - // for them assume that pre-releases are not compatible. See issue 21 for - // more details. - if v.Prerelease() != "" && c.con.Prerelease() == "" { + // The existence of prereleases is checked at the group level and passed in. + // Exit early if the version has a prerelease but those are to be ignored. + if v.Prerelease() != "" && !includePre { return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v) } @@ -422,11 +433,10 @@ func constraintGreaterThanEqual(v *Version, c *constraint) (bool, error) { return false, fmt.Errorf("%s is less than %s", v, c.orig) } -func constraintLessThanEqual(v *Version, c *constraint) (bool, error) { - // If there is a pre-release on the version but the constraint isn't looking - // for them assume that pre-releases are not compatible. See issue 21 for - // more details. - if v.Prerelease() != "" && c.con.Prerelease() == "" { +func constraintLessThanEqual(v *Version, c *constraint, includePre bool) (bool, error) { + // The existence of prereleases is checked at the group level and passed in. + // Exit early if the version has a prerelease but those are to be ignored. + if v.Prerelease() != "" && !includePre { return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v) } @@ -455,11 +465,10 @@ func constraintLessThanEqual(v *Version, c *constraint) (bool, error) { // ~1.2, ~1.2.x, ~>1.2, ~>1.2.x --> >=1.2.0, <1.3.0 // ~1.2.3, ~>1.2.3 --> >=1.2.3, <1.3.0 // ~1.2.0, ~>1.2.0 --> >=1.2.0, <1.3.0 -func constraintTilde(v *Version, c *constraint) (bool, error) { - // If there is a pre-release on the version but the constraint isn't looking - // for them assume that pre-releases are not compatible. See issue 21 for - // more details. - if v.Prerelease() != "" && c.con.Prerelease() == "" { +func constraintTilde(v *Version, c *constraint, includePre bool) (bool, error) { + // The existence of prereleases is checked at the group level and passed in. + // Exit early if the version has a prerelease but those are to be ignored. + if v.Prerelease() != "" && !includePre { return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v) } @@ -487,16 +496,15 @@ func constraintTilde(v *Version, c *constraint) (bool, error) { // When there is a .x (dirty) status it automatically opts in to ~. Otherwise // it's a straight = -func constraintTildeOrEqual(v *Version, c *constraint) (bool, error) { - // If there is a pre-release on the version but the constraint isn't looking - // for them assume that pre-releases are not compatible. See issue 21 for - // more details. - if v.Prerelease() != "" && c.con.Prerelease() == "" { +func constraintTildeOrEqual(v *Version, c *constraint, includePre bool) (bool, error) { + // The existence of prereleases is checked at the group level and passed in. + // Exit early if the version has a prerelease but those are to be ignored. + if v.Prerelease() != "" && !includePre { return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v) } if c.dirty { - return constraintTilde(v, c) + return constraintTilde(v, c, includePre) } eq := v.Equal(c.con) @@ -516,11 +524,10 @@ func constraintTildeOrEqual(v *Version, c *constraint) (bool, error) { // ^0.0.3 --> >=0.0.3 <0.0.4 // ^0.0 --> >=0.0.0 <0.1.0 // ^0 --> >=0.0.0 <1.0.0 -func constraintCaret(v *Version, c *constraint) (bool, error) { - // If there is a pre-release on the version but the constraint isn't looking - // for them assume that pre-releases are not compatible. See issue 21 for - // more details. - if v.Prerelease() != "" && c.con.Prerelease() == "" { +func constraintCaret(v *Version, c *constraint, includePre bool) (bool, error) { + // The existence of prereleases is checked at the group level and passed in. + // Exit early if the version has a prerelease but those are to be ignored. + if v.Prerelease() != "" && !includePre { return false, fmt.Errorf("%s is a prerelease version and the constraint is only looking for release versions", v) } diff --git a/vendor/github.com/Masterminds/semver/v3/version.go b/vendor/github.com/Masterminds/semver/v3/version.go index 7c4bed334..7a3ba7388 100644 --- a/vendor/github.com/Masterminds/semver/v3/version.go +++ b/vendor/github.com/Masterminds/semver/v3/version.go @@ -14,32 +14,52 @@ import ( // The compiled version of the regex created at init() is cached here so it // only needs to be created once. var versionRegex *regexp.Regexp +var looseVersionRegex *regexp.Regexp + +// CoerceNewVersion sets if leading 0's are allowd in the version part. Leading 0's are +// not allowed in a valid semantic version. When set to true, NewVersion will coerce +// leading 0's into a valid version. +var CoerceNewVersion = true + +// DetailedNewVersionErrors specifies if detailed errors are returned from the NewVersion +// function. This is used when CoerceNewVersion is set to false. If set to false +// ErrInvalidSemVer is returned for an invalid version. This does not apply to +// StrictNewVersion. Setting this function to false returns errors more quickly. +var DetailedNewVersionErrors = true var ( // ErrInvalidSemVer is returned a version is found to be invalid when // being parsed. - ErrInvalidSemVer = errors.New("Invalid Semantic Version") + ErrInvalidSemVer = errors.New("invalid semantic version") // ErrEmptyString is returned when an empty string is passed in for parsing. - ErrEmptyString = errors.New("Version string empty") + ErrEmptyString = errors.New("version string empty") // ErrInvalidCharacters is returned when invalid characters are found as // part of a version - ErrInvalidCharacters = errors.New("Invalid characters in version") + ErrInvalidCharacters = errors.New("invalid characters in version") // ErrSegmentStartsZero is returned when a version segment starts with 0. // This is invalid in SemVer. - ErrSegmentStartsZero = errors.New("Version segment starts with 0") + ErrSegmentStartsZero = errors.New("version segment starts with 0") // ErrInvalidMetadata is returned when the metadata is an invalid format - ErrInvalidMetadata = errors.New("Invalid Metadata string") + ErrInvalidMetadata = errors.New("invalid metadata string") // ErrInvalidPrerelease is returned when the pre-release is an invalid format - ErrInvalidPrerelease = errors.New("Invalid Prerelease string") + ErrInvalidPrerelease = errors.New("invalid prerelease string") ) // semVerRegex is the regular expression used to parse a semantic version. -const semVerRegex string = `v?([0-9]+)(\.[0-9]+)?(\.[0-9]+)?` + +// This is not the official regex from the semver spec. It has been modified to allow for loose handling +// where versions like 2.1 are detected. +const semVerRegex string = `v?(0|[1-9]\d*)(?:\.(0|[1-9]\d*))?(?:\.(0|[1-9]\d*))?` + + `(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?` + + `(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?` + +// looseSemVerRegex is a regular expression that lets invalid semver expressions through +// with enough detail that certain errors can be checked for. +const looseSemVerRegex string = `v?([0-9]+)(\.[0-9]+)?(\.[0-9]+)?` + `(-([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?` + `(\+([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?` @@ -53,6 +73,7 @@ type Version struct { func init() { versionRegex = regexp.MustCompile("^" + semVerRegex + "$") + looseVersionRegex = regexp.MustCompile("^" + looseSemVerRegex + "$") } const ( @@ -83,22 +104,23 @@ func StrictNewVersion(v string) (*Version, error) { original: v, } - // check for prerelease or build metadata - var extra []string - if strings.ContainsAny(parts[2], "-+") { - // Start with the build metadata first as it needs to be on the right - extra = strings.SplitN(parts[2], "+", 2) - if len(extra) > 1 { - // build metadata found - sv.metadata = extra[1] - parts[2] = extra[0] + // Extract build metadata + if strings.Contains(parts[2], "+") { + extra := strings.SplitN(parts[2], "+", 2) + sv.metadata = extra[1] + parts[2] = extra[0] + if err := validateMetadata(sv.metadata); err != nil { + return nil, err } + } - extra = strings.SplitN(parts[2], "-", 2) - if len(extra) > 1 { - // prerelease found - sv.pre = extra[1] - parts[2] = extra[0] + // Extract build prerelease + if strings.Contains(parts[2], "-") { + extra := strings.SplitN(parts[2], "-", 2) + sv.pre = extra[1] + parts[2] = extra[0] + if err := validatePrerelease(sv.pre); err != nil { + return nil, err } } @@ -114,7 +136,7 @@ func StrictNewVersion(v string) (*Version, error) { } } - // Extract the major, minor, and patch elements onto the returned Version + // Extract major, minor, and patch var err error sv.major, err = strconv.ParseUint(parts[0], 10, 64) if err != nil { @@ -131,11 +153,71 @@ func StrictNewVersion(v string) (*Version, error) { return nil, err } - // No prerelease or build metadata found so returning now as a fastpath. - if sv.pre == "" && sv.metadata == "" { - return sv, nil + return sv, nil +} + +// NewVersion parses a given version and returns an instance of Version or +// an error if unable to parse the version. If the version is SemVer-ish it +// attempts to convert it to SemVer. If you want to validate it was a strict +// semantic version at parse time see StrictNewVersion(). +func NewVersion(v string) (*Version, error) { + if CoerceNewVersion { + return coerceNewVersion(v) + } + m := versionRegex.FindStringSubmatch(v) + if m == nil { + + // Disabling detailed errors is first so that it is in the fast path. + if !DetailedNewVersionErrors { + return nil, ErrInvalidSemVer + } + + // Check for specific errors with the semver string and return a more detailed + // error. + m = looseVersionRegex.FindStringSubmatch(v) + if m == nil { + return nil, ErrInvalidSemVer + } + err := validateVersion(m) + if err != nil { + return nil, err + } + return nil, ErrInvalidSemVer + } + + sv := &Version{ + metadata: m[5], + pre: m[4], + original: v, + } + + var err error + sv.major, err = strconv.ParseUint(m[1], 10, 64) + if err != nil { + return nil, fmt.Errorf("error parsing version segment: %w", err) + } + + if m[2] != "" { + sv.minor, err = strconv.ParseUint(m[2], 10, 64) + if err != nil { + return nil, fmt.Errorf("error parsing version segment: %w", err) + } + } else { + sv.minor = 0 + } + + if m[3] != "" { + sv.patch, err = strconv.ParseUint(m[3], 10, 64) + if err != nil { + return nil, fmt.Errorf("error parsing version segment: %w", err) + } + } else { + sv.patch = 0 } + // Perform some basic due diligence on the extra parts to ensure they are + // valid. + if sv.pre != "" { if err = validatePrerelease(sv.pre); err != nil { return nil, err @@ -151,12 +233,8 @@ func StrictNewVersion(v string) (*Version, error) { return sv, nil } -// NewVersion parses a given version and returns an instance of Version or -// an error if unable to parse the version. If the version is SemVer-ish it -// attempts to convert it to SemVer. If you want to validate it was a strict -// semantic version at parse time see StrictNewVersion(). -func NewVersion(v string) (*Version, error) { - m := versionRegex.FindStringSubmatch(v) +func coerceNewVersion(v string) (*Version, error) { + m := looseVersionRegex.FindStringSubmatch(v) if m == nil { return nil, ErrInvalidSemVer } @@ -170,13 +248,13 @@ func NewVersion(v string) (*Version, error) { var err error sv.major, err = strconv.ParseUint(m[1], 10, 64) if err != nil { - return nil, fmt.Errorf("Error parsing version segment: %s", err) + return nil, fmt.Errorf("error parsing version segment: %w", err) } if m[2] != "" { sv.minor, err = strconv.ParseUint(strings.TrimPrefix(m[2], "."), 10, 64) if err != nil { - return nil, fmt.Errorf("Error parsing version segment: %s", err) + return nil, fmt.Errorf("error parsing version segment: %w", err) } } else { sv.minor = 0 @@ -185,7 +263,7 @@ func NewVersion(v string) (*Version, error) { if m[3] != "" { sv.patch, err = strconv.ParseUint(strings.TrimPrefix(m[3], "."), 10, 64) if err != nil { - return nil, fmt.Errorf("Error parsing version segment: %s", err) + return nil, fmt.Errorf("error parsing version segment: %w", err) } } else { sv.patch = 0 @@ -381,15 +459,31 @@ func (v *Version) LessThan(o *Version) bool { return v.Compare(o) < 0 } +// LessThanEqual tests if one version is less or equal than another one. +func (v *Version) LessThanEqual(o *Version) bool { + return v.Compare(o) <= 0 +} + // GreaterThan tests if one version is greater than another one. func (v *Version) GreaterThan(o *Version) bool { return v.Compare(o) > 0 } +// GreaterThanEqual tests if one version is greater or equal than another one. +func (v *Version) GreaterThanEqual(o *Version) bool { + return v.Compare(o) >= 0 +} + // Equal tests if two versions are equal to each other. // Note, versions can be equal with different metadata since metadata // is not considered part of the comparable version. func (v *Version) Equal(o *Version) bool { + if v == o { + return true + } + if v == nil || o == nil { + return false + } return v.Compare(o) == 0 } @@ -612,7 +706,9 @@ func containsOnly(s string, comp string) bool { func validatePrerelease(p string) error { eparts := strings.Split(p, ".") for _, p := range eparts { - if containsOnly(p, num) { + if p == "" { + return ErrInvalidPrerelease + } else if containsOnly(p, num) { if len(p) > 1 && p[0] == '0' { return ErrSegmentStartsZero } @@ -631,9 +727,62 @@ func validatePrerelease(p string) error { func validateMetadata(m string) error { eparts := strings.Split(m, ".") for _, p := range eparts { - if !containsOnly(p, allowed) { + if p == "" { return ErrInvalidMetadata + } else if !containsOnly(p, allowed) { + return ErrInvalidMetadata + } + } + return nil +} + +// validateVersion checks for common validation issues but may not catch all errors +func validateVersion(m []string) error { + var err error + var v string + if m[1] != "" { + if len(m[1]) > 1 && m[1][0] == '0' { + return ErrSegmentStartsZero + } + _, err = strconv.ParseUint(m[1], 10, 64) + if err != nil { + return fmt.Errorf("error parsing version segment: %w", err) + } + } + + if m[2] != "" { + v = strings.TrimPrefix(m[2], ".") + if len(v) > 1 && v[0] == '0' { + return ErrSegmentStartsZero + } + _, err = strconv.ParseUint(v, 10, 64) + if err != nil { + return fmt.Errorf("error parsing version segment: %w", err) } } + + if m[3] != "" { + v = strings.TrimPrefix(m[3], ".") + if len(v) > 1 && v[0] == '0' { + return ErrSegmentStartsZero + } + _, err = strconv.ParseUint(v, 10, 64) + if err != nil { + return fmt.Errorf("error parsing version segment: %w", err) + } + } + + if m[5] != "" { + if err = validatePrerelease(m[5]); err != nil { + return err + } + } + + if m[8] != "" { + if err = validateMetadata(m[8]); err != nil { + return err + } + } + return nil } diff --git a/vendor/github.com/Masterminds/sprig/v3/CHANGELOG.md b/vendor/github.com/Masterminds/sprig/v3/CHANGELOG.md index 2ce45dd4e..b5ef766a7 100644 --- a/vendor/github.com/Masterminds/sprig/v3/CHANGELOG.md +++ b/vendor/github.com/Masterminds/sprig/v3/CHANGELOG.md @@ -1,5 +1,23 @@ # Changelog +## Release 3.3.0 (2024-08-29) + +### Added + +- #400: added sha512sum function (thanks @itzik-elayev) + +### Changed + +- #407: Removed duplicate documentation (functions were documentated in 2 places) +- #290: Corrected copy/paster oops in math documentation (thanks @zzhu41) +- #369: Corrected template reference in docs (thanks @chey) +- #375: Added link to URL documenation (thanks @carlpett) +- #406: Updated the mergo dependency which had a breaking change (which was accounted for) +- #376: Fixed documentation error (thanks @jheyduk) +- #404: Updated dependency tree +- #391: Fixed misspelling (thanks @chrishalbert) +- #405: Updated Go versions used in testing + ## Release 3.2.3 (2022-11-29) ### Changed @@ -307,7 +325,7 @@ This release adds new functions, including: - Added `semver` and `semverCompare` for Semantic Versions - `list` replaces `tuple` - Fixed issue with `join` -- Added `first`, `last`, `intial`, `rest`, `prepend`, `append`, `toString`, `toStrings`, `sortAlpha`, `reverse`, `coalesce`, `pluck`, `pick`, `compact`, `keys`, `omit`, `uniq`, `has`, `without` +- Added `first`, `last`, `initial`, `rest`, `prepend`, `append`, `toString`, `toStrings`, `sortAlpha`, `reverse`, `coalesce`, `pluck`, `pick`, `compact`, `keys`, `omit`, `uniq`, `has`, `without` ## Release 2.9.0 (2017-02-23) @@ -361,7 +379,7 @@ Because we switched from `int` to `int64` as the return value for all integer ma - `min` complements `max` (formerly `biggest`) - `empty` indicates that a value is the empty value for its type - `tuple` creates a tuple inside of a template: `{{$t := tuple "a", "b" "c"}}` -- `dict` creates a dictionary inside of a template `{{$d := dict "key1" "val1" "key2" "val2"}}` +- `dict` creates a dictionary inside of a template `{{$d := dict "key1" "val1" "key2" "val2"}}` - Date formatters have been added for HTML dates (as used in `date` input fields) - Integer math functions can convert from a number of types, including `string` (via `strconv.ParseInt`). diff --git a/vendor/github.com/Masterminds/sprig/v3/crypto.go b/vendor/github.com/Masterminds/sprig/v3/crypto.go index 13a5cd559..75fe027e4 100644 --- a/vendor/github.com/Masterminds/sprig/v3/crypto.go +++ b/vendor/github.com/Masterminds/sprig/v3/crypto.go @@ -14,6 +14,7 @@ import ( "crypto/rsa" "crypto/sha1" "crypto/sha256" + "crypto/sha512" "crypto/x509" "crypto/x509/pkix" "encoding/asn1" @@ -36,6 +37,11 @@ import ( "golang.org/x/crypto/scrypt" ) +func sha512sum(input string) string { + hash := sha512.Sum512([]byte(input)) + return hex.EncodeToString(hash[:]) +} + func sha256sum(input string) string { hash := sha256.Sum256([]byte(input)) return hex.EncodeToString(hash[:]) diff --git a/vendor/github.com/Masterminds/sprig/v3/dict.go b/vendor/github.com/Masterminds/sprig/v3/dict.go index ade889698..4315b3542 100644 --- a/vendor/github.com/Masterminds/sprig/v3/dict.go +++ b/vendor/github.com/Masterminds/sprig/v3/dict.go @@ -1,7 +1,7 @@ package sprig import ( - "github.com/imdario/mergo" + "dario.cat/mergo" "github.com/mitchellh/copystructure" ) diff --git a/vendor/github.com/Masterminds/sprig/v3/doc.go b/vendor/github.com/Masterminds/sprig/v3/doc.go index aabb9d448..91031d6d1 100644 --- a/vendor/github.com/Masterminds/sprig/v3/doc.go +++ b/vendor/github.com/Masterminds/sprig/v3/doc.go @@ -6,7 +6,7 @@ inside of Go `html/template` and `text/template` files. To add these functions, use the `template.Funcs()` method: - t := templates.New("foo").Funcs(sprig.FuncMap()) + t := template.New("foo").Funcs(sprig.FuncMap()) Note that you should add the function map before you parse any template files. diff --git a/vendor/github.com/Masterminds/sprig/v3/functions.go b/vendor/github.com/Masterminds/sprig/v3/functions.go index 57fcec1d9..cda47d26f 100644 --- a/vendor/github.com/Masterminds/sprig/v3/functions.go +++ b/vendor/github.com/Masterminds/sprig/v3/functions.go @@ -22,8 +22,7 @@ import ( // // Use this to pass the functions into the template engine: // -// tpl := template.New("foo").Funcs(sprig.FuncMap())) -// +// tpl := template.New("foo").Funcs(sprig.FuncMap())) func FuncMap() template.FuncMap { return HtmlFuncMap() } @@ -142,10 +141,13 @@ var genericMap = map[string]interface{}{ "swapcase": util.SwapCase, "shuffle": xstrings.Shuffle, "snakecase": xstrings.ToSnakeCase, - "camelcase": xstrings.ToCamelCase, - "kebabcase": xstrings.ToKebabCase, - "wrap": func(l int, s string) string { return util.Wrap(s, l) }, - "wrapWith": func(l int, sep, str string) string { return util.WrapCustom(str, l, sep, true) }, + // camelcase used to call xstrings.ToCamelCase, but that function had a breaking change in version + // 1.5 that moved it from upper camel case to lower camel case. This is a breaking change for sprig. + // A new xstrings.ToPascalCase function was added that provided upper camel case. + "camelcase": xstrings.ToPascalCase, + "kebabcase": xstrings.ToKebabCase, + "wrap": func(l int, s string) string { return util.Wrap(s, l) }, + "wrapWith": func(l int, sep, str string) string { return util.WrapCustom(str, l, sep, true) }, // Switch order so that "foobar" | contains "foo" "contains": func(substr string, str string) bool { return strings.Contains(str, substr) }, "hasPrefix": func(substr string, str string) bool { return strings.HasPrefix(str, substr) }, @@ -159,6 +161,7 @@ var genericMap = map[string]interface{}{ "plural": plural, "sha1sum": sha1sum, "sha256sum": sha256sum, + "sha512sum": sha512sum, "adler32sum": adler32sum, "toString": strval, @@ -336,20 +339,20 @@ var genericMap = map[string]interface{}{ "mustChunk": mustChunk, // Crypto: - "bcrypt": bcrypt, - "htpasswd": htpasswd, - "genPrivateKey": generatePrivateKey, - "derivePassword": derivePassword, - "buildCustomCert": buildCustomCertificate, - "genCA": generateCertificateAuthority, - "genCAWithKey": generateCertificateAuthorityWithPEMKey, - "genSelfSignedCert": generateSelfSignedCertificate, + "bcrypt": bcrypt, + "htpasswd": htpasswd, + "genPrivateKey": generatePrivateKey, + "derivePassword": derivePassword, + "buildCustomCert": buildCustomCertificate, + "genCA": generateCertificateAuthority, + "genCAWithKey": generateCertificateAuthorityWithPEMKey, + "genSelfSignedCert": generateSelfSignedCertificate, "genSelfSignedCertWithKey": generateSelfSignedCertificateWithPEMKey, - "genSignedCert": generateSignedCertificate, - "genSignedCertWithKey": generateSignedCertificateWithPEMKey, - "encryptAES": encryptAES, - "decryptAES": decryptAES, - "randBytes": randBytes, + "genSignedCert": generateSignedCertificate, + "genSignedCertWithKey": generateSignedCertificateWithPEMKey, + "encryptAES": encryptAES, + "decryptAES": decryptAES, + "randBytes": randBytes, // UUIDs: "uuidv4": uuidv4, diff --git a/vendor/github.com/go-openapi/errors/.golangci.yml b/vendor/github.com/go-openapi/errors/.golangci.yml index cf88ead32..60798c211 100644 --- a/vendor/github.com/go-openapi/errors/.golangci.yml +++ b/vendor/github.com/go-openapi/errors/.golangci.yml @@ -1,62 +1,75 @@ -linters-settings: - govet: - check-shadowing: true - golint: - min-confidence: 0 - gocyclo: - min-complexity: 45 - maligned: - suggest-new: true - dupl: - threshold: 200 - goconst: - min-len: 2 - min-occurrences: 3 - +version: "2" linters: - enable-all: true + default: all disable: - - errname # this repo doesn't follow the convention advised by this linter - - maligned - - unparam - - lll - - gochecknoinits - - gochecknoglobals + - cyclop + - depguard + - errchkjson + - errorlint + - exhaustruct + - forcetypeassert - funlen - - godox + - gochecknoglobals + - gochecknoinits - gocognit - - whitespace - - wsl - - wrapcheck - - testpackage - - nlreturn - - gomnd - - exhaustivestruct - - goerr113 - - errorlint - - nestif - godot - - gofumpt + - godox + - gosmopolitan + - inamedparam + - intrange # disabled while < go1.22 + - ireturn + - lll + - musttag + - nestif + - nlreturn + - noinlineerr + - nonamedreturns - paralleltest - - tparallel + - recvcheck + - testpackage - thelper - - ifshort - - exhaustruct + - tparallel + - unparam - varnamelen - - gci - - depguard - - errchkjson - - inamedparam - - nonamedreturns - - musttag - - ireturn - - forcetypeassert - - cyclop - # deprecated linters - - deadcode - - interfacer - - scopelint - - varcheck - - structcheck - - golint - - nosnakecase + - whitespace + - wrapcheck + - wsl + - wsl_v5 + settings: + dupl: + threshold: 200 + goconst: + min-len: 2 + min-occurrences: 3 + gocyclo: + min-complexity: 45 + exclusions: + generated: lax + presets: + - comments + - common-false-positives + - legacy + - std-error-handling + paths: + - third_party$ + - builtin$ + - examples$ +formatters: + enable: + - gofmt + - goimports + exclusions: + generated: lax + paths: + - third_party$ + - builtin$ + - examples$ +issues: + # Maximum issues count per one linter. + # Set to 0 to disable. + # Default: 50 + max-issues-per-linter: 0 + # Maximum count of issues with the same text. + # Set to 0 to disable. + # Default: 3 + max-same-issues: 0 diff --git a/vendor/github.com/go-openapi/errors/api.go b/vendor/github.com/go-openapi/errors/api.go index 5320cb963..d6f507f42 100644 --- a/vendor/github.com/go-openapi/errors/api.go +++ b/vendor/github.com/go-openapi/errors/api.go @@ -185,7 +185,7 @@ func ServeError(rw http.ResponseWriter, r *http.Request, err error) { } func asHTTPCode(input int) int { - if input >= 600 { + if input >= maximumValidHTTPCode { return DefaultHTTPCode } return input diff --git a/vendor/github.com/go-openapi/errors/headers.go b/vendor/github.com/go-openapi/errors/headers.go index dfebe8f95..6ea1151f4 100644 --- a/vendor/github.com/go-openapi/errors/headers.go +++ b/vendor/github.com/go-openapi/errors/headers.go @@ -21,7 +21,7 @@ import ( ) // Validation represents a failure of a precondition -type Validation struct { +type Validation struct { //nolint: errname code int32 Name string In string diff --git a/vendor/github.com/go-openapi/errors/middleware.go b/vendor/github.com/go-openapi/errors/middleware.go index 963472d1f..1b9f3a930 100644 --- a/vendor/github.com/go-openapi/errors/middleware.go +++ b/vendor/github.com/go-openapi/errors/middleware.go @@ -22,7 +22,7 @@ import ( // APIVerificationFailed is an error that contains all the missing info for a mismatched section // between the api registrations and the api spec -type APIVerificationFailed struct { +type APIVerificationFailed struct { //nolint: errname Section string `json:"section,omitempty"` MissingSpecification []string `json:"missingSpecification,omitempty"` MissingRegistration []string `json:"missingRegistration,omitempty"` @@ -35,7 +35,7 @@ func (v *APIVerificationFailed) Error() string { hasSpecMissing := len(v.MissingSpecification) > 0 if hasRegMissing { - buf.WriteString(fmt.Sprintf("missing [%s] %s registrations", strings.Join(v.MissingRegistration, ", "), v.Section)) + fmt.Fprintf(buf, "missing [%s] %s registrations", strings.Join(v.MissingRegistration, ", "), v.Section) } if hasRegMissing && hasSpecMissing { @@ -43,7 +43,7 @@ func (v *APIVerificationFailed) Error() string { } if hasSpecMissing { - buf.WriteString(fmt.Sprintf("missing from spec file [%s] %s", strings.Join(v.MissingSpecification, ", "), v.Section)) + fmt.Fprintf(buf, "missing from spec file [%s] %s", strings.Join(v.MissingSpecification, ", "), v.Section) } return buf.String() diff --git a/vendor/github.com/go-openapi/errors/parsing.go b/vendor/github.com/go-openapi/errors/parsing.go index 5096e1ea7..34930c087 100644 --- a/vendor/github.com/go-openapi/errors/parsing.go +++ b/vendor/github.com/go-openapi/errors/parsing.go @@ -17,6 +17,7 @@ package errors import ( "encoding/json" "fmt" + "net/http" ) // ParseError represents a parsing error @@ -29,6 +30,24 @@ type ParseError struct { message string } +// NewParseError creates a new parse error +func NewParseError(name, in, value string, reason error) *ParseError { + var msg string + if in == "" { + msg = fmt.Sprintf(parseErrorTemplContentNoIn, name, value, reason) + } else { + msg = fmt.Sprintf(parseErrorTemplContent, name, in, value, reason) + } + return &ParseError{ + code: http.StatusBadRequest, + Name: name, + In: in, + Value: value, + Reason: reason, + message: msg, + } +} + func (e *ParseError) Error() string { return e.message } @@ -58,21 +77,3 @@ const ( parseErrorTemplContent = `parsing %s %s from %q failed, because %s` parseErrorTemplContentNoIn = `parsing %s from %q failed, because %s` ) - -// NewParseError creates a new parse error -func NewParseError(name, in, value string, reason error) *ParseError { - var msg string - if in == "" { - msg = fmt.Sprintf(parseErrorTemplContentNoIn, name, value, reason) - } else { - msg = fmt.Sprintf(parseErrorTemplContent, name, in, value, reason) - } - return &ParseError{ - code: 400, - Name: name, - In: in, - Value: value, - Reason: reason, - message: msg, - } -} diff --git a/vendor/github.com/go-openapi/errors/schema.go b/vendor/github.com/go-openapi/errors/schema.go index cf7ac2ed4..8f3239dfd 100644 --- a/vendor/github.com/go-openapi/errors/schema.go +++ b/vendor/github.com/go-openapi/errors/schema.go @@ -17,6 +17,7 @@ package errors import ( "encoding/json" "fmt" + "net/http" "strings" ) @@ -32,12 +33,12 @@ const ( patternFail = "%s in %s should match '%s'" enumFail = "%s in %s should be one of %v" multipleOfFail = "%s in %s should be a multiple of %v" - maxIncFail = "%s in %s should be less than or equal to %v" - maxExcFail = "%s in %s should be less than %v" + maximumIncFail = "%s in %s should be less than or equal to %v" + maximumExcFail = "%s in %s should be less than %v" minIncFail = "%s in %s should be greater than or equal to %v" minExcFail = "%s in %s should be greater than %v" uniqueFail = "%s in %s shouldn't contain duplicates" - maxItemsFail = "%s in %s should have at most %d items" + maximumItemsFail = "%s in %s should have at most %d items" minItemsFail = "%s in %s should have at least %d items" typeFailNoIn = "%s must be of type %s" typeFailWithDataNoIn = "%s must be of type %s: %q" @@ -49,12 +50,12 @@ const ( patternFailNoIn = "%s should match '%s'" enumFailNoIn = "%s should be one of %v" multipleOfFailNoIn = "%s should be a multiple of %v" - maxIncFailNoIn = "%s should be less than or equal to %v" - maxExcFailNoIn = "%s should be less than %v" + maximumIncFailNoIn = "%s should be less than or equal to %v" + maximumExcFailNoIn = "%s should be less than %v" minIncFailNoIn = "%s should be greater than or equal to %v" minExcFailNoIn = "%s should be greater than %v" uniqueFailNoIn = "%s shouldn't contain duplicates" - maxItemsFailNoIn = "%s should have at most %d items" + maximumItemsFailNoIn = "%s should have at most %d items" minItemsFailNoIn = "%s should have at least %d items" noAdditionalItems = "%s in %s can't have additional items" noAdditionalItemsNoIn = "%s can't have additional items" @@ -69,14 +70,17 @@ const ( multipleOfMustBePositive = "factor MultipleOf declared for %s must be positive: %v" ) +const maximumValidHTTPCode = 600 + // All code responses can be used to differentiate errors for different handling // by the consuming program const ( // CompositeErrorCode remains 422 for backwards-compatibility // and to separate it from validation errors with cause - CompositeErrorCode = 422 + CompositeErrorCode = http.StatusUnprocessableEntity + // InvalidTypeCode is used for any subclass of invalid types - InvalidTypeCode = 600 + iota + InvalidTypeCode = maximumValidHTTPCode + iota RequiredFailCode TooLongFailCode TooShortFailCode @@ -298,10 +302,10 @@ func DuplicateItems(name, in string) *Validation { } // TooManyItems error for when an array contains too many items -func TooManyItems(name, in string, max int64, value interface{}) *Validation { - msg := fmt.Sprintf(maxItemsFail, name, in, max) +func TooManyItems(name, in string, maximum int64, value interface{}) *Validation { + msg := fmt.Sprintf(maximumItemsFail, name, in, maximum) if in == "" { - msg = fmt.Sprintf(maxItemsFailNoIn, name, max) + msg = fmt.Sprintf(maximumItemsFailNoIn, name, maximum) } return &Validation{ @@ -314,10 +318,10 @@ func TooManyItems(name, in string, max int64, value interface{}) *Validation { } // TooFewItems error for when an array contains too few items -func TooFewItems(name, in string, min int64, value interface{}) *Validation { - msg := fmt.Sprintf(minItemsFail, name, in, min) +func TooFewItems(name, in string, minimum int64, value interface{}) *Validation { + msg := fmt.Sprintf(minItemsFail, name, in, minimum) if in == "" { - msg = fmt.Sprintf(minItemsFailNoIn, name, min) + msg = fmt.Sprintf(minItemsFailNoIn, name, minimum) } return &Validation{ code: MinItemsFailCode, @@ -328,21 +332,21 @@ func TooFewItems(name, in string, min int64, value interface{}) *Validation { } } -// ExceedsMaximumInt error for when maximum validation fails -func ExceedsMaximumInt(name, in string, max int64, exclusive bool, value interface{}) *Validation { +// ExceedsMaximumInt error for when maximumimum validation fails +func ExceedsMaximumInt(name, in string, maximum int64, exclusive bool, value interface{}) *Validation { var message string if in == "" { - m := maxIncFailNoIn + m := maximumIncFailNoIn if exclusive { - m = maxExcFailNoIn + m = maximumExcFailNoIn } - message = fmt.Sprintf(m, name, max) + message = fmt.Sprintf(m, name, maximum) } else { - m := maxIncFail + m := maximumIncFail if exclusive { - m = maxExcFail + m = maximumExcFail } - message = fmt.Sprintf(m, name, in, max) + message = fmt.Sprintf(m, name, in, maximum) } return &Validation{ code: MaxFailCode, @@ -353,21 +357,21 @@ func ExceedsMaximumInt(name, in string, max int64, exclusive bool, value interfa } } -// ExceedsMaximumUint error for when maximum validation fails -func ExceedsMaximumUint(name, in string, max uint64, exclusive bool, value interface{}) *Validation { +// ExceedsMaximumUint error for when maximumimum validation fails +func ExceedsMaximumUint(name, in string, maximum uint64, exclusive bool, value interface{}) *Validation { var message string if in == "" { - m := maxIncFailNoIn + m := maximumIncFailNoIn if exclusive { - m = maxExcFailNoIn + m = maximumExcFailNoIn } - message = fmt.Sprintf(m, name, max) + message = fmt.Sprintf(m, name, maximum) } else { - m := maxIncFail + m := maximumIncFail if exclusive { - m = maxExcFail + m = maximumExcFail } - message = fmt.Sprintf(m, name, in, max) + message = fmt.Sprintf(m, name, in, maximum) } return &Validation{ code: MaxFailCode, @@ -378,21 +382,21 @@ func ExceedsMaximumUint(name, in string, max uint64, exclusive bool, value inter } } -// ExceedsMaximum error for when maximum validation fails -func ExceedsMaximum(name, in string, max float64, exclusive bool, value interface{}) *Validation { +// ExceedsMaximum error for when maximumimum validation fails +func ExceedsMaximum(name, in string, maximum float64, exclusive bool, value interface{}) *Validation { var message string if in == "" { - m := maxIncFailNoIn + m := maximumIncFailNoIn if exclusive { - m = maxExcFailNoIn + m = maximumExcFailNoIn } - message = fmt.Sprintf(m, name, max) + message = fmt.Sprintf(m, name, maximum) } else { - m := maxIncFail + m := maximumIncFail if exclusive { - m = maxExcFail + m = maximumExcFail } - message = fmt.Sprintf(m, name, in, max) + message = fmt.Sprintf(m, name, in, maximum) } return &Validation{ code: MaxFailCode, @@ -404,20 +408,20 @@ func ExceedsMaximum(name, in string, max float64, exclusive bool, value interfac } // ExceedsMinimumInt error for when minimum validation fails -func ExceedsMinimumInt(name, in string, min int64, exclusive bool, value interface{}) *Validation { +func ExceedsMinimumInt(name, in string, minimum int64, exclusive bool, value interface{}) *Validation { var message string if in == "" { m := minIncFailNoIn if exclusive { m = minExcFailNoIn } - message = fmt.Sprintf(m, name, min) + message = fmt.Sprintf(m, name, minimum) } else { m := minIncFail if exclusive { m = minExcFail } - message = fmt.Sprintf(m, name, in, min) + message = fmt.Sprintf(m, name, in, minimum) } return &Validation{ code: MinFailCode, @@ -429,20 +433,20 @@ func ExceedsMinimumInt(name, in string, min int64, exclusive bool, value interfa } // ExceedsMinimumUint error for when minimum validation fails -func ExceedsMinimumUint(name, in string, min uint64, exclusive bool, value interface{}) *Validation { +func ExceedsMinimumUint(name, in string, minimum uint64, exclusive bool, value interface{}) *Validation { var message string if in == "" { m := minIncFailNoIn if exclusive { m = minExcFailNoIn } - message = fmt.Sprintf(m, name, min) + message = fmt.Sprintf(m, name, minimum) } else { m := minIncFail if exclusive { m = minExcFail } - message = fmt.Sprintf(m, name, in, min) + message = fmt.Sprintf(m, name, in, minimum) } return &Validation{ code: MinFailCode, @@ -454,20 +458,20 @@ func ExceedsMinimumUint(name, in string, min uint64, exclusive bool, value inter } // ExceedsMinimum error for when minimum validation fails -func ExceedsMinimum(name, in string, min float64, exclusive bool, value interface{}) *Validation { +func ExceedsMinimum(name, in string, minimum float64, exclusive bool, value interface{}) *Validation { var message string if in == "" { m := minIncFailNoIn if exclusive { m = minExcFailNoIn } - message = fmt.Sprintf(m, name, min) + message = fmt.Sprintf(m, name, minimum) } else { m := minIncFail if exclusive { m = minExcFail } - message = fmt.Sprintf(m, name, in, min) + message = fmt.Sprintf(m, name, in, minimum) } return &Validation{ code: MinFailCode, @@ -549,12 +553,12 @@ func ReadOnly(name, in string, value interface{}) *Validation { } // TooLong error for when a string is too long -func TooLong(name, in string, max int64, value interface{}) *Validation { +func TooLong(name, in string, maximum int64, value interface{}) *Validation { var msg string if in == "" { - msg = fmt.Sprintf(tooLongMessageNoIn, name, max) + msg = fmt.Sprintf(tooLongMessageNoIn, name, maximum) } else { - msg = fmt.Sprintf(tooLongMessage, name, in, max) + msg = fmt.Sprintf(tooLongMessage, name, in, maximum) } return &Validation{ code: TooLongFailCode, @@ -566,12 +570,12 @@ func TooLong(name, in string, max int64, value interface{}) *Validation { } // TooShort error for when a string is too short -func TooShort(name, in string, min int64, value interface{}) *Validation { +func TooShort(name, in string, minimum int64, value interface{}) *Validation { var msg string if in == "" { - msg = fmt.Sprintf(tooShortMessageNoIn, name, min) + msg = fmt.Sprintf(tooShortMessageNoIn, name, minimum) } else { - msg = fmt.Sprintf(tooShortMessage, name, in, min) + msg = fmt.Sprintf(tooShortMessage, name, in, minimum) } return &Validation{ diff --git a/vendor/github.com/go-openapi/inflect/.golangci.yml b/vendor/github.com/go-openapi/inflect/.golangci.yml index 22f8d21cc..b4ded785e 100644 --- a/vendor/github.com/go-openapi/inflect/.golangci.yml +++ b/vendor/github.com/go-openapi/inflect/.golangci.yml @@ -1,61 +1,64 @@ -linters-settings: - govet: - check-shadowing: true - golint: - min-confidence: 0 - gocyclo: - min-complexity: 45 - maligned: - suggest-new: true - dupl: - threshold: 200 - goconst: - min-len: 2 - min-occurrences: 3 - +version: "2" linters: - enable-all: true + default: all disable: - - maligned - - unparam - - lll - - gochecknoinits - - gochecknoglobals + - cyclop + - depguard + - errchkjson + - errorlint + - exhaustruct + - forcetypeassert - funlen - - godox + - gochecknoglobals + - gochecknoinits - gocognit - - whitespace - - wsl - - wrapcheck - - testpackage - - nlreturn - - gomnd - - exhaustivestruct - - goerr113 - - errorlint - - nestif - godot - - gofumpt + - godox + - gosmopolitan + - inamedparam + - ireturn + - lll + - musttag + - nestif + - nlreturn + - noinlineerr + - nonamedreturns - paralleltest - - tparallel + - testpackage - thelper - - ifshort - - exhaustruct + - tparallel + - unparam - varnamelen - - gci - - depguard - - errchkjson - - inamedparam - - nonamedreturns - - musttag - - ireturn - - forcetypeassert - - cyclop - # deprecated linters - - deadcode - - interfacer - - scopelint - - varcheck - - structcheck - - golint - - nosnakecase + - whitespace + - wrapcheck + - wsl + - wsl_v5 + settings: + dupl: + threshold: 200 + goconst: + min-len: 2 + min-occurrences: 3 + gocyclo: + min-complexity: 45 + exclusions: + generated: lax + presets: + - comments + - common-false-positives + - legacy + - std-error-handling + paths: + - third_party$ + - builtin$ + - examples$ +formatters: + enable: + - gofmt + - goimports + exclusions: + generated: lax + paths: + - third_party$ + - builtin$ + - examples$ diff --git a/vendor/github.com/go-openapi/inflect/inflect.go b/vendor/github.com/go-openapi/inflect/inflect.go index 9d8ca6dbd..2a421c06b 100644 --- a/vendor/github.com/go-openapi/inflect/inflect.go +++ b/vendor/github.com/go-openapi/inflect/inflect.go @@ -307,15 +307,6 @@ func (rs *Ruleset) AddUncountable(word string) { rs.uncountables[strings.ToLower(word)] = true } -func (rs *Ruleset) isUncountable(word string) bool { - // handle multiple words by using the last one - words := strings.Split(word, " ") - if _, exists := rs.uncountables[strings.ToLower(words[len(words)-1])]; exists { - return true - } - return false -} - // returns the plural form of a singular word func (rs *Ruleset) Pluralize(word string) string { if len(word) == 0 { @@ -383,20 +374,6 @@ func (rs *Ruleset) Titleize(word string) string { return strings.Join(words, " ") } -func (rs *Ruleset) safeCaseAcronyms(word string) string { - // convert an acroymn like HTML into Html - for _, rule := range rs.acronyms { - word = strings.ReplaceAll(word, rule.suffix, rule.replacement) - } - return word -} - -func (rs *Ruleset) seperatedWords(word, sep string) string { - word = rs.safeCaseAcronyms(word) - words := splitAtCaseChange(word) - return strings.Join(words, sep) -} - // lowercase underscore version "BigBen" -> "big_ben" func (rs *Ruleset) Underscore(word string) string { return rs.seperatedWords(word, "_") @@ -452,32 +429,6 @@ func (rs *Ruleset) ParameterizeJoin(word, sep string) string { return word } -var lookalikes = map[string]*regexp.Regexp{ - "A": regexp.MustCompile(`À|Á|Â|Ã|Ä|Å`), - "AE": regexp.MustCompile(`Æ`), - "C": regexp.MustCompile(`Ç`), - "E": regexp.MustCompile(`È|É|Ê|Ë`), - "G": regexp.MustCompile(`Ğ`), - "I": regexp.MustCompile(`Ì|Í|Î|Ï|İ`), - "N": regexp.MustCompile(`Ñ`), - "O": regexp.MustCompile(`Ò|Ó|Ô|Õ|Ö|Ø`), - "S": regexp.MustCompile(`Ş`), - "U": regexp.MustCompile(`Ù|Ú|Û|Ü`), - "Y": regexp.MustCompile(`Ý`), - "ss": regexp.MustCompile(`ß`), - "a": regexp.MustCompile(`à|á|â|ã|ä|å`), - "ae": regexp.MustCompile(`æ`), - "c": regexp.MustCompile(`ç`), - "e": regexp.MustCompile(`è|é|ê|ë`), - "g": regexp.MustCompile(`ğ`), - "i": regexp.MustCompile(`ì|í|î|ï|ı`), - "n": regexp.MustCompile(`ñ`), - "o": regexp.MustCompile(`ò|ó|ô|õ|ö|ø`), - "s": regexp.MustCompile(`ş`), - "u": regexp.MustCompile(`ù|ú|û|ü|ũ|ū|ŭ|ů|ű|ų`), - "y": regexp.MustCompile(`ý|ÿ`), -} - // transforms latin characters like é -> e func (rs *Ruleset) Asciify(word string) string { for repl, regex := range lookalikes { @@ -500,6 +451,8 @@ func (rs *Ruleset) Dasherize(word string) string { } // "1031" -> "1031st" +// +//nolint:mnd func (rs *Ruleset) Ordinalize(str string) string { number, err := strconv.Atoi(str) if err != nil { @@ -521,6 +474,55 @@ func (rs *Ruleset) Ordinalize(str string) string { return fmt.Sprintf("%dth", number) } +func (rs *Ruleset) isUncountable(word string) bool { + // handle multiple words by using the last one + words := strings.Split(word, " ") + if _, exists := rs.uncountables[strings.ToLower(words[len(words)-1])]; exists { + return true + } + return false +} + +func (rs *Ruleset) safeCaseAcronyms(word string) string { + // convert an acroymn like HTML into Html + for _, rule := range rs.acronyms { + word = strings.ReplaceAll(word, rule.suffix, rule.replacement) + } + return word +} + +func (rs *Ruleset) seperatedWords(word, sep string) string { + word = rs.safeCaseAcronyms(word) + words := splitAtCaseChange(word) + return strings.Join(words, sep) +} + +var lookalikes = map[string]*regexp.Regexp{ + "A": regexp.MustCompile(`À|Á|Â|Ã|Ä|Å`), + "AE": regexp.MustCompile(`Æ`), + "C": regexp.MustCompile(`Ç`), + "E": regexp.MustCompile(`È|É|Ê|Ë`), + "G": regexp.MustCompile(`Ğ`), + "I": regexp.MustCompile(`Ì|Í|Î|Ï|İ`), + "N": regexp.MustCompile(`Ñ`), + "O": regexp.MustCompile(`Ò|Ó|Ô|Õ|Ö|Ø`), + "S": regexp.MustCompile(`Ş`), + "U": regexp.MustCompile(`Ù|Ú|Û|Ü`), + "Y": regexp.MustCompile(`Ý`), + "ss": regexp.MustCompile(`ß`), + "a": regexp.MustCompile(`à|á|â|ã|ä|å`), + "ae": regexp.MustCompile(`æ`), + "c": regexp.MustCompile(`ç`), + "e": regexp.MustCompile(`è|é|ê|ë`), + "g": regexp.MustCompile(`ğ`), + "i": regexp.MustCompile(`ì|í|î|ï|ı`), + "n": regexp.MustCompile(`ñ`), + "o": regexp.MustCompile(`ò|ó|ô|õ|ö|ø`), + "s": regexp.MustCompile(`ş`), + "u": regexp.MustCompile(`ù|ú|û|ü|ũ|ū|ŭ|ů|ű|ų`), + "y": regexp.MustCompile(`ý|ÿ`), +} + ///////////////////////////////////////// // the default global ruleset ////////////////////////////////////////// diff --git a/vendor/github.com/go-openapi/jsonpointer/.golangci.yml b/vendor/github.com/go-openapi/jsonpointer/.golangci.yml index 22f8d21cc..500630621 100644 --- a/vendor/github.com/go-openapi/jsonpointer/.golangci.yml +++ b/vendor/github.com/go-openapi/jsonpointer/.golangci.yml @@ -1,61 +1,62 @@ -linters-settings: - govet: - check-shadowing: true - golint: - min-confidence: 0 - gocyclo: - min-complexity: 45 - maligned: - suggest-new: true - dupl: - threshold: 200 - goconst: - min-len: 2 - min-occurrences: 3 - +version: "2" linters: - enable-all: true + default: all disable: - - maligned - - unparam - - lll - - gochecknoinits - - gochecknoglobals + - cyclop + - depguard + - errchkjson + - errorlint + - exhaustruct + - forcetypeassert - funlen - - godox + - gochecknoglobals + - gochecknoinits - gocognit - - whitespace - - wsl - - wrapcheck - - testpackage - - nlreturn - - gomnd - - exhaustivestruct - - goerr113 - - errorlint - - nestif - godot - - gofumpt + - godox + - gosmopolitan + - inamedparam + - ireturn + - lll + - musttag + - nestif + - nlreturn + - nonamedreturns - paralleltest - - tparallel + - testpackage - thelper - - ifshort - - exhaustruct + - tparallel + - unparam - varnamelen - - gci - - depguard - - errchkjson - - inamedparam - - nonamedreturns - - musttag - - ireturn - - forcetypeassert - - cyclop - # deprecated linters - - deadcode - - interfacer - - scopelint - - varcheck - - structcheck - - golint - - nosnakecase + - whitespace + - wrapcheck + - wsl + settings: + dupl: + threshold: 200 + goconst: + min-len: 2 + min-occurrences: 3 + gocyclo: + min-complexity: 45 + exclusions: + generated: lax + presets: + - comments + - common-false-positives + - legacy + - std-error-handling + paths: + - third_party$ + - builtin$ + - examples$ +formatters: + enable: + - gofmt + - goimports + exclusions: + generated: lax + paths: + - third_party$ + - builtin$ + - examples$ diff --git a/vendor/github.com/go-openapi/jsonpointer/errors.go b/vendor/github.com/go-openapi/jsonpointer/errors.go new file mode 100644 index 000000000..b84343d9d --- /dev/null +++ b/vendor/github.com/go-openapi/jsonpointer/errors.go @@ -0,0 +1,18 @@ +package jsonpointer + +type pointerError string + +func (e pointerError) Error() string { + return string(e) +} + +const ( + // ErrPointer is an error raised by the jsonpointer package + ErrPointer pointerError = "JSON pointer error" + + // ErrInvalidStart states that a JSON pointer must start with a separator ("/") + ErrInvalidStart pointerError = `JSON pointer must be empty or start with a "` + pointerSeparator + + // ErrUnsupportedValueType indicates that a value of the wrong type is being set + ErrUnsupportedValueType pointerError = "only structs, pointers, maps and slices are supported for setting values" +) diff --git a/vendor/github.com/go-openapi/jsonpointer/pointer.go b/vendor/github.com/go-openapi/jsonpointer/pointer.go index d970c7cf4..613621057 100644 --- a/vendor/github.com/go-openapi/jsonpointer/pointer.go +++ b/vendor/github.com/go-openapi/jsonpointer/pointer.go @@ -39,9 +39,6 @@ import ( const ( emptyPointer = `` pointerSeparator = `/` - - invalidStart = `JSON pointer must be empty or start with a "` + pointerSeparator - notFound = `Can't find the pointer in the document` ) var jsonPointableType = reflect.TypeOf(new(JSONPointable)).Elem() @@ -80,7 +77,7 @@ func (p *Pointer) parse(jsonPointerString string) error { if jsonPointerString != emptyPointer { if !strings.HasPrefix(jsonPointerString, pointerSeparator) { - err = errors.New(invalidStart) + err = errors.Join(ErrInvalidStart, ErrPointer) } else { referenceTokens := strings.Split(jsonPointerString, pointerSeparator) p.referenceTokens = append(p.referenceTokens, referenceTokens[1:]...) @@ -128,7 +125,7 @@ func getSingleImpl(node any, decodedToken string, nameProvider *swag.NameProvide rValue := reflect.Indirect(reflect.ValueOf(node)) kind := rValue.Kind() if isNil(node) { - return nil, kind, fmt.Errorf("nil value has not field %q", decodedToken) + return nil, kind, fmt.Errorf("nil value has no field %q: %w", decodedToken, ErrPointer) } switch typed := node.(type) { @@ -146,7 +143,7 @@ func getSingleImpl(node any, decodedToken string, nameProvider *swag.NameProvide case reflect.Struct: nm, ok := nameProvider.GetGoNameForType(rValue.Type(), decodedToken) if !ok { - return nil, kind, fmt.Errorf("object has no field %q", decodedToken) + return nil, kind, fmt.Errorf("object has no field %q: %w", decodedToken, ErrPointer) } fld := rValue.FieldByName(nm) return fld.Interface(), kind, nil @@ -158,7 +155,7 @@ func getSingleImpl(node any, decodedToken string, nameProvider *swag.NameProvide if mv.IsValid() { return mv.Interface(), kind, nil } - return nil, kind, fmt.Errorf("object has no key %q", decodedToken) + return nil, kind, fmt.Errorf("object has no key %q: %w", decodedToken, ErrPointer) case reflect.Slice: tokenIndex, err := strconv.Atoi(decodedToken) @@ -167,14 +164,14 @@ func getSingleImpl(node any, decodedToken string, nameProvider *swag.NameProvide } sLength := rValue.Len() if tokenIndex < 0 || tokenIndex >= sLength { - return nil, kind, fmt.Errorf("index out of bounds array[0,%d] index '%d'", sLength-1, tokenIndex) + return nil, kind, fmt.Errorf("index out of bounds array[0,%d] index '%d': %w", sLength-1, tokenIndex, ErrPointer) } elem := rValue.Index(tokenIndex) return elem.Interface(), kind, nil default: - return nil, kind, fmt.Errorf("invalid token reference %q", decodedToken) + return nil, kind, fmt.Errorf("invalid token reference %q: %w", decodedToken, ErrPointer) } } @@ -182,6 +179,11 @@ func getSingleImpl(node any, decodedToken string, nameProvider *swag.NameProvide func setSingleImpl(node, data any, decodedToken string, nameProvider *swag.NameProvider) error { rValue := reflect.Indirect(reflect.ValueOf(node)) + // Check for nil to prevent panic when calling rValue.Type() + if isNil(node) { + return fmt.Errorf("cannot set field %q on nil value: %w", decodedToken, ErrPointer) + } + if ns, ok := node.(JSONSetable); ok { // pointer impl return ns.JSONSet(decodedToken, data) } @@ -194,7 +196,7 @@ func setSingleImpl(node, data any, decodedToken string, nameProvider *swag.NameP case reflect.Struct: nm, ok := nameProvider.GetGoNameForType(rValue.Type(), decodedToken) if !ok { - return fmt.Errorf("object has no field %q", decodedToken) + return fmt.Errorf("object has no field %q: %w", decodedToken, ErrPointer) } fld := rValue.FieldByName(nm) if fld.IsValid() { @@ -214,18 +216,18 @@ func setSingleImpl(node, data any, decodedToken string, nameProvider *swag.NameP } sLength := rValue.Len() if tokenIndex < 0 || tokenIndex >= sLength { - return fmt.Errorf("index out of bounds array[0,%d] index '%d'", sLength, tokenIndex) + return fmt.Errorf("index out of bounds array[0,%d] index '%d': %w", sLength, tokenIndex, ErrPointer) } elem := rValue.Index(tokenIndex) if !elem.CanSet() { - return fmt.Errorf("can't set slice index %s to %v", decodedToken, data) + return fmt.Errorf("can't set slice index %s to %v: %w", decodedToken, data, ErrPointer) } elem.Set(reflect.ValueOf(data)) return nil default: - return fmt.Errorf("invalid token reference %q", decodedToken) + return fmt.Errorf("invalid token reference %q: %w", decodedToken, ErrPointer) } } @@ -244,7 +246,6 @@ func (p *Pointer) get(node any, nameProvider *swag.NameProvider) (any, reflect.K } for _, token := range p.referenceTokens { - decodedToken := Unescape(token) r, knd, err := getSingleImpl(node, decodedToken, nameProvider) @@ -264,7 +265,10 @@ func (p *Pointer) set(node, data any, nameProvider *swag.NameProvider) error { knd := reflect.ValueOf(node).Kind() if knd != reflect.Ptr && knd != reflect.Struct && knd != reflect.Map && knd != reflect.Slice && knd != reflect.Array { - return errors.New("only structs, pointers, maps and slices are supported for setting values") + return errors.Join( + ErrUnsupportedValueType, + ErrPointer, + ) } if nameProvider == nil { @@ -286,6 +290,11 @@ func (p *Pointer) set(node, data any, nameProvider *swag.NameProvider) error { return setSingleImpl(node, data, decodedToken, nameProvider) } + // Check for nil during traversal + if isNil(node) { + return fmt.Errorf("cannot traverse through nil value at %q: %w", decodedToken, ErrPointer) + } + rValue := reflect.Indirect(reflect.ValueOf(node)) kind := rValue.Kind() @@ -307,7 +316,7 @@ func (p *Pointer) set(node, data any, nameProvider *swag.NameProvider) error { case reflect.Struct: nm, ok := nameProvider.GetGoNameForType(rValue.Type(), decodedToken) if !ok { - return fmt.Errorf("object has no field %q", decodedToken) + return fmt.Errorf("object has no field %q: %w", decodedToken, ErrPointer) } fld := rValue.FieldByName(nm) if fld.CanAddr() && fld.Kind() != reflect.Interface && fld.Kind() != reflect.Map && fld.Kind() != reflect.Slice && fld.Kind() != reflect.Ptr { @@ -321,7 +330,7 @@ func (p *Pointer) set(node, data any, nameProvider *swag.NameProvider) error { mv := rValue.MapIndex(kv) if !mv.IsValid() { - return fmt.Errorf("object has no key %q", decodedToken) + return fmt.Errorf("object has no key %q: %w", decodedToken, ErrPointer) } if mv.CanAddr() && mv.Kind() != reflect.Interface && mv.Kind() != reflect.Map && mv.Kind() != reflect.Slice && mv.Kind() != reflect.Ptr { node = mv.Addr().Interface() @@ -336,7 +345,7 @@ func (p *Pointer) set(node, data any, nameProvider *swag.NameProvider) error { } sLength := rValue.Len() if tokenIndex < 0 || tokenIndex >= sLength { - return fmt.Errorf("index out of bounds array[0,%d] index '%d'", sLength, tokenIndex) + return fmt.Errorf("index out of bounds array[0,%d] index '%d': %w", sLength, tokenIndex, ErrPointer) } elem := rValue.Index(tokenIndex) @@ -347,7 +356,7 @@ func (p *Pointer) set(node, data any, nameProvider *swag.NameProvider) error { node = elem.Interface() default: - return fmt.Errorf("invalid token reference %q", decodedToken) + return fmt.Errorf("invalid token reference %q: %w", decodedToken, ErrPointer) } } @@ -404,10 +413,10 @@ func (p *Pointer) Offset(document string) (int64, error) { return 0, err } default: - return 0, fmt.Errorf("invalid token %#v", tk) + return 0, fmt.Errorf("invalid token %#v: %w", tk, ErrPointer) } default: - return 0, fmt.Errorf("invalid token %#v", tk) + return 0, fmt.Errorf("invalid token %#v: %w", tk, ErrPointer) } } return offset, nil @@ -437,16 +446,16 @@ func offsetSingleObject(dec *json.Decoder, decodedToken string) (int64, error) { return offset, nil } default: - return 0, fmt.Errorf("invalid token %#v", tk) + return 0, fmt.Errorf("invalid token %#v: %w", tk, ErrPointer) } } - return 0, fmt.Errorf("token reference %q not found", decodedToken) + return 0, fmt.Errorf("token reference %q not found: %w", decodedToken, ErrPointer) } func offsetSingleArray(dec *json.Decoder, decodedToken string) (int64, error) { idx, err := strconv.Atoi(decodedToken) if err != nil { - return 0, fmt.Errorf("token reference %q is not a number: %v", decodedToken, err) + return 0, fmt.Errorf("token reference %q is not a number: %v: %w", decodedToken, err, ErrPointer) } var i int for i = 0; i < idx && dec.More(); i++ { @@ -470,7 +479,7 @@ func offsetSingleArray(dec *json.Decoder, decodedToken string) (int64, error) { } if !dec.More() { - return 0, fmt.Errorf("token reference %q not found", decodedToken) + return 0, fmt.Errorf("token reference %q not found: %w", decodedToken, ErrPointer) } return dec.InputOffset(), nil } diff --git a/vendor/github.com/go-openapi/swag/.golangci.yml b/vendor/github.com/go-openapi/swag/.golangci.yml index 80e2be004..d2fafb8a2 100644 --- a/vendor/github.com/go-openapi/swag/.golangci.yml +++ b/vendor/github.com/go-openapi/swag/.golangci.yml @@ -1,22 +1,17 @@ linters-settings: - govet: - check-shadowing: true - golint: - min-confidence: 0 gocyclo: min-complexity: 45 - maligned: - suggest-new: true dupl: threshold: 200 goconst: - min-len: 3 + min-len: 2 min-occurrences: 3 linters: enable-all: true disable: - - maligned + - recvcheck + - unparam - lll - gochecknoinits - gochecknoglobals @@ -28,9 +23,6 @@ linters: - wrapcheck - testpackage - nlreturn - - gomnd - - exhaustivestruct - - goerr113 - errorlint - nestif - godot @@ -38,7 +30,6 @@ linters: - paralleltest - tparallel - thelper - - ifshort - exhaustruct - varnamelen - gci @@ -51,10 +42,15 @@ linters: - forcetypeassert - cyclop # deprecated linters - - deadcode - - interfacer - - scopelint - - varcheck - - structcheck - - golint - - nosnakecase + #- deadcode + #- interfacer + #- scopelint + #- varcheck + #- structcheck + #- golint + #- nosnakecase + #- maligned + #- goerr113 + #- ifshort + #- gomnd + #- exhaustivestruct diff --git a/vendor/github.com/go-openapi/swag/errors.go b/vendor/github.com/go-openapi/swag/errors.go new file mode 100644 index 000000000..6c67fbf92 --- /dev/null +++ b/vendor/github.com/go-openapi/swag/errors.go @@ -0,0 +1,15 @@ +package swag + +type swagError string + +const ( + // ErrYAML is an error raised by YAML utilities + ErrYAML swagError = "yaml error" + + // ErrLoader is an error raised by the file loader utility + ErrLoader swagError = "loader error" +) + +func (e swagError) Error() string { + return string(e) +} diff --git a/vendor/github.com/go-openapi/swag/json.go b/vendor/github.com/go-openapi/swag/json.go index 7e9902ca3..c7caa9908 100644 --- a/vendor/github.com/go-openapi/swag/json.go +++ b/vendor/github.com/go-openapi/swag/json.go @@ -126,7 +126,8 @@ func ConcatJSON(blobs ...[]byte) []byte { continue // don't know how to concatenate non container objects } - if len(b) < 3 { // yep empty but also the last one, so closing this thing + const minLengthIfNotEmpty = 3 + if len(b) < minLengthIfNotEmpty { // yep empty but also the last one, so closing this thing if i == last && a > 0 { if err := buf.WriteByte(closing); err != nil { log.Println(err) diff --git a/vendor/github.com/go-openapi/swag/loading.go b/vendor/github.com/go-openapi/swag/loading.go index 783442fdd..658a24b78 100644 --- a/vendor/github.com/go-openapi/swag/loading.go +++ b/vendor/github.com/go-openapi/swag/loading.go @@ -168,7 +168,7 @@ func loadHTTPBytes(timeout time.Duration) func(path string) ([]byte, error) { } if resp.StatusCode != http.StatusOK { - return nil, fmt.Errorf("could not access document at %q [%s] ", path, resp.Status) + return nil, fmt.Errorf("could not access document at %q [%s]: %w", path, resp.Status, ErrLoader) } return io.ReadAll(resp.Body) diff --git a/vendor/github.com/go-openapi/swag/yaml.go b/vendor/github.com/go-openapi/swag/yaml.go index f59e02593..575346539 100644 --- a/vendor/github.com/go-openapi/swag/yaml.go +++ b/vendor/github.com/go-openapi/swag/yaml.go @@ -16,7 +16,6 @@ package swag import ( "encoding/json" - "errors" "fmt" "path/filepath" "reflect" @@ -51,7 +50,7 @@ func BytesToYAMLDoc(data []byte) (interface{}, error) { return nil, err } if document.Kind != yaml.DocumentNode || len(document.Content) != 1 || document.Content[0].Kind != yaml.MappingNode { - return nil, errors.New("only YAML documents that are objects are supported") + return nil, fmt.Errorf("only YAML documents that are objects are supported: %w", ErrYAML) } return &document, nil } @@ -69,31 +68,32 @@ func yamlNode(root *yaml.Node) (interface{}, error) { case yaml.AliasNode: return yamlNode(root.Alias) default: - return nil, fmt.Errorf("unsupported YAML node type: %v", root.Kind) + return nil, fmt.Errorf("unsupported YAML node type: %v: %w", root.Kind, ErrYAML) } } func yamlDocument(node *yaml.Node) (interface{}, error) { if len(node.Content) != 1 { - return nil, fmt.Errorf("unexpected YAML Document node content length: %d", len(node.Content)) + return nil, fmt.Errorf("unexpected YAML Document node content length: %d: %w", len(node.Content), ErrYAML) } return yamlNode(node.Content[0]) } func yamlMapping(node *yaml.Node) (interface{}, error) { - m := make(JSONMapSlice, len(node.Content)/2) + const sensibleAllocDivider = 2 + m := make(JSONMapSlice, len(node.Content)/sensibleAllocDivider) var j int for i := 0; i < len(node.Content); i += 2 { var nmi JSONMapItem k, err := yamlStringScalarC(node.Content[i]) if err != nil { - return nil, fmt.Errorf("unable to decode YAML map key: %w", err) + return nil, fmt.Errorf("unable to decode YAML map key: %w: %w", err, ErrYAML) } nmi.Key = k v, err := yamlNode(node.Content[i+1]) if err != nil { - return nil, fmt.Errorf("unable to process YAML map value for key %q: %w", k, err) + return nil, fmt.Errorf("unable to process YAML map value for key %q: %w: %w", k, err, ErrYAML) } nmi.Value = v m[j] = nmi @@ -109,7 +109,7 @@ func yamlSequence(node *yaml.Node) (interface{}, error) { v, err := yamlNode(node.Content[i]) if err != nil { - return nil, fmt.Errorf("unable to decode YAML sequence value: %w", err) + return nil, fmt.Errorf("unable to decode YAML sequence value: %w: %w", err, ErrYAML) } s = append(s, v) } @@ -132,19 +132,19 @@ func yamlScalar(node *yaml.Node) (interface{}, error) { case yamlBoolScalar: b, err := strconv.ParseBool(node.Value) if err != nil { - return nil, fmt.Errorf("unable to process scalar node. Got %q. Expecting bool content: %w", node.Value, err) + return nil, fmt.Errorf("unable to process scalar node. Got %q. Expecting bool content: %w: %w", node.Value, err, ErrYAML) } return b, nil case yamlIntScalar: i, err := strconv.ParseInt(node.Value, 10, 64) if err != nil { - return nil, fmt.Errorf("unable to process scalar node. Got %q. Expecting integer content: %w", node.Value, err) + return nil, fmt.Errorf("unable to process scalar node. Got %q. Expecting integer content: %w: %w", node.Value, err, ErrYAML) } return i, nil case yamlFloatScalar: f, err := strconv.ParseFloat(node.Value, 64) if err != nil { - return nil, fmt.Errorf("unable to process scalar node. Got %q. Expecting float content: %w", node.Value, err) + return nil, fmt.Errorf("unable to process scalar node. Got %q. Expecting float content: %w: %w", node.Value, err, ErrYAML) } return f, nil case yamlTimestamp: @@ -152,19 +152,19 @@ func yamlScalar(node *yaml.Node) (interface{}, error) { case yamlNull: return nil, nil //nolint:nilnil default: - return nil, fmt.Errorf("YAML tag %q is not supported", node.LongTag()) + return nil, fmt.Errorf("YAML tag %q is not supported: %w", node.LongTag(), ErrYAML) } } func yamlStringScalarC(node *yaml.Node) (string, error) { if node.Kind != yaml.ScalarNode { - return "", fmt.Errorf("expecting a string scalar but got %q", node.Kind) + return "", fmt.Errorf("expecting a string scalar but got %q: %w", node.Kind, ErrYAML) } switch node.LongTag() { case yamlStringScalar, yamlIntScalar, yamlFloatScalar: return node.Value, nil default: - return "", fmt.Errorf("YAML tag %q is not supported as map key", node.LongTag()) + return "", fmt.Errorf("YAML tag %q is not supported as map key: %w", node.LongTag(), ErrYAML) } } @@ -349,7 +349,7 @@ func json2yaml(item interface{}) (*yaml.Node, error) { Value: strconv.FormatBool(val), }, nil default: - return nil, fmt.Errorf("unhandled type: %T", val) + return nil, fmt.Errorf("unhandled type: %T: %w", val, ErrYAML) } } @@ -416,7 +416,7 @@ func transformData(input interface{}) (out interface{}, err error) { case int64: return strconv.FormatInt(k, 10), nil default: - return "", fmt.Errorf("unexpected map key type, got: %T", k) + return "", fmt.Errorf("unexpected map key type, got: %T: %w", k, ErrYAML) } } diff --git a/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/diff.go b/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/diff.go index 2faba2537..f1579f163 100644 --- a/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/diff.go +++ b/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/diff.go @@ -9,6 +9,7 @@ import ( "os" "github.com/go-openapi/loads" + "github.com/go-swagger/go-swagger/cmd/swagger/commands/diff" ) @@ -42,7 +43,7 @@ func (c *DiffCommand) Execute(_ []string) error { err error ) if c.Destination != "stdout" { - output, err = os.OpenFile(c.Destination, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0600) + output, err = os.OpenFile(c.Destination, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0o600) if err != nil { return fmt.Errorf("%s: %w", c.Destination, err) } diff --git a/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/diff/checks.go b/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/diff/checks.go index 627bc5f7b..ba9fa008b 100644 --- a/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/diff/checks.go +++ b/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/diff/checks.go @@ -76,7 +76,6 @@ func CompareProperties(location DifferenceLocation, schema1 *spec.Schema, schema } } return propDiffs - } // CompareFloatValues compares a float data item @@ -123,7 +122,6 @@ func CompareIntValues(fieldName string, val1 *int64, val2 *int64, ifGreaterCode // CheckToFromPrimitiveType check for diff to or from a primitive func CheckToFromPrimitiveType(diffs []TypeDiff, type1, type2 interface{}) []TypeDiff { - type1IsPrimitive := isPrimitive(type1) type2IsPrimitive := isPrimitive(type2) @@ -139,7 +137,6 @@ func CheckToFromPrimitiveType(diffs []TypeDiff, type1, type2 interface{}) []Type // CheckRefChange has the property ref changed func CheckRefChange(diffs []TypeDiff, type1, type2 interface{}) (diffReturn []TypeDiff) { - diffReturn = diffs if isRefType(type1) && isRefType(type2) { // both refs but to different objects (TODO detect renamed object) diff --git a/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/diff/node.go b/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/diff/node.go index e1c7c95f1..74b57796a 100644 --- a/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/diff/node.go +++ b/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/diff/node.go @@ -30,7 +30,6 @@ func (n *Node) String() string { // AddLeafNode Adds (recursive) a Child to the first non-nil child found func (n *Node) AddLeafNode(toAdd *Node) *Node { - if n.ChildNode == nil { n.ChildNode = toAdd } else { diff --git a/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/diff/schema.go b/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/diff/schema.go index 0874154bb..52464a9ba 100644 --- a/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/diff/schema.go +++ b/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/diff/schema.go @@ -18,7 +18,6 @@ func getTypeFromSchema(schema *spec.Schema) (typeName string, isArray bool) { return typeName, true } return typeName, false - } func getTypeFromSimpleSchema(schema *spec.SimpleSchema) (typeName string, isArray bool) { @@ -32,7 +31,6 @@ func getTypeFromSimpleSchema(schema *spec.SimpleSchema) (typeName string, isArra return typeName, true } return typeName, false - } func getTypeFromSchemaProps(schema *spec.SchemaProps) (typeName string, isArray bool) { @@ -52,7 +50,6 @@ func getTypeFromSchemaProps(schema *spec.SchemaProps) (typeName string, isArray } } return typeName, false - } func getSchemaTypeStr(item interface{}) string { @@ -61,7 +58,6 @@ func getSchemaTypeStr(item interface{}) string { } func getSchemaType(item interface{}) (typeName string, isArray bool) { - switch s := item.(type) { case *spec.Schema: typeName, isArray = getTypeFromSchema(s) @@ -78,7 +74,6 @@ func getSchemaType(item interface{}) (typeName string, isArray bool) { } return - } func formatTypeString(typ string, isarray bool) string { diff --git a/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/diff/spec_analyser.go b/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/diff/spec_analyser.go index 655af1465..d3b74fa44 100644 --- a/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/diff/spec_analyser.go +++ b/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/diff/spec_analyser.go @@ -3,7 +3,9 @@ package diff import ( "fmt" "reflect" - "strings" + + "golang.org/x/text/cases" + "golang.org/x/text/language" "github.com/go-openapi/spec" ) @@ -20,7 +22,7 @@ type URLMethodResponse struct { // MarshalText - for serializing as a map key func (p URLMethod) MarshalText() (text []byte, err error) { - return []byte(fmt.Sprintf("%s %s", p.Path, p.Method)), nil + return fmt.Appendf([]byte{}, "%s %s", p.Path, p.Method), nil } // URLMethods allows iteration of endpoints based on url and method @@ -38,6 +40,7 @@ type SpecAnalyser struct { ReferencedDefinitions map[string]bool schemasCompared map[string]struct{} + titler cases.Caser } // NewSpecAnalyser returns an empty SpecDiffs @@ -45,6 +48,7 @@ func NewSpecAnalyser() *SpecAnalyser { return &SpecAnalyser{ Diffs: SpecDifferences{}, ReferencedDefinitions: map[string]bool{}, + titler: cases.Title(language.English, cases.NoLower), } } @@ -155,7 +159,6 @@ func (sd *SpecAnalyser) AnalyseDefinitions() { } func (sd *SpecAnalyser) analyseEndpointData() { - for URLMethod, op2 := range sd.urlMethods2 { if op1, ok := sd.urlMethods1[URLMethod]; ok { addedTags, deletedTags, _ := fromStringArray(op1.Operation.Tags).DiffsTo(op2.Operation.Tags) @@ -178,7 +181,8 @@ func (sd *SpecAnalyser) analyseRequestParams() { locations := []string{"query", "path", "body", "header", "formData"} for _, paramLocation := range locations { - rootNode := getNameOnlyDiffNode(strings.Title(paramLocation)) + rootNode := getNameOnlyDiffNode(sd.titler.String(paramLocation)) + sd.titler.Reset() for URLMethod, op2 := range sd.urlMethods2 { if op1, ok := sd.urlMethods1[URLMethod]; ok { @@ -221,7 +225,6 @@ func (sd *SpecAnalyser) analyseRequestParams() { func (sd *SpecAnalyser) analyseResponseParams() { // Loop through url+methods in spec 2 - check deleted and changed for eachURLMethodFrom2, op2 := range sd.urlMethods2 { - // present in both specs? Use key from spec 2 to lookup in spec 1 if op1, ok := sd.urlMethods1[eachURLMethodFrom2]; ok { // compare responses for url and method @@ -246,27 +249,29 @@ func (sd *SpecAnalyser) analyseResponseParams() { // Added updated Response Codes for code2, op2Response := range op2Responses { if op1Response, ok := op1Responses[code2]; ok { - op1Headers := op1Response.ResponseProps.Headers + op1Headers := op1Response.Headers headerRootNode := getNameOnlyDiffNode("Headers") // Iterate Spec2 Headers looking for added and updated location := DifferenceLocation{URL: eachURLMethodFrom2.Path, Method: eachURLMethodFrom2.Method, Response: code2, Node: headerRootNode} - for op2HeaderName, op2Header := range op2Response.ResponseProps.Headers { + for op2HeaderName, op2Header := range op2Response.Headers { if op1Header, ok := op1Headers[op2HeaderName]; ok { diffs := sd.CompareProps(forHeader(op1Header), forHeader(op2Header)) sd.addDiffs(location, diffs) } else { sd.Diffs = sd.Diffs.addDiff(SpecDifference{ DifferenceLocation: location.AddNode(getSchemaDiffNode(op2HeaderName, &op2Header.SimpleSchema)), - Code: AddedResponseHeader}) + Code: AddedResponseHeader, + }) } } - for op1HeaderName := range op1Response.ResponseProps.Headers { - if _, ok := op2Response.ResponseProps.Headers[op1HeaderName]; !ok { - op1Header := op1Response.ResponseProps.Headers[op1HeaderName] + for op1HeaderName := range op1Response.Headers { + if _, ok := op2Response.Headers[op1HeaderName]; !ok { + op1Header := op1Response.Headers[op1HeaderName] sd.Diffs = sd.Diffs.addDiff(SpecDifference{ DifferenceLocation: location.AddNode(getSchemaDiffNode(op1HeaderName, &op1Header.SimpleSchema)), - Code: DeletedResponseHeader}) + Code: DeletedResponseHeader, + }) } } schem := op1Response.Schema @@ -274,17 +279,20 @@ func (sd *SpecAnalyser) analyseResponseParams() { if schem != nil { node = getSchemaDiffNode("Body", &schem.SchemaProps) } - responseLocation := DifferenceLocation{URL: eachURLMethodFrom2.Path, + responseLocation := DifferenceLocation{ + URL: eachURLMethodFrom2.Path, Method: eachURLMethodFrom2.Method, Response: code2, - Node: node} + Node: node, + } sd.compareDescripton(responseLocation, op1Response.Description, op2Response.Description) if op1Response.Schema != nil { if op2Response.Schema == nil { sd.Diffs = sd.Diffs.addDiff(SpecDifference{ DifferenceLocation: DifferenceLocation{URL: eachURLMethodFrom2.Path, Method: eachURLMethodFrom2.Method, Response: code2, Node: getSchemaDiffNode("Body", op1Response.Schema)}, - Code: DeletedProperty}) + Code: DeletedProperty, + }) } else { sd.compareSchema( DifferenceLocation{URL: eachURLMethodFrom2.Path, Method: eachURLMethodFrom2.Method, Response: code2, Node: getSchemaDiffNode("Body", op1Response.Schema)}, @@ -294,14 +302,16 @@ func (sd *SpecAnalyser) analyseResponseParams() { } else if op2Response.Schema != nil { sd.Diffs = sd.Diffs.addDiff(SpecDifference{ DifferenceLocation: DifferenceLocation{URL: eachURLMethodFrom2.Path, Method: eachURLMethodFrom2.Method, Response: code2, Node: getSchemaDiffNode("Body", op2Response.Schema)}, - Code: AddedProperty}) + Code: AddedProperty, + }) } } else { // op2Response sd.Diffs = sd.Diffs.addDiff(SpecDifference{ DifferenceLocation: DifferenceLocation{URL: eachURLMethodFrom2.Path, Method: eachURLMethodFrom2.Method, Response: code2, Node: getSchemaDiffNode("Body", op2Response.Schema)}, - Code: AddedResponse}) + Code: AddedResponse, + }) } } } @@ -538,7 +548,6 @@ func addTypeDiff(diffs []TypeDiff, diff TypeDiff) []TypeDiff { // CompareProps computes type specific property diffs func (sd *SpecAnalyser) CompareProps(type1, type2 *spec.SchemaProps) []TypeDiff { - diffs := []TypeDiff{} diffs = CheckToFromPrimitiveType(diffs, type1, type2) @@ -563,7 +572,7 @@ func (sd *SpecAnalyser) CompareProps(type1, type2 *spec.SchemaProps) []TypeDiff return diffs } - if !(isPrimitiveType(type1.Type) && isPrimitiveType(type2.Type)) { + if !isPrimitiveType(type1.Type) || !isPrimitiveType(type2.Type) { return diffs } @@ -592,7 +601,8 @@ func (sd *SpecAnalyser) CompareProps(type1, type2 *spec.SchemaProps) []TypeDiff func (sd *SpecAnalyser) compareParams(urlMethod URLMethod, location string, name string, param1, param2 spec.Parameter) { diffLocation := DifferenceLocation{URL: urlMethod.Path, Method: urlMethod.Method} - childLocation := diffLocation.AddNode(getNameOnlyDiffNode(strings.Title(location))) + childLocation := diffLocation.AddNode(getNameOnlyDiffNode(sd.titler.String(location))) + sd.titler.Reset() paramLocation := diffLocation.AddNode(getNameOnlyDiffNode(name)) sd.compareDescripton(paramLocation, param1.Description, param2.Description) @@ -629,7 +639,8 @@ func (sd *SpecAnalyser) addTypeDiff(location DifferenceLocation, diff *TypeDiff) sd.Diffs = sd.Diffs.addDiff(SpecDifference{ DifferenceLocation: location, Code: diffCopy.Change, - DiffInfo: desc}) + DiffInfo: desc, + }) } func (sd *SpecAnalyser) compareDescripton(location DifferenceLocation, desc1, desc2 string) { @@ -651,6 +662,7 @@ func isPrimitiveType(item spec.StringOrArray) bool { func isArrayType(item spec.StringOrArray) bool { return len(item) > 0 && item[0] == ArrayType } + func (sd *SpecAnalyser) getRefSchemaFromSpec1(ref spec.Ref) (*spec.Schema, string) { return sd.schemaFromRef(ref, &sd.Definitions1) } @@ -663,7 +675,6 @@ func (sd *SpecAnalyser) getRefSchemaFromSpec2(ref spec.Ref) (*spec.Schema, strin type CompareSchemaFn func(location DifferenceLocation, schema1, schema2 *spec.Schema) func (sd *SpecAnalyser) compareSchema(location DifferenceLocation, schema1, schema2 *spec.Schema) { - refDiffs := []TypeDiff{} refDiffs = CheckRefChange(refDiffs, schema1, schema2) if len(refDiffs) > 0 { @@ -826,7 +837,6 @@ func (sd *SpecAnalyser) schemaFromRef(ref spec.Ref, defns *spec.Definitions) (ac sd.ReferencedDefinitions[definitionName] = true actualSchema = &foundSchema return - } func schemaLocationKey(location DifferenceLocation) string { diff --git a/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/diff/spec_difference.go b/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/diff/spec_difference.go index 73e38ce4e..14ffcc4d5 100644 --- a/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/diff/spec_difference.go +++ b/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/diff/spec_difference.go @@ -46,7 +46,6 @@ func equalNodes(a, b *Node) bool { a.IsArray == b.IsArray && a.TypeName == b.TypeName && equalNodes(a.ChildNode, b.ChildNode) - } // BreakingChangeCount Calculates the breaking change count @@ -187,7 +186,7 @@ func (sd SpecDifferences) ReportAllDiffs(fmtJSON bool) (io.Reader, error, error) if fmtJSON { b, err := JSONMarshal(sd) if err != nil { - return nil, fmt.Errorf("couldn't print results: %v", err), nil + return nil, fmt.Errorf("couldn't print results: %w", err), nil } out, err := prettyprint(b) return out, err, nil diff --git a/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/diff/type_adapters.go b/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/diff/type_adapters.go index 5679367fd..c264395f8 100644 --- a/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/diff/type_adapters.go +++ b/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/diff/type_adapters.go @@ -11,8 +11,8 @@ func forItems(items *spec.Items) *spec.Schema { valids := items.CommonValidations schema := spec.Schema{ SchemaProps: spec.SchemaProps{ - Type: []string{items.SimpleSchema.Type}, - Format: items.SimpleSchema.Format, + Type: []string{items.Type}, + Format: items.Format, Maximum: valids.Maximum, ExclusiveMaximum: valids.ExclusiveMaximum, Minimum: valids.Minimum, diff --git a/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/expand.go b/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/expand.go index ed1fd3bfa..bef84c8be 100644 --- a/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/expand.go +++ b/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/expand.go @@ -4,13 +4,15 @@ import ( "encoding/json" "errors" "fmt" + "io" "log" "os" + flags "github.com/jessevdk/go-flags" + "github.com/go-openapi/loads" "github.com/go-openapi/spec" "github.com/go-openapi/swag" - flags "github.com/jessevdk/go-flags" ) // ExpandSpec is a command that expands the $refs in a swagger document. @@ -42,6 +44,8 @@ func (c *ExpandSpec) Execute(args []string) error { return writeToFile(exp.Spec(), !c.Compact, c.Format, string(c.Output)) } +var defaultWriter io.Writer = os.Stdout + func writeToFile(swspec *spec.Swagger, pretty bool, format string, output string) error { var b []byte var err error @@ -61,7 +65,7 @@ func writeToFile(swspec *spec.Swagger, pretty bool, format string, output string if erg := json.Unmarshal(b, &data); erg != nil { log.Fatalln(erg) } - var bb interface{} + var bb any bb, err = data.MarshalYAML() if err == nil { b = bb.([]byte) @@ -73,10 +77,11 @@ func writeToFile(swspec *spec.Swagger, pretty bool, format string, output string return err } - if output == "" { - fmt.Println(string(b)) - return nil + switch output { + case "", "-": + _, e := fmt.Fprintf(defaultWriter, "%s\n", b) + return e + default: + return os.WriteFile(output, b, 0o644) //#nosec } - - return os.WriteFile(output, b, 0644) // #nosec } diff --git a/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/flatten.go b/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/flatten.go index b30b50fd5..0001971b9 100644 --- a/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/flatten.go +++ b/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/flatten.go @@ -3,10 +3,12 @@ package commands import ( "errors" + flags "github.com/jessevdk/go-flags" + "github.com/go-openapi/analysis" "github.com/go-openapi/loads" + "github.com/go-swagger/go-swagger/cmd/swagger/commands/generate" - flags "github.com/jessevdk/go-flags" ) // FlattenSpec is a command that flattens a swagger document @@ -31,7 +33,7 @@ func (c *FlattenSpec) Execute(args []string) error { return err } - flattenOpts := c.FlattenCmdOptions.SetFlattenOptions(&analysis.FlattenOpts{ + flattenOpts := c.SetFlattenOptions(&analysis.FlattenOpts{ // defaults Minimal: true, Verbose: true, diff --git a/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/generate/cli.go b/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/generate/cli.go index e8ea11c79..7896536a7 100644 --- a/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/generate/cli.go +++ b/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/generate/cli.go @@ -7,12 +7,13 @@ type Cli struct { Client // cmd/<cli-app-name>/main.go will be generated. This ensures that go install will compile the app with desired name. CliAppName string `long:"cli-app-name" description:"the app name for the cli executable. useful for go install." default:"cli"` + CliPackage string `long:"cli-package" description:"the package to save the cli specific code" default:"cli"` } func (c Cli) apply(opts *generator.GenOpts) { c.Client.apply(opts) opts.IncludeCLi = true - opts.CliPackage = "cli" // hardcoded for now, can be exposed via cmd opt later + opts.CliPackage = c.CliPackage opts.CliAppName = c.CliAppName } @@ -21,6 +22,6 @@ func (c *Cli) generate(opts *generator.GenOpts) error { } // Execute runs this command -func (c *Cli) Execute(args []string) error { +func (c *Cli) Execute(_ []string) error { return createSwagger(c) } diff --git a/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/generate/client.go b/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/generate/client.go index 3a78b5622..728fcaa88 100644 --- a/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/generate/client.go +++ b/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/generate/client.go @@ -67,20 +67,19 @@ func (c *Client) generate(opts *generator.GenOpts) error { return generator.GenerateClient(c.Name, c.Models.Models, c.Operations.Operations, opts) } -func (c *Client) log(rp string) { +func (c *Client) log(_ string) { log.Println(`Generation completed! For this generation to compile you need to have some packages in your go.mod: * github.com/go-openapi/errors * github.com/go-openapi/runtime - * github.com/go-openapi/runtime/client * github.com/go-openapi/strfmt You can get these now with: go mod tidy`) } // Execute runs this command -func (c *Client) Execute(args []string) error { +func (c *Client) Execute(_ []string) error { return createSwagger(c) } diff --git a/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/generate/markdown.go b/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/generate/markdown.go index ba9df3812..0dd4fc962 100644 --- a/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/generate/markdown.go +++ b/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/generate/markdown.go @@ -1,8 +1,9 @@ package generate import ( - "github.com/go-swagger/go-swagger/generator" "github.com/jessevdk/go-flags" + + "github.com/go-swagger/go-swagger/generator" ) // Markdown generates a markdown representation of the spec @@ -24,10 +25,10 @@ func (m *Markdown) generate(opts *generator.GenOpts) error { return generator.GenerateMarkdown(string(m.Output), m.Models.Models, m.Operations.Operations, opts) } -func (m Markdown) log(rp string) { +func (m Markdown) log(_ string) { } // Execute runs this command -func (m *Markdown) Execute(args []string) error { +func (m *Markdown) Execute(_ []string) error { return createSwagger(m) } diff --git a/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/generate/model.go b/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/generate/model.go index 5dffa66ea..62b46b1f0 100644 --- a/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/generate/model.go +++ b/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/generate/model.go @@ -71,7 +71,7 @@ func (m Model) apply(opts *generator.GenOpts) { opts.AcceptDefinitionsOnly = m.AcceptDefinitionsOnly } -func (m Model) log(rp string) { +func (m Model) log(_ string) { log.Println(`Generation completed! For this generation to compile you need to have some packages in your go.mod: @@ -87,8 +87,7 @@ func (m *Model) generate(opts *generator.GenOpts) error { } // Execute generates a model file -func (m *Model) Execute(args []string) error { - +func (m *Model) Execute(_ []string) error { if m.Shared.DumpData && len(append(m.Name, m.Models.Models...)) > 1 { return errors.New("only 1 model at a time is supported for dumping data") } diff --git a/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/generate/operation.go b/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/generate/operation.go index ba554314a..9eea866ee 100644 --- a/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/generate/operation.go +++ b/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/generate/operation.go @@ -83,8 +83,7 @@ func (o *Operation) generate(opts *generator.GenOpts) error { return generator.GenerateServerOperation(append(o.Name, o.Operations.Operations...), opts) } -func (o Operation) log(rp string) { - +func (o Operation) log(_ string) { log.Println(`Generation completed! For this generation to compile you need to have some packages in your go.mod: @@ -95,7 +94,7 @@ You can get these now with: go mod tidy`) } // Execute generates a model file -func (o *Operation) Execute(args []string) error { +func (o *Operation) Execute(_ []string) error { if o.Shared.DumpData && len(append(o.Name, o.Operations.Operations...)) > 1 { return errors.New("only 1 operation at a time is supported for dumping data") } diff --git a/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/generate/server.go b/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/generate/server.go index 92495adde..2a5a6425b 100644 --- a/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/generate/server.go +++ b/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/generate/server.go @@ -57,9 +57,10 @@ type Server struct { WithContext bool `long:"with-context" description:"handlers get a context as first arg (deprecated)"` } -func (s Server) apply(opts *generator.GenOpts) { +func (s *Server) apply(opts *generator.GenOpts) { if s.WithContext { log.Printf("warning: deprecated option --with-context is ignored") + s.WithContext = false } s.Shared.apply(opts) @@ -92,7 +93,7 @@ func (s *Server) generate(opts *generator.GenOpts) error { return generator.GenerateServer(s.Name, s.Models.Models, s.Operations.Operations, opts) } -func (s Server) log(rp string) { +func (s Server) log(_ string) { var flagsPackage string switch { case strings.HasPrefix(s.FlagStrategy, "pflag"): @@ -114,6 +115,6 @@ You can get these now with: go mod tidy`) } // Execute runs this command -func (s *Server) Execute(args []string) error { +func (s *Server) Execute(_ []string) error { return createSwagger(s) } diff --git a/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/generate/shared.go b/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/generate/shared.go index 7eb3af3fa..b8a5f358c 100644 --- a/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/generate/shared.go +++ b/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/generate/shared.go @@ -7,11 +7,13 @@ import ( "path/filepath" "strings" + flags "github.com/jessevdk/go-flags" + "github.com/spf13/viper" + "github.com/go-openapi/analysis" "github.com/go-openapi/swag" + "github.com/go-swagger/go-swagger/generator" - flags "github.com/jessevdk/go-flags" - "github.com/spf13/viper" ) // FlattenCmdOptions determines options to the flatten spec preprocessing @@ -125,6 +127,7 @@ type sharedOptionsCommon struct { SkipValidation bool `long:"skip-validation" description:"skips validation of spec prior to generation" group:"shared"` DumpData bool `long:"dump-data" description:"when present dumps the json for the template generator instead of generating files" group:"shared"` StrictResponders bool `long:"strict-responders" description:"Use strict type for the handler return value"` + ReturnErrors bool `long:"return-errors" short:"e" description:"handlers explicitly return an error as the second value" group:"shared"` FlattenCmdOptions } @@ -136,9 +139,10 @@ func (s sharedOptionsCommon) apply(opts *generator.GenOpts) { opts.AllowTemplateOverride = s.AllowTemplateOverride opts.ValidateSpec = !s.SkipValidation opts.DumpData = s.DumpData - opts.FlattenOpts = s.FlattenCmdOptions.SetFlattenOptions(opts.FlattenOpts) + opts.FlattenOpts = s.SetFlattenOptions(opts.FlattenOpts) opts.Copyright = string(s.CopyrightFile) opts.StrictResponders = s.StrictResponders + opts.ReturnErrors = s.ReturnErrors swag.AddInitialisms(s.AdditionalInitialisms...) } @@ -167,7 +171,7 @@ func createSwagger(s sharedCommand) error { opts.Copyright, err = setCopyright(opts.Copyright) if err != nil { - return fmt.Errorf("could not load copyright file: %v", err) + return fmt.Errorf("could not load copyright file: %w", err) } if opts.Template != "" { diff --git a/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/generate/sharedopts_nonwin.go b/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/generate/sharedopts_nonwin.go index 7f7c25187..630e20d90 100644 --- a/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/generate/sharedopts_nonwin.go +++ b/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/generate/sharedopts_nonwin.go @@ -4,8 +4,9 @@ package generate import ( - "github.com/go-swagger/go-swagger/generator" "github.com/jessevdk/go-flags" + + "github.com/go-swagger/go-swagger/generator" ) type sharedOptions struct { diff --git a/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/generate/spec.go b/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/generate/spec.go index 58f6a945b..3f9c37126 100644 --- a/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/generate/spec.go +++ b/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/generate/spec.go @@ -17,15 +17,17 @@ package generate import ( "encoding/json" "fmt" + "io" "os" "strings" "github.com/go-swagger/go-swagger/codescan" - "github.com/go-openapi/loads" - "github.com/go-openapi/spec" "github.com/jessevdk/go-flags" "gopkg.in/yaml.v3" + + "github.com/go-openapi/loads" + "github.com/go-openapi/spec" ) // SpecFile command to generate a swagger spec from a go application @@ -42,6 +44,7 @@ type SpecFile struct { ExcludeTags []string `long:"exclude-tag" short:"" description:"exclude routes having specified tags (can be specified many times)"` ExcludeDeps bool `long:"exclude-deps" short:"" description:"exclude all dependencies of project"` SetXNullableForPointers bool `long:"nullable-pointers" short:"n" description:"set x-nullable extension to true automatically for fields of pointer types without 'omitempty'"` + RefAliases bool `long:"ref-aliases" short:"r" description:"transform aliased types into $ref rather than expanding their definition"` } // Execute runs this command @@ -67,6 +70,7 @@ func (s *SpecFile) Execute(args []string) error { opts.ExcludeTags = s.ExcludeTags opts.ExcludeDeps = s.ExcludeDeps opts.SetXNullableForPointers = s.SetXNullableForPointers + opts.RefAliases = s.RefAliases swspec, err := codescan.Run(&opts) if err != nil { return err @@ -89,6 +93,8 @@ func loadSpec(input string) (*spec.Swagger, error) { return nil, nil } +var defaultWriter io.Writer = os.Stdout + func writeToFile(swspec *spec.Swagger, pretty bool, output string) error { var b []byte var err error @@ -103,11 +109,15 @@ func writeToFile(swspec *spec.Swagger, pretty bool, output string) error { return err } - if output == "" { - fmt.Println(string(b)) - return nil + switch output { + case "", "-": + _, e := fmt.Fprintf(defaultWriter, "%s\n", b) + return e + default: + return os.WriteFile(output, b, 0o644) //#nosec } - return os.WriteFile(output, b, 0644) // #nosec + + // #nosec } func marshalToJSONFormat(swspec *spec.Swagger, pretty bool) ([]byte, error) { @@ -123,7 +133,7 @@ func marshalToYAMLFormat(swspec *spec.Swagger) ([]byte, error) { return nil, err } - var jsonObj interface{} + var jsonObj any if err := yaml.Unmarshal(b, &jsonObj); err != nil { return nil, err } diff --git a/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/generate/support.go b/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/generate/support.go index 9e52f428c..4e84c0267 100644 --- a/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/generate/support.go +++ b/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/generate/support.go @@ -48,20 +48,19 @@ func (s *Support) generate(opts *generator.GenOpts) error { return generator.GenerateSupport(s.Name, s.Models.Models, s.Operations.Operations, opts) } -func (s Support) log(rp string) { - +func (s Support) log(_ string) { log.Println(`Generation completed! For this generation to compile you need to have some packages in go.mod: * github.com/go-openapi/runtime - * github.com/asaskevich/govalidator + * github.com/go-openapi/strfmt * github.com/jessevdk/go-flags You can get these now with: go mod tidy`) } // Execute generates the supporting files file -func (s *Support) Execute(args []string) error { +func (s *Support) Execute(_ []string) error { return createSwagger(s) } diff --git a/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/initcmd.go b/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/initcmd.go index 7a992f2b7..5f6b05297 100644 --- a/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/initcmd.go +++ b/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/initcmd.go @@ -8,6 +8,6 @@ type InitCmd struct { } // Execute provides default empty implementation -func (i *InitCmd) Execute(args []string) error { +func (i *InitCmd) Execute(_ []string) error { return nil } diff --git a/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/initcmd/spec.go b/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/initcmd/spec.go index c540dc5b4..b81eb933c 100644 --- a/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/initcmd/spec.go +++ b/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/initcmd/spec.go @@ -15,7 +15,7 @@ import ( // Spec a command struct for initializing a new swagger application. type Spec struct { - Format string `long:"format" description:"the format for the spec document" default:"yaml" choice:"yaml" choice:"json"` + Format string `long:"format" description:"the format for the spec document" default:"yaml" choice:"yaml" choice:"json"` //nolint:staticcheck Title string `long:"title" description:"the title of the API"` Description string `long:"description" description:"the description of the API"` Version string `long:"version" description:"the version of the API" default:"0.1.0"` diff --git a/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/mixin.go b/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/mixin.go index 79e26c440..86db148b2 100644 --- a/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/mixin.go +++ b/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/mixin.go @@ -6,10 +6,11 @@ import ( "log" "os" + flags "github.com/jessevdk/go-flags" + "github.com/go-openapi/analysis" "github.com/go-openapi/loads" "github.com/go-openapi/spec" - flags "github.com/jessevdk/go-flags" "github.com/go-swagger/go-swagger/generator" ) @@ -50,7 +51,6 @@ type MixinSpec struct { // generation tools that natively support hosting multiple specs in // one server process will not need this tool. func (c *MixinSpec) Execute(args []string) error { - if len(args) < 2 { return errors.New(nothingToDo) } @@ -90,8 +90,7 @@ func (c *MixinSpec) Execute(args []string) error { // with mixins to the given writer in JSON. Returns the warning // messages for collisions that occurred during mixin process and any // error. -func (c *MixinSpec) MixinFiles(primaryFile string, mixinFiles []string, w io.Writer) ([]string, error) { - +func (c *MixinSpec) MixinFiles(primaryFile string, mixinFiles []string, _ io.Writer) ([]string, error) { primaryDoc, err := loads.Spec(primaryFile) if err != nil { return nil, err diff --git a/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/serve.go b/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/serve.go index 63705f618..30ff8eed0 100644 --- a/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/serve.go +++ b/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/serve.go @@ -10,12 +10,13 @@ import ( "path" "strconv" + "github.com/gorilla/handlers" + "github.com/toqueteos/webbrowser" + "github.com/go-openapi/loads" "github.com/go-openapi/runtime/middleware" "github.com/go-openapi/spec" "github.com/go-openapi/swag" - "github.com/gorilla/handlers" - "github.com/toqueteos/webbrowser" ) // ServeCmd to serve a swagger spec with docs ui @@ -48,7 +49,6 @@ func (s *ServeCmd) Execute(args []string) error { ContinueOnError: true, AbsoluteCircularRef: true, }) - if err != nil { return err } diff --git a/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/version.go b/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/version.go index 9a860653b..fd776066b 100644 --- a/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/version.go +++ b/vendor/github.com/go-swagger/go-swagger/cmd/swagger/commands/version.go @@ -13,11 +13,10 @@ var ( ) // PrintVersion the command -type PrintVersion struct { -} +type PrintVersion struct{} // Execute this command -func (p *PrintVersion) Execute(args []string) error { +func (p *PrintVersion) Execute(_ []string) error { if Version == "" { if info, available := debug.ReadBuildInfo(); available && info.Main.Version != "(devel)" { // built from source, with module (e.g. go get) diff --git a/vendor/github.com/go-swagger/go-swagger/cmd/swagger/swagger.go b/vendor/github.com/go-swagger/go-swagger/cmd/swagger/swagger.go index dfc89ba2e..54cc23223 100644 --- a/vendor/github.com/go-swagger/go-swagger/cmd/swagger/swagger.go +++ b/vendor/github.com/go-swagger/go-swagger/cmd/swagger/swagger.go @@ -19,8 +19,9 @@ import ( "log" "os" - "github.com/go-swagger/go-swagger/cmd/swagger/commands" flags "github.com/jessevdk/go-flags" + + "github.com/go-swagger/go-swagger/cmd/swagger/commands" ) var opts struct { @@ -130,7 +131,7 @@ It aims to represent the contract of your API with a language agnostic descripti log.SetOutput(io.Discard) } opts.LogFile = func(logfile string) { - f, err := os.OpenFile(logfile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666) + f, err := os.OpenFile(logfile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0o666) if err != nil { log.Fatalf("cannot write to file %s: %v", logfile, err) } diff --git a/vendor/github.com/go-swagger/go-swagger/codescan/application.go b/vendor/github.com/go-swagger/go-swagger/codescan/application.go index ebaa6261a..b086f918d 100644 --- a/vendor/github.com/go-swagger/go-swagger/codescan/application.go +++ b/vendor/github.com/go-swagger/go-swagger/codescan/application.go @@ -9,11 +9,10 @@ import ( "os" "strings" + "github.com/go-openapi/spec" "github.com/go-openapi/swag" "golang.org/x/tools/go/packages" - - "github.com/go-openapi/spec" ) const pkgLoadMode = packages.NeedName | packages.NeedFiles | packages.NeedImports | packages.NeedDeps | packages.NeedTypes | packages.NeedSyntax | packages.NeedTypesInfo @@ -53,6 +52,7 @@ type Options struct { IncludeTags []string ExcludeTags []string SetXNullableForPointers bool + RefAliases bool // aliases result in $ref, otherwise aliases are expanded } type scanCtx struct { @@ -93,9 +93,15 @@ func newScanCtx(opts *Options) (*scanCtx, error) { return nil, err } - app, err := newTypeIndex(pkgs, opts.ExcludeDeps, - sliceToSet(opts.IncludeTags), sliceToSet(opts.ExcludeTags), - opts.Include, opts.Exclude, opts.SetXNullableForPointers) + app, err := newTypeIndex(pkgs, + withExcludeDeps(opts.ExcludeDeps), + withIncludeTags(sliceToSet(opts.IncludeTags)), + withExcludeTags(sliceToSet(opts.ExcludeTags)), + withIncludePkgs(opts.Include), + withExcludePkgs(opts.Exclude), + withXNullableForPointers(opts.SetXNullableForPointers), + withRefAliases(opts.RefAliases), + ) if err != nil { return nil, err } @@ -109,6 +115,7 @@ func newScanCtx(opts *Options) (*scanCtx, error) { type entityDecl struct { Comments *ast.CommentGroup Type *types.Named + Alias *types.Alias // added to supplement Named, after go1.22 Ident *ast.Ident Spec *ast.TypeSpec File *ast.File @@ -118,6 +125,29 @@ type entityDecl struct { hasParameterAnnotation bool } +// Obj returns the type name for the declaration defining the named type or alias t. +func (d *entityDecl) Obj() *types.TypeName { + if d.Type != nil { + return d.Type.Obj() + } + if d.Alias != nil { + return d.Alias.Obj() + } + + panic("invalid entityDecl: Type and Alias are both nil") +} + +func (d *entityDecl) ObjType() types.Type { + if d.Type != nil { + return d.Type + } + if d.Alias != nil { + return d.Alias + } + + panic("invalid entityDecl: Type and Alias are both nil") +} + func (d *entityDecl) Names() (name, goName string) { goName = d.Ident.Name name = goName @@ -138,6 +168,7 @@ DECLS: } } } + return } @@ -259,11 +290,15 @@ func (s *scanCtx) FindDecl(pkgPath, name string) (*entityDecl, bool) { def, ok := pkg.TypesInfo.Defs[ts.Name] if !ok { debugLog("couldn't find type info for %s", ts.Name) + continue } + nt, isNamed := def.Type().(*types.Named) - if !isNamed { - debugLog("%s is not a named type but a %T", ts.Name, def.Type()) + at, isAliased := def.Type().(*types.Alias) + if !isNamed && !isAliased { + debugLog("%s is not a named or an aliased type but a %T", ts.Name, def.Type()) + continue } @@ -275,31 +310,36 @@ func (s *scanCtx) FindDecl(pkgPath, name string) (*entityDecl, bool) { decl := &entityDecl{ Comments: comments, Type: nt, + Alias: at, Ident: ts.Name, Spec: ts, File: file, Pkg: pkg, } + return decl, true } } } } } + return nil, false } func (s *scanCtx) FindModel(pkgPath, name string) (*entityDecl, bool) { for _, cand := range s.app.Models { - ct := cand.Type.Obj() + ct := cand.Obj() if ct.Name() == name && ct.Pkg().Path() == pkgPath { return cand, true } } + if decl, found := s.FindDecl(pkgPath, name); found { s.app.ExtraModels[decl.Ident] = decl return decl, true } + return nil, false } @@ -314,9 +354,12 @@ func (s *scanCtx) DeclForType(t types.Type) (*entityDecl, bool) { return s.DeclForType(tpe.Elem()) case *types.Named: return s.FindDecl(tpe.Obj().Pkg().Path(), tpe.Obj().Name()) + case *types.Alias: + return s.FindDecl(tpe.Obj().Pkg().Path(), tpe.Obj().Name()) default: - log.Printf("unknown type to find the package for [%T]: %s", t, t.String()) + log.Printf("WARNING: unknown type to find the package for [%T]: %s", t, t.String()) + return nil, false } } @@ -333,6 +376,9 @@ func (s *scanCtx) PkgForType(t types.Type) (*packages.Package, bool) { case *types.Named: v, ok := s.app.AllPackages[tpe.Obj().Pkg().Path()] return v, ok + case *types.Alias: + v, ok := s.app.AllPackages[tpe.Obj().Pkg().Path()] + return v, ok default: log.Printf("unknown type to find the package for [%T]: %s", t, t.String()) return nil, false @@ -385,7 +431,7 @@ func (s *scanCtx) FindEnumValues(pkg *packages.Package, enumName string) (list [ desc = &strings.Builder{} namesLen = len(vs.Names) ) - desc.WriteString(fmt.Sprintf("%v ", blValue)) + fmt.Fprintf(desc, "%v ", blValue) for i, name := range vs.Names { desc.WriteString(name.Name) if i < namesLen-1 { @@ -419,18 +465,60 @@ func (s *scanCtx) FindEnumValues(pkg *packages.Package, enumName string) (list [ return list, descList, true } -func newTypeIndex(pkgs []*packages.Package, excludeDeps bool, includeTags, excludeTags map[string]bool, includePkgs, excludePkgs []string, setXNullableForPointers bool) (*typeIndex, error) { +type typeIndexOption func(*typeIndex) + +func withExcludeDeps(excluded bool) typeIndexOption { + return func(a *typeIndex) { + a.excludeDeps = excluded + } +} + +func withIncludeTags(included map[string]bool) typeIndexOption { + return func(a *typeIndex) { + a.includeTags = included + } +} + +func withExcludeTags(excluded map[string]bool) typeIndexOption { + return func(a *typeIndex) { + a.excludeTags = excluded + } +} + +func withIncludePkgs(included []string) typeIndexOption { + return func(a *typeIndex) { + a.includePkgs = included + } +} + +func withExcludePkgs(excluded []string) typeIndexOption { + return func(a *typeIndex) { + a.excludePkgs = excluded + } +} + +func withXNullableForPointers(enabled bool) typeIndexOption { + return func(a *typeIndex) { + a.setXNullableForPointers = enabled + } +} + +func withRefAliases(enabled bool) typeIndexOption { + return func(a *typeIndex) { + a.refAliases = enabled + } +} + +func newTypeIndex(pkgs []*packages.Package, opts ...typeIndexOption) (*typeIndex, error) { ac := &typeIndex{ - AllPackages: make(map[string]*packages.Package), - Models: make(map[*ast.Ident]*entityDecl), - ExtraModels: make(map[*ast.Ident]*entityDecl), - excludeDeps: excludeDeps, - includeTags: includeTags, - excludeTags: excludeTags, - includePkgs: includePkgs, - excludePkgs: excludePkgs, - setXNullableForPointers: setXNullableForPointers, + AllPackages: make(map[string]*packages.Package), + Models: make(map[*ast.Ident]*entityDecl), + ExtraModels: make(map[*ast.Ident]*entityDecl), } + for _, apply := range opts { + apply(ac) + } + if err := ac.build(pkgs); err != nil { return nil, err } @@ -452,6 +540,7 @@ type typeIndex struct { includePkgs []string excludePkgs []string setXNullableForPointers bool + refAliases bool } func (a *typeIndex) build(pkgs []*packages.Package) error { @@ -554,8 +643,10 @@ func (a *typeIndex) processDecl(pkg *packages.Package, file *ast.File, n node, g continue } nt, isNamed := def.Type().(*types.Named) - if !isNamed { - debugLog("%s is not a named type but a %T", ts.Name, def.Type()) + at, isAliased := def.Type().(*types.Alias) + if !isNamed && !isAliased { + debugLog("%s is not a named or aliased type but a %T", ts.Name, def.Type()) + continue } @@ -567,20 +658,26 @@ func (a *typeIndex) processDecl(pkg *packages.Package, file *ast.File, n node, g decl := &entityDecl{ Comments: comments, Type: nt, + Alias: at, Ident: ts.Name, Spec: ts, File: file, Pkg: pkg, } key := ts.Name - if n&modelNode != 0 && decl.HasModelAnnotation() { + switch { + case n&modelNode != 0 && decl.HasModelAnnotation(): a.Models[key] = decl - } - if n¶metersNode != 0 && decl.HasParameterAnnotation() { + case n¶metersNode != 0 && decl.HasParameterAnnotation(): a.Parameters = append(a.Parameters, decl) - } - if n&responseNode != 0 && decl.HasResponseAnnotation() { + case n&responseNode != 0 && decl.HasResponseAnnotation(): a.Responses = append(a.Responses, decl) + default: + debugLog( + "type %q skipped because it is not tagged as a model, a parameter or a response. %s", + decl.Obj().Name(), + "It may reenter the scope because it is a discovered dependency", + ) } } } @@ -668,6 +765,6 @@ func (a *typeIndex) detectNodes(file *ast.File) (node, error) { func debugLog(format string, args ...interface{}) { if Debug { - log.Printf(format, args...) + _ = log.Output(2, fmt.Sprintf(format, args...)) } } diff --git a/vendor/github.com/go-swagger/go-swagger/codescan/assertions.go b/vendor/github.com/go-swagger/go-swagger/codescan/assertions.go new file mode 100644 index 000000000..a6c8100d0 --- /dev/null +++ b/vendor/github.com/go-swagger/go-swagger/codescan/assertions.go @@ -0,0 +1,34 @@ +package codescan + +import ( + "fmt" + "go/types" +) + +type Error string + +func (e Error) Error() string { + return string(e) +} + +const ( + ErrInternal Error = "internal error due to a bug or a mishandling of go types AST. This usually indicates a bug in the scanner" +) + +// code assertions to be explicit about the various expectations when entering a function + +func mustNotBeABuiltinType(o *types.TypeName) { + if o.Pkg() != nil { + return + } + + panic(fmt.Errorf("type %q expected not to be a builtin: %w", o.Name(), ErrInternal)) +} + +func mustHaveRightHandSide(a *types.Alias) { + if a.Rhs() != nil { + return + } + + panic(fmt.Errorf("type alias %q expected to declare a right-hand-side: %w", a.Obj().Name(), ErrInternal)) +} diff --git a/vendor/github.com/go-swagger/go-swagger/codescan/parameters.go b/vendor/github.com/go-swagger/go-swagger/codescan/parameters.go index 1ee769ae8..6a090bd37 100644 --- a/vendor/github.com/go-swagger/go-swagger/codescan/parameters.go +++ b/vendor/github.com/go-swagger/go-swagger/codescan/parameters.go @@ -15,6 +15,8 @@ type paramTypable struct { param *spec.Parameter } +func (pt paramTypable) In() string { return pt.param.In } + func (pt paramTypable) Level() int { return 0 } func (pt paramTypable) Typed(tpe, format string) { @@ -36,7 +38,7 @@ func (pt paramTypable) Items() swaggerTypable { pt.param.Items = new(spec.Items) } pt.param.Type = "array" - return itemsTypable{pt.param.Items, 1} + return itemsTypable{pt.param.Items, 1, pt.param.In} } func (pt paramTypable) Schema() *spec.Schema { @@ -71,8 +73,11 @@ func (pt paramTypable) WithEnumDescription(desc string) { type itemsTypable struct { items *spec.Items level int + in string } +func (pt itemsTypable) In() string { return pt.in } // TODO(fred): inherit from param + func (pt itemsTypable) Level() int { return pt.level } func (pt itemsTypable) Typed(tpe, format string) { @@ -92,7 +97,7 @@ func (pt itemsTypable) Items() swaggerTypable { pt.items.Items = new(spec.Items) } pt.items.Type = "array" - return itemsTypable{pt.items.Items, pt.level + 1} + return itemsTypable{pt.items.Items, pt.level + 1, pt.in} } func (pt itemsTypable) AddExtension(key string, value interface{}) { @@ -188,10 +193,11 @@ func (p *parameterBuilder) Build(operations map[string]*spec.Operation) error { // * has to document the validations that apply for the type and the field // * when the struct field points to a model it becomes a ref: #/definitions/ModelName // * comments that aren't tags is used as the description - if err := p.buildFromType(p.decl.Type, operation, make(map[string]spec.Parameter)); err != nil { + if err := p.buildFromType(p.decl.ObjType(), operation, make(map[string]spec.Parameter)); err != nil { return err } } + return nil } @@ -200,88 +206,247 @@ func (p *parameterBuilder) buildFromType(otpe types.Type, op *spec.Operation, se case *types.Pointer: return p.buildFromType(tpe.Elem(), op, seen) case *types.Named: - o := tpe.Obj() - switch stpe := o.Type().Underlying().(type) { - case *types.Struct: - debugLog("build from type %s: %T", tpe.Obj().Name(), otpe) - if decl, found := p.ctx.DeclForType(o.Type()); found { - return p.buildFromStruct(decl, stpe, op, seen) - } - return p.buildFromStruct(p.decl, stpe, op, seen) - default: - return fmt.Errorf("unhandled type (%T): %s", stpe, o.Type().Underlying().String()) - } + return p.buildNamedType(tpe, op, seen) + case *types.Alias: + debugLog("alias(parameters.buildFromType): got alias %v to %v", tpe, tpe.Rhs()) + return p.buildAlias(tpe, op, seen) default: return fmt.Errorf("unhandled type (%T): %s", otpe, tpe.String()) } } +func (p *parameterBuilder) buildNamedType(tpe *types.Named, op *spec.Operation, seen map[string]spec.Parameter) error { + o := tpe.Obj() + if isAny(o) || isStdError(o) { + return fmt.Errorf("%s type not supported in the context of a parameters section definition", o.Name()) + } + mustNotBeABuiltinType(o) + + switch stpe := o.Type().Underlying().(type) { + case *types.Struct: + debugLog("build from named type %s: %T", o.Name(), tpe) + if decl, found := p.ctx.DeclForType(o.Type()); found { + return p.buildFromStruct(decl, stpe, op, seen) + } + + return p.buildFromStruct(p.decl, stpe, op, seen) + default: + return fmt.Errorf("unhandled type (%T): %s", stpe, o.Type().Underlying().String()) + } +} + +func (p *parameterBuilder) buildAlias(tpe *types.Alias, op *spec.Operation, seen map[string]spec.Parameter) error { + o := tpe.Obj() + if isAny(o) || isStdError(o) { + return fmt.Errorf("%s type not supported in the context of a parameters section definition", o.Name()) + } + mustNotBeABuiltinType(o) + mustHaveRightHandSide(tpe) + + rhs := tpe.Rhs() + decl, ok := p.ctx.FindModel(o.Pkg().Path(), o.Name()) + if !ok { + return fmt.Errorf("can't find source file for aliased type: %v -> %v", tpe, rhs) + } + p.postDecls = append(p.postDecls, decl) // mark the left-hand side as discovered + + switch rtpe := rhs.(type) { + // load declaration for named unaliased type + case *types.Named: + o := rtpe.Obj() + if o.Pkg() == nil { + break // builtin + } + decl, found := p.ctx.FindModel(o.Pkg().Path(), o.Name()) + if !found { + return fmt.Errorf("can't find source file for target type of alias: %v -> %v", tpe, rtpe) + } + p.postDecls = append(p.postDecls, decl) + case *types.Alias: + o := rtpe.Obj() + if o.Pkg() == nil { + break // builtin + } + decl, found := p.ctx.FindModel(o.Pkg().Path(), o.Name()) + if !found { + return fmt.Errorf("can't find source file for target type of alias: %v -> %v", tpe, rtpe) + } + p.postDecls = append(p.postDecls, decl) + } + + return p.buildFromType(rhs, op, seen) +} + func (p *parameterBuilder) buildFromField(fld *types.Var, tpe types.Type, typable swaggerTypable, seen map[string]spec.Parameter) error { debugLog("build from field %s: %T", fld.Name(), tpe) + switch ftpe := tpe.(type) { case *types.Basic: return swaggerSchemaForType(ftpe.Name(), typable) case *types.Struct: - sb := schemaBuilder{ - decl: p.decl, - ctx: p.ctx, - } - if err := sb.buildFromType(tpe, typable); err != nil { - return err - } - p.postDecls = append(p.postDecls, sb.postDecls...) - return nil + return p.buildFromFieldStruct(ftpe, typable) case *types.Pointer: return p.buildFromField(fld, ftpe.Elem(), typable, seen) case *types.Interface: - sb := schemaBuilder{ - decl: p.decl, - ctx: p.ctx, - } - if err := sb.buildFromType(tpe, typable); err != nil { - return err - } - p.postDecls = append(p.postDecls, sb.postDecls...) - return nil + return p.buildFromFieldInterface(ftpe, typable) case *types.Array: return p.buildFromField(fld, ftpe.Elem(), typable.Items(), seen) case *types.Slice: return p.buildFromField(fld, ftpe.Elem(), typable.Items(), seen) case *types.Map: - schema := new(spec.Schema) - typable.Schema().Typed("object", "").AdditionalProperties = &spec.SchemaOrBool{ - Schema: schema, + return p.buildFromFieldMap(ftpe, typable) + case *types.Named: + return p.buildNamedField(ftpe, typable) + case *types.Alias: + debugLog("alias(parameters.buildFromField): got alias %v to %v", ftpe, ftpe.Rhs()) // TODO + return p.buildFieldAlias(ftpe, typable, fld, seen) + default: + return fmt.Errorf("unknown type for %s: %T", fld.String(), fld.Type()) + } +} + +func (p *parameterBuilder) buildFromFieldStruct(tpe *types.Struct, typable swaggerTypable) error { + sb := schemaBuilder{ + decl: p.decl, + ctx: p.ctx, + } + + if err := sb.buildFromType(tpe, typable); err != nil { + return err + } + p.postDecls = append(p.postDecls, sb.postDecls...) + + return nil +} + +func (p *parameterBuilder) buildFromFieldMap(ftpe *types.Map, typable swaggerTypable) error { + schema := new(spec.Schema) + typable.Schema().Typed("object", "").AdditionalProperties = &spec.SchemaOrBool{ + Schema: schema, + } + + sb := schemaBuilder{ + decl: p.decl, + ctx: p.ctx, + } + + if err := sb.buildFromType(ftpe.Elem(), schemaTypable{schema, typable.Level() + 1}); err != nil { + return err + } + + return nil +} + +func (p *parameterBuilder) buildFromFieldInterface(tpe *types.Interface, typable swaggerTypable) error { + sb := schemaBuilder{ + decl: p.decl, + ctx: p.ctx, + } + + if err := sb.buildFromType(tpe, typable); err != nil { + return err + } + + p.postDecls = append(p.postDecls, sb.postDecls...) + + return nil +} + +func (p *parameterBuilder) buildNamedField(ftpe *types.Named, typable swaggerTypable) error { + o := ftpe.Obj() + if isAny(o) { + // e.g. Field interface{} or Field any + return nil + } + if isStdError(o) { + return fmt.Errorf("%s type not supported in the context of a parameter definition", o.Name()) + } + mustNotBeABuiltinType(o) + + decl, found := p.ctx.DeclForType(o.Type()) + if !found { + return fmt.Errorf("unable to find package and source file for: %s", ftpe.String()) + } + + if isStdTime(o) { + typable.Typed("string", "date-time") + return nil + } + + if sfnm, isf := strfmtName(decl.Comments); isf { + typable.Typed("string", sfnm) + return nil + } + + sb := &schemaBuilder{ctx: p.ctx, decl: decl} + sb.inferNames() + if err := sb.buildFromType(decl.ObjType(), typable); err != nil { + return err + } + + p.postDecls = append(p.postDecls, sb.postDecls...) + + return nil +} + +func (p *parameterBuilder) buildFieldAlias(tpe *types.Alias, typable swaggerTypable, fld *types.Var, seen map[string]spec.Parameter) error { + o := tpe.Obj() + if isAny(o) { + // e.g. Field interface{} or Field any + _ = typable.Schema() + + return nil // just leave an empty schema + } + if isStdError(o) { + return fmt.Errorf("%s type not supported in the context of a parameter definition", o.Name()) + } + mustNotBeABuiltinType(o) + mustHaveRightHandSide(tpe) + + rhs := tpe.Rhs() + decl, ok := p.ctx.FindModel(o.Pkg().Path(), o.Name()) + if !ok { + return fmt.Errorf("can't find source file for aliased type: %v -> %v", tpe, rhs) + } + p.postDecls = append(p.postDecls, decl) // mark the left-hand side as discovered + + if typable.In() != "body" || !p.ctx.app.refAliases { + // if ref option is disabled, and always for non-body parameters: just expand the alias + unaliased := types.Unalias(tpe) + return p.buildFromField(fld, unaliased, typable, seen) + } + + // for parameters that are full-fledged schemas, consider expanding or ref'ing + switch rtpe := rhs.(type) { + // load declaration for named RHS type (might be an alias itself) + case *types.Named: + o := rtpe.Obj() + if o.Pkg() == nil { + break // builtin } - sb := schemaBuilder{ - decl: p.decl, - ctx: p.ctx, + + decl, found := p.ctx.FindModel(o.Pkg().Path(), o.Name()) + if !found { + return fmt.Errorf("can't find source file for target type of alias: %v -> %v", tpe, rtpe) } - if err := sb.buildFromType(ftpe.Elem(), schemaTypable{schema, typable.Level() + 1}); err != nil { - return err + + return p.makeRef(decl, typable) + case *types.Alias: + o := rtpe.Obj() + if o.Pkg() == nil { + break // builtin } - return nil - case *types.Named: - if decl, found := p.ctx.DeclForType(ftpe.Obj().Type()); found { - if decl.Type.Obj().Pkg().Path() == "time" && decl.Type.Obj().Name() == "Time" { - typable.Typed("string", "date-time") - return nil - } - if sfnm, isf := strfmtName(decl.Comments); isf { - typable.Typed("string", sfnm) - return nil - } - sb := &schemaBuilder{ctx: p.ctx, decl: decl} - sb.inferNames() - if err := sb.buildFromType(decl.Type, typable); err != nil { - return err - } - p.postDecls = append(p.postDecls, sb.postDecls...) - return nil + + decl, found := p.ctx.FindModel(o.Pkg().Path(), o.Name()) + if !found { + return fmt.Errorf("can't find source file for target type of alias: %v -> %v", tpe, rtpe) } - return fmt.Errorf("unable to find package and source file for: %s", ftpe.String()) - default: - return fmt.Errorf("unknown type for %s: %T", fld.String(), fld.Type()) + + return p.makeRef(decl, typable) } + + // anonymous type: just expand it + return p.buildFromField(fld, rhs, typable, seen) } func spExtensionsSetter(ps *spec.Parameter) func(*spec.Extensions) { @@ -515,3 +680,16 @@ func (p *parameterBuilder) buildFromStruct(decl *entityDecl, tpe *types.Struct, } return nil } + +func (p *parameterBuilder) makeRef(decl *entityDecl, prop swaggerTypable) error { + nm, _ := decl.Names() + ref, err := spec.NewRef("#/definitions/" + nm) + if err != nil { + return err + } + + prop.SetRef(ref) + p.postDecls = append(p.postDecls, decl) // mark the $ref target as discovered + + return nil +} diff --git a/vendor/github.com/go-swagger/go-swagger/codescan/parser.go b/vendor/github.com/go-swagger/go-swagger/codescan/parser.go index 3733d50df..3582ad7e7 100644 --- a/vendor/github.com/go-swagger/go-swagger/codescan/parser.go +++ b/vendor/github.com/go-swagger/go-swagger/codescan/parser.go @@ -5,15 +5,17 @@ import ( "errors" "fmt" "go/ast" + "go/types" "log" "reflect" "regexp" "strconv" "strings" + "gopkg.in/yaml.v3" + "github.com/go-openapi/loads/fmts" "github.com/go-openapi/spec" - "gopkg.in/yaml.v3" ) func shouldAcceptTag(tags []string, includeTags map[string]bool, excludeTags map[string]bool) bool { @@ -204,6 +206,7 @@ type swaggerTypable interface { AddExtension(key string, value interface{}) WithEnum(...interface{}) WithEnumDescription(desc string) + In() string } // Map all Go builtin types that have Json representation to Swagger/Json types. @@ -695,11 +698,11 @@ func (sm *setMaximum) Parse(lines []string) error { } matches := sm.rx.FindStringSubmatch(lines[0]) if len(matches) > 2 && len(matches[2]) > 0 { - max, err := strconv.ParseFloat(matches[2], 64) + maximum, err := strconv.ParseFloat(matches[2], 64) if err != nil { return err } - sm.builder.SetMaximum(max, matches[1] == "<") + sm.builder.SetMaximum(maximum, matches[1] == "<") } return nil } @@ -723,11 +726,11 @@ func (sm *setMinimum) Parse(lines []string) error { } matches := sm.rx.FindStringSubmatch(lines[0]) if len(matches) > 2 && len(matches[2]) > 0 { - min, err := strconv.ParseFloat(matches[2], 64) + minimum, err := strconv.ParseFloat(matches[2], 64) if err != nil { return err } - sm.builder.SetMinimum(min, matches[1] == ">") + sm.builder.SetMinimum(minimum, matches[1] == ">") } return nil } @@ -1685,8 +1688,8 @@ func (ss *setOpExtensions) Parse(lines []string) error { exts.AddExtension(ext.Extension, ext.Root.(map[string]string)[ext.Extension]) } else if _, ok := ext.Root.(map[string]*[]string); ok { exts.AddExtension(ext.Extension, *(ext.Root.(map[string]*[]string)[ext.Extension])) - } else if _, ok := ext.Root.(map[string]interface{}); ok { - exts.AddExtension(ext.Extension, ext.Root.(map[string]interface{})[ext.Extension]) + } else if _, ok := ext.Root.(map[string]any); ok { + exts.AddExtension(ext.Extension, ext.Root.(map[string]any)[ext.Extension]) } else { debugLog("Unknown Extension type: %s", fmt.Sprint(reflect.TypeOf(ext.Root))) } @@ -1695,3 +1698,60 @@ func (ss *setOpExtensions) Parse(lines []string) error { ss.set(&exts.Extensions) return nil } + +var unsupportedTypes = map[string]struct{}{ + "complex64": {}, + "complex128": {}, +} + +type objecter interface { + Obj() *types.TypeName +} + +func unsupportedBuiltinType(tpe types.Type) bool { + unaliased := types.Unalias(tpe) + + switch ftpe := unaliased.(type) { + case *types.Basic: + return unsupportedBasic(ftpe) + case *types.TypeParam: + return true + case *types.Chan: + return true + case *types.Signature: + return true + case objecter: + return unsupportedBuiltin(ftpe) + default: + return false + } +} + +func unsupportedBuiltin(tpe objecter) bool { + o := tpe.Obj() + if o == nil { + return false + } + + if o.Pkg() != nil { + if o.Pkg().Path() == "unsafe" { + return true + } + + return false // not a builtin type + } + + _, found := unsupportedTypes[o.Name()] + + return found +} + +func unsupportedBasic(tpe *types.Basic) bool { + if tpe.Kind() == types.UnsafePointer { + return true + } + + _, found := unsupportedTypes[tpe.Name()] + + return found +} diff --git a/vendor/github.com/go-swagger/go-swagger/codescan/responses.go b/vendor/github.com/go-swagger/go-swagger/codescan/responses.go index 39274baf0..cf99b7474 100644 --- a/vendor/github.com/go-swagger/go-swagger/codescan/responses.go +++ b/vendor/github.com/go-swagger/go-swagger/codescan/responses.go @@ -7,8 +7,9 @@ import ( "go/types" "strings" - "github.com/go-openapi/spec" "golang.org/x/tools/go/ast/astutil" + + "github.com/go-openapi/spec" ) type responseTypable struct { @@ -17,6 +18,8 @@ type responseTypable struct { response *spec.Response } +func (ht responseTypable) In() string { return ht.in } + func (ht responseTypable) Level() int { return 0 } func (ht responseTypable) Typed(tpe, format string) { @@ -52,7 +55,7 @@ func (ht responseTypable) Items() swaggerTypable { ht.header.Items = new(spec.Items) } ht.header.Type = "array" - return itemsTypable{ht.header.Items, 1} + return itemsTypable{ht.header.Items, 1, "header"} } func (ht responseTypable) SetRef(ref spec.Ref) { @@ -171,7 +174,7 @@ func (r *responseBuilder) Build(responses map[string]spec.Response) error { // * has to document the validations that apply for the type and the field // * when the struct field points to a model it becomes a ref: #/definitions/ModelName // * comments that aren't tags is used as the description - if err := r.buildFromType(r.decl.Type, &response, make(map[string]bool)); err != nil { + if err := r.buildFromType(r.decl.ObjType(), &response, make(map[string]bool)); err != nil { return err } responses[name] = response @@ -180,52 +183,117 @@ func (r *responseBuilder) Build(responses map[string]spec.Response) error { func (r *responseBuilder) buildFromField(fld *types.Var, tpe types.Type, typable swaggerTypable, seen map[string]bool) error { debugLog("build from field %s: %T", fld.Name(), tpe) + switch ftpe := tpe.(type) { case *types.Basic: return swaggerSchemaForType(ftpe.Name(), typable) case *types.Struct: - sb := schemaBuilder{ - decl: r.decl, - ctx: r.ctx, - } - if err := sb.buildFromType(tpe, typable); err != nil { - return err - } - r.postDecls = append(r.postDecls, sb.postDecls...) - return nil + return r.buildFromFieldStruct(ftpe, typable) case *types.Pointer: return r.buildFromField(fld, ftpe.Elem(), typable, seen) case *types.Interface: - sb := schemaBuilder{ - decl: r.decl, - ctx: r.ctx, - } - if err := sb.buildFromType(tpe, typable); err != nil { - return err - } - r.postDecls = append(r.postDecls, sb.postDecls...) - return nil + return r.buildFromFieldInterface(ftpe, typable) case *types.Array: return r.buildFromField(fld, ftpe.Elem(), typable.Items(), seen) case *types.Slice: return r.buildFromField(fld, ftpe.Elem(), typable.Items(), seen) case *types.Map: - schema := new(spec.Schema) - typable.Schema().Typed("object", "").AdditionalProperties = &spec.SchemaOrBool{ - Schema: schema, - } - sb := schemaBuilder{ - decl: r.decl, - ctx: r.ctx, - } - if err := sb.buildFromType(ftpe.Elem(), schemaTypable{schema, typable.Level() + 1}); err != nil { - return err - } - r.postDecls = append(r.postDecls, sb.postDecls...) - return nil + return r.buildFromFieldMap(ftpe, typable) case *types.Named: - if decl, found := r.ctx.DeclForType(ftpe.Obj().Type()); found { - if decl.Type.Obj().Pkg().Path() == "time" && decl.Type.Obj().Name() == "Time" { + return r.buildNamedField(ftpe, typable) + case *types.Alias: + debugLog("alias(responses.buildFromField): got alias %v to %v", ftpe, ftpe.Rhs()) + return r.buildFieldAlias(ftpe, typable, fld, seen) + default: + return fmt.Errorf("unknown type for %s: %T", fld.String(), fld.Type()) + } +} + +func (r *responseBuilder) buildFromFieldStruct(ftpe *types.Struct, typable swaggerTypable) error { + sb := schemaBuilder{ + decl: r.decl, + ctx: r.ctx, + } + + if err := sb.buildFromType(ftpe, typable); err != nil { + return err + } + + r.postDecls = append(r.postDecls, sb.postDecls...) + + return nil +} + +func (r *responseBuilder) buildFromFieldMap(ftpe *types.Map, typable swaggerTypable) error { + schema := new(spec.Schema) + typable.Schema().Typed("object", "").AdditionalProperties = &spec.SchemaOrBool{ + Schema: schema, + } + + sb := schemaBuilder{ + decl: r.decl, + ctx: r.ctx, + } + + if err := sb.buildFromType(ftpe.Elem(), schemaTypable{schema, typable.Level() + 1}); err != nil { + return err + } + + r.postDecls = append(r.postDecls, sb.postDecls...) + + return nil +} + +func (r *responseBuilder) buildFromFieldInterface(tpe types.Type, typable swaggerTypable) error { + sb := schemaBuilder{ + decl: r.decl, + ctx: r.ctx, + } + if err := sb.buildFromType(tpe, typable); err != nil { + return err + } + r.postDecls = append(r.postDecls, sb.postDecls...) + + return nil +} + +func (r *responseBuilder) buildFromType(otpe types.Type, resp *spec.Response, seen map[string]bool) error { + switch tpe := otpe.(type) { + case *types.Pointer: + return r.buildFromType(tpe.Elem(), resp, seen) + case *types.Named: + return r.buildNamedType(tpe, resp, seen) + case *types.Alias: + debugLog("alias(responses.buildFromType): got alias %v to %v", tpe, tpe.Rhs()) + return r.buildAlias(tpe, resp, seen) + default: + return errors.New("anonymous types are currently not supported for responses") + } +} + +func (r *responseBuilder) buildNamedType(tpe *types.Named, resp *spec.Response, seen map[string]bool) error { + o := tpe.Obj() + if isAny(o) || isStdError(o) { + return fmt.Errorf("%s type not supported in the context of a responses section definition", o.Name()) + } + mustNotBeABuiltinType(o) + // ICI + + switch stpe := o.Type().Underlying().(type) { // TODO(fred): this is wrong without checking for aliases? + case *types.Struct: + debugLog("build from type %s: %T", o.Name(), tpe) + if decl, found := r.ctx.DeclForType(o.Type()); found { + return r.buildFromStruct(decl, stpe, resp, seen) + } + return r.buildFromStruct(r.decl, stpe, resp, seen) + + default: + if decl, found := r.ctx.DeclForType(o.Type()); found { + var schema spec.Schema + typable := schemaTypable{schema: &schema, level: 0} + + d := decl.Obj() + if isStdTime(d) { typable.Typed("string", "date-time") return nil } @@ -235,58 +303,111 @@ func (r *responseBuilder) buildFromField(fld *types.Var, tpe types.Type, typable } sb := &schemaBuilder{ctx: r.ctx, decl: decl} sb.inferNames() - if err := sb.buildFromType(decl.Type, typable); err != nil { + if err := sb.buildFromType(tpe.Underlying(), typable); err != nil { return err } + resp.WithSchema(&schema) r.postDecls = append(r.postDecls, sb.postDecls...) return nil } - return fmt.Errorf("unable to find package and source file for: %s", ftpe.String()) - default: - return fmt.Errorf("unknown type for %s: %T", fld.String(), fld.Type()) + return fmt.Errorf("responses can only be structs, did you mean for %s to be the response body?", tpe.String()) } } -func (r *responseBuilder) buildFromType(otpe types.Type, resp *spec.Response, seen map[string]bool) error { - switch tpe := otpe.(type) { - case *types.Pointer: - return r.buildFromType(tpe.Elem(), resp, seen) +func (r *responseBuilder) buildAlias(tpe *types.Alias, resp *spec.Response, seen map[string]bool) error { + // panic("yay") + o := tpe.Obj() + if isAny(o) || isStdError(o) { + // wrong: TODO(fred): see what object exactly we want to build here - figure out with specific tests + return fmt.Errorf("%s type not supported in the context of a responses section definition", o.Name()) + } + mustNotBeABuiltinType(o) + mustHaveRightHandSide(tpe) + + rhs := tpe.Rhs() + decl, ok := r.ctx.FindModel(o.Pkg().Path(), o.Name()) + if !ok { + return fmt.Errorf("can't find source file for aliased type: %v -> %v", tpe, rhs) + } + r.postDecls = append(r.postDecls, decl) // mark the left-hand side as discovered + + if !r.ctx.app.refAliases { + // expand alias + unaliased := types.Unalias(tpe) + return r.buildFromType(unaliased.Underlying(), resp, seen) + } + + switch rtpe := rhs.(type) { + // load declaration for named unaliased type case *types.Named: - o := tpe.Obj() - switch stpe := o.Type().Underlying().(type) { - case *types.Struct: - debugLog("build from type %s: %T", tpe.Obj().Name(), otpe) - if decl, found := r.ctx.DeclForType(o.Type()); found { - return r.buildFromStruct(decl, stpe, resp, seen) - } - return r.buildFromStruct(r.decl, stpe, resp, seen) - default: - if decl, found := r.ctx.DeclForType(o.Type()); found { - var schema spec.Schema - typable := schemaTypable{schema: &schema, level: 0} - - if decl.Type.Obj().Pkg().Path() == "time" && decl.Type.Obj().Name() == "Time" { - typable.Typed("string", "date-time") - return nil - } - if sfnm, isf := strfmtName(decl.Comments); isf { - typable.Typed("string", sfnm) - return nil - } - sb := &schemaBuilder{ctx: r.ctx, decl: decl} - sb.inferNames() - if err := sb.buildFromType(tpe.Underlying(), typable); err != nil { - return err - } - resp.WithSchema(&schema) - r.postDecls = append(r.postDecls, sb.postDecls...) - return nil - } - return fmt.Errorf("responses can only be structs, did you mean for %s to be the response body?", otpe.String()) + o := rtpe.Obj() + if o.Pkg() == nil { + break // builtin } - default: - return errors.New("anonymous types are currently not supported for responses") + + typable := schemaTypable{schema: &spec.Schema{}, level: 0} + return r.makeRef(decl, typable) + case *types.Alias: + o := rtpe.Obj() + if o.Pkg() == nil { + break // builtin + } + + typable := schemaTypable{schema: &spec.Schema{}, level: 0} + + return r.makeRef(decl, typable) } + + return r.buildFromType(rhs, resp, seen) +} + +func (r *responseBuilder) buildNamedField(ftpe *types.Named, typable swaggerTypable) error { + decl, found := r.ctx.DeclForType(ftpe.Obj().Type()) + if !found { + return fmt.Errorf("unable to find package and source file for: %s", ftpe.String()) + } + + d := decl.Obj() + if isStdTime(d) { + typable.Typed("string", "date-time") + return nil + } + + if sfnm, isf := strfmtName(decl.Comments); isf { + typable.Typed("string", sfnm) + return nil + } + + // ICI + sb := &schemaBuilder{ctx: r.ctx, decl: decl} + sb.inferNames() + if err := sb.buildFromType(decl.ObjType(), typable); err != nil { + return err + } + + r.postDecls = append(r.postDecls, sb.postDecls...) + + return nil +} + +func (r *responseBuilder) buildFieldAlias(tpe *types.Alias, typable swaggerTypable, fld *types.Var, seen map[string]bool) error { + _ = fld + _ = seen + o := tpe.Obj() + if isAny(o) { + // e.g. Field interface{} or Field any + _ = typable.Schema() + + return nil // just leave an empty schema + } + + decl, ok := r.ctx.FindModel(o.Pkg().Path(), o.Name()) + if !ok { + return fmt.Errorf("can't find source file for aliased type: %v", tpe) + } + r.postDecls = append(r.postDecls, decl) // mark the left-hand side as discovered + + return r.makeRef(decl, typable) } func (r *responseBuilder) buildFromStruct(decl *entityDecl, tpe *types.Struct, resp *spec.Response, seen map[string]bool) error { @@ -330,6 +451,7 @@ func (r *responseBuilder) buildFromStruct(decl *entityDecl, tpe *types.Struct, r // if the field is annotated with swagger:ignore, ignore it if ignored(afld.Doc) { + debugLog("field %v of type %v is deliberately ignored", fld, tpe) continue } @@ -362,8 +484,11 @@ func (r *responseBuilder) buildFromStruct(decl *entityDecl, tpe *types.Struct, r if afld.Doc != nil && fileParam(afld.Doc) { resp.Schema = &spec.Schema{} resp.Schema.Typed("file", "") - } else if err := r.buildFromField(fld, fld.Type(), responseTypable{in, &ps, resp}, seen); err != nil { - return err + } else { + debugLog("build response %v (%v) (not a file)", fld, fld.Type()) + if err := r.buildFromField(fld, fld.Type(), responseTypable{in, &ps, resp}, seen); err != nil { + return err + } } if strfmtName, ok := strfmtName(afld.Doc); ok { @@ -478,3 +603,16 @@ func (r *responseBuilder) buildFromStruct(decl *entityDecl, tpe *types.Struct, r } return nil } + +func (r *responseBuilder) makeRef(decl *entityDecl, prop swaggerTypable) error { + nm, _ := decl.Names() + ref, err := spec.NewRef("#/definitions/" + nm) + if err != nil { + return err + } + + prop.SetRef(ref) + r.postDecls = append(r.postDecls, decl) // mark the $ref target as discovered + + return nil +} diff --git a/vendor/github.com/go-swagger/go-swagger/codescan/schema.go b/vendor/github.com/go-swagger/go-swagger/codescan/schema.go index 640ac0830..670b2ece1 100644 --- a/vendor/github.com/go-swagger/go-swagger/codescan/schema.go +++ b/vendor/github.com/go-swagger/go-swagger/codescan/schema.go @@ -31,6 +31,8 @@ type schemaTypable struct { level int } +func (st schemaTypable) In() string { return "body" } + func (st schemaTypable) Typed(tpe, format string) { st.schema.Typed(tpe, format) } @@ -170,7 +172,7 @@ func (s *schemaBuilder) buildFromDecl(_ *entityDecl, schema *spec.Schema) error sp.setTitle = func(lines []string) { schema.Title = joinDropLast(lines) } sp.setDescription = func(lines []string) { schema.Description = joinDropLast(lines) - enumDesc := getEnumDesc(schema.VendorExtensible.Extensions) + enumDesc := getEnumDesc(schema.Extensions) if enumDesc != "" { schema.Description += "\n" + enumDesc } @@ -184,60 +186,83 @@ func (s *schemaBuilder) buildFromDecl(_ *entityDecl, schema *spec.Schema) error return nil } - switch tpe := s.decl.Type.Obj().Type().(type) { + defer func() { + if schema.Ref.String() == "" { + // unless this is a $ref, we add traceability of the origin of this schema in source + if s.Name != s.GoName { + addExtension(&schema.VendorExtensible, "x-go-name", s.GoName) + } + addExtension(&schema.VendorExtensible, "x-go-package", s.decl.Obj().Pkg().Path()) + } + }() + + switch tpe := s.decl.ObjType().(type) { + // TODO(fredbi): we may safely remove all the cases here that are not Named or Alias case *types.Basic: debugLog("basic: %v", tpe.Name()) + return nil case *types.Struct: - if err := s.buildFromStruct(s.decl, tpe, schema, make(map[string]string)); err != nil { - return err - } + return s.buildFromStruct(s.decl, tpe, schema, make(map[string]string)) case *types.Interface: - if err := s.buildFromInterface(s.decl, tpe, schema, make(map[string]string)); err != nil { - return err - } + return s.buildFromInterface(s.decl, tpe, schema, make(map[string]string)) case *types.Array: debugLog("array: %v -> %v", s.decl.Ident.Name, tpe.Elem().String()) + return nil case *types.Slice: debugLog("slice: %v -> %v", s.decl.Ident.Name, tpe.Elem().String()) + return nil case *types.Map: debugLog("map: %v -> [%v]%v", s.decl.Ident.Name, tpe.Key().String(), tpe.Elem().String()) + return nil case *types.Named: - o := tpe.Obj() - if o != nil { - debugLog("got the named type object: %s.%s | isAlias: %t | exported: %t", o.Pkg().Path(), o.Name(), o.IsAlias(), o.Exported()) - if o.Pkg().Name() == "time" && o.Name() == "Time" { - schema.Typed("string", "date-time") - return nil - } + debugLog("named: %v", tpe) + return s.buildDeclNamed(tpe, schema) + case *types.Alias: + debugLog("alias: %v -> %v", tpe, tpe.Rhs()) + tgt := schemaTypable{schema, 0} - ps := schemaTypable{schema, 0} - for { - ti := s.decl.Pkg.TypesInfo.Types[s.decl.Spec.Type] - if ti.IsBuiltin() { - break - } - if ti.IsType() { - if err := s.buildFromType(ti.Type, ps); err != nil { - return err - } - break - } - } - } + return s.buildDeclAlias(tpe, tgt) + case *types.TypeParam: + log.Printf("WARNING: generic type parameters are not supported yet %[1]v (%[1]T). Skipped", tpe) + return nil + case *types.Chan: + log.Printf("WARNING: channels are not supported %[1]v (%[1]T). Skipped", tpe) + return nil + case *types.Signature: + log.Printf("WARNING: functions are not supported %[1]v (%[1]T). Skipped", tpe) + return nil default: - log.Printf("WARNING: Missing parser for a %T, skipping model: %s\n", tpe, s.Name) + log.Printf("WARNING: missing parser for type %T, skipping model: %s\n", tpe, s.Name) return nil } +} - if schema.Ref.String() == "" { - if s.Name != s.GoName { - addExtension(&schema.VendorExtensible, "x-go-name", s.GoName) - } - addExtension(&schema.VendorExtensible, "x-go-package", s.decl.Type.Obj().Pkg().Path()) +func (s *schemaBuilder) buildDeclNamed(tpe *types.Named, schema *spec.Schema) error { + if unsupportedBuiltin(tpe) { + log.Printf("WARNING: skipped unsupported builtin type: %v", tpe) + + return nil } - return nil + o := tpe.Obj() + + mustNotBeABuiltinType(o) + + debugLog("got the named type object: %s.%s | isAlias: %t | exported: %t", o.Pkg().Path(), o.Name(), o.IsAlias(), o.Exported()) + if isStdTime(o) { + schema.Typed("string", "date-time") + return nil + } + + ps := schemaTypable{schema, 0} + ti := s.decl.Pkg.TypesInfo.Types[s.decl.Spec.Type] + if !ti.IsType() { + return fmt.Errorf("declaration is not a type: %v", o) + } + + return s.buildFromType(ti.Type, ps) } +// buildFromTextMarshal renders a type that marshals as text as a string func (s *schemaBuilder) buildFromTextMarshal(tpe types.Type, tgt swaggerTypable) error { if typePtr, ok := tpe.(*types.Pointer); ok { return s.buildFromTextMarshal(typePtr.Elem(), tgt) @@ -250,7 +275,8 @@ func (s *schemaBuilder) buildFromTextMarshal(tpe types.Type, tgt swaggerTypable) } tio := typeNamed.Obj() - if tio.Pkg() == nil && tio.Name() == "error" { + if isStdError(tio) { + tgt.AddExtension("x-go-type", tio.Name()) return swaggerSchemaForType(tio.Name(), tgt) } @@ -264,17 +290,20 @@ func (s *schemaBuilder) buildFromTextMarshal(tpe types.Type, tgt swaggerTypable) if !found { // this must be a builtin - debugLog("skipping because package is nil: %s", tpe.String()) + debugLog("skipping because package is nil: %v", tpe) return nil } - if pkg.Name == "time" && tio.Name() == "Time" { + + if isStdTime(tio) { tgt.Typed("string", "date-time") return nil } - if pkg.PkgPath == "encoding/json" && tio.Name() == "RawMessage" { - tgt.Typed("object", "") + + if isStdJSONRawMessage(tio) { + tgt.Typed("object", "") // TODO: this should actually be any type return nil } + cmt, hasComments := s.ctx.FindComments(pkg, tio.Name()) if !hasComments { cmt = new(ast.CommentGroup) @@ -286,26 +315,26 @@ func (s *schemaBuilder) buildFromTextMarshal(tpe types.Type, tgt swaggerTypable) } tgt.Typed("string", "") + tgt.AddExtension("x-go-type", tio.Pkg().Path()+"."+tio.Name()) + return nil } func (s *schemaBuilder) buildFromType(tpe types.Type, tgt swaggerTypable) error { - pkg, err := importer.Default().Import("encoding") - if err != nil { - return nil - } - ifc := pkg.Scope().Lookup("TextMarshaler").Type().Underlying().(*types.Interface) - // check if the type implements encoding.TextMarshaler interface - isTextMarshaler := types.Implements(tpe, ifc) - if isTextMarshaler { + // if so, the type is rendered as a string. + debugLog("schema buildFromType %v (%T)", tpe, tpe) + + if isTextMarshaler(tpe) { return s.buildFromTextMarshal(tpe, tgt) } switch titpe := tpe.(type) { - case *types.Alias: - return nil // resolves panic case *types.Basic: + if unsupportedBuiltinType(titpe) { + log.Printf("WARNING: skipped unsupported builtin type: %v", tpe) + return nil + } return swaggerSchemaForType(titpe.String(), tgt) case *types.Pointer: return s.buildFromType(titpe.Elem(), tgt) @@ -314,167 +343,451 @@ func (s *schemaBuilder) buildFromType(tpe types.Type, tgt swaggerTypable) error case *types.Interface: return s.buildFromInterface(s.decl, titpe, tgt.Schema(), make(map[string]string)) case *types.Slice: + // anonymous slice return s.buildFromType(titpe.Elem(), tgt.Items()) case *types.Array: + // anonymous array return s.buildFromType(titpe.Elem(), tgt.Items()) case *types.Map: - // debugLog("map: %v -> [%v]%v", fld.Name(), ftpe.Key().String(), ftpe.Elem().String()) - // check if key is a string type, if not print a message - // and skip the map property. Only maps with string keys can go into additional properties - sch := tgt.Schema() - if sch == nil { - return errors.New("items doesn't support maps") - } - eleProp := schemaTypable{sch, tgt.Level()} - key := titpe.Key() - isTextMarshaler := types.Implements(key, ifc) - if key.Underlying().String() == "string" || isTextMarshaler { - return s.buildFromType(titpe.Elem(), eleProp.AdditionalProperties()) - } + return s.buildFromMap(titpe, tgt) case *types.Named: - tio := titpe.Obj() - if tio.Pkg() == nil && tio.Name() == "error" { - return swaggerSchemaForType(tio.Name(), tgt) - } - debugLog("named refined type %s.%s", tio.Pkg().Path(), tio.Name()) - pkg, found := s.ctx.PkgForType(tpe) - if !found { - // this must be a builtin - debugLog("skipping because package is nil: %s", tpe.String()) + // a named type, e.g. type X struct {} + return s.buildNamedType(titpe, tgt) + case *types.Alias: + // a named alias, e.g. type X = {RHS type}. + debugLog("alias(schema.buildFromType): got alias %v to %v", titpe, titpe.Rhs()) + return s.buildAlias(titpe, tgt) + case *types.TypeParam: + log.Printf("WARNING: generic type parameters are not supported yet %[1]v (%[1]T). Skipped", titpe) + return nil + case *types.Chan: + log.Printf("WARNING: channels are not supported %[1]v (%[1]T). Skipped", tpe) + return nil + case *types.Signature: + log.Printf("WARNING: functions are not supported %[1]v (%[1]T). Skipped", tpe) + return nil + default: + panic(fmt.Errorf("ERROR: can't determine refined type %[1]v (%[1]T): %w", titpe, ErrInternal)) + } +} + +func (s *schemaBuilder) buildNamedType(titpe *types.Named, tgt swaggerTypable) error { + tio := titpe.Obj() + if unsupportedBuiltin(titpe) { + log.Printf("WARNING: skipped unsupported builtin type: %v", titpe) + return nil + } + if isAny(tio) { + // e.g type X any or type X interface{} + _ = tgt.Schema() + + return nil + } + + // special case of the "error" interface. + if isStdError(tio) { + tgt.AddExtension("x-go-type", tio.Name()) + return swaggerSchemaForType(tio.Name(), tgt) + } + + // special case of the "time.Time" type + if isStdTime(tio) { + tgt.Typed("string", "date-time") + return nil + } + + // special case of the "json.RawMessage" type + if isStdJSONRawMessage(tio) { + tgt.Typed("object", "") // TODO: this should actually be any type + return nil + } + + pkg, found := s.ctx.PkgForType(titpe) + debugLog("named refined type %s.%s", pkg, tio.Name()) + if !found { + // this must be a builtin + // + // This could happen for example when using unsupported types such as complex64, complex128, uintptr, + // or type constraints such as comparable. + debugLog("skipping because package is nil (builtin type): %v", tio) + + return nil + } + + cmt, hasComments := s.ctx.FindComments(pkg, tio.Name()) + if !hasComments { + cmt = new(ast.CommentGroup) + } + + if typeName, ok := typeName(cmt); ok { + _ = swaggerSchemaForType(typeName, tgt) + + return nil + } + + if s.decl.Spec.Assign.IsValid() { + debugLog("found assignment: %s.%s", tio.Pkg().Path(), tio.Name()) + return s.buildFromType(titpe.Underlying(), tgt) + } + + if titpe.TypeArgs() != nil && titpe.TypeArgs().Len() > 0 { + return s.buildFromType(titpe.Underlying(), tgt) + } + + // invariant: the Underlying cannot be an alias or named type + switch utitpe := titpe.Underlying().(type) { + case *types.Struct: + debugLog("found struct: %s.%s", tio.Pkg().Path(), tio.Name()) + + decl, ok := s.ctx.FindModel(tio.Pkg().Path(), tio.Name()) + if !ok { + debugLog("could not find model in index: %s.%s", tio.Pkg().Path(), tio.Name()) return nil } - if pkg.Name == "time" && tio.Name() == "Time" { + + o := decl.Obj() + if isStdTime(o) { tgt.Typed("string", "date-time") return nil } - if pkg.PkgPath == "encoding/json" && tio.Name() == "RawMessage" { - tgt.Typed("object", "") + + if sfnm, isf := strfmtName(cmt); isf { + tgt.Typed("string", sfnm) return nil } - cmt, hasComments := s.ctx.FindComments(pkg, tio.Name()) - if !hasComments { - cmt = new(ast.CommentGroup) - } if typeName, ok := typeName(cmt); ok { _ = swaggerSchemaForType(typeName, tgt) return nil } - if s.decl.Spec.Assign.IsValid() { - return s.buildFromType(titpe.Underlying(), tgt) + return s.makeRef(decl, tgt) + case *types.Interface: + debugLog("found interface: %s.%s", tio.Pkg().Path(), tio.Name()) + + decl, found := s.ctx.FindModel(tio.Pkg().Path(), tio.Name()) + if !found { + return fmt.Errorf("can't find source file for type: %v", utitpe) } - if titpe.TypeArgs() != nil && titpe.TypeArgs().Len() > 0 { - return s.buildFromType(titpe.Underlying(), tgt) + return s.makeRef(decl, tgt) + case *types.Basic: + if unsupportedBuiltinType(utitpe) { + log.Printf("WARNING: skipped unsupported builtin type: %v", utitpe) + return nil } - switch utitpe := tpe.Underlying().(type) { - case *types.Struct: - if decl, ok := s.ctx.FindModel(tio.Pkg().Path(), tio.Name()); ok { - if decl.Type.Obj().Pkg().Path() == "time" && decl.Type.Obj().Name() == "Time" { - tgt.Typed("string", "date-time") - return nil - } - if sfnm, isf := strfmtName(cmt); isf { - tgt.Typed("string", sfnm) - return nil - } - if typeName, ok := typeName(cmt); ok { - _ = swaggerSchemaForType(typeName, tgt) - return nil - } + debugLog("found primitive type: %s.%s", tio.Pkg().Path(), tio.Name()) - return s.makeRef(decl, tgt) - } - case *types.Interface: - if decl, ok := s.ctx.FindModel(tio.Pkg().Path(), tio.Name()); ok { - return s.makeRef(decl, tgt) + if sfnm, isf := strfmtName(cmt); isf { + tgt.Typed("string", sfnm) + return nil + } + + if enumName, ok := enumName(cmt); ok { + enumValues, enumDesces, _ := s.ctx.FindEnumValues(pkg, enumName) + if len(enumValues) > 0 { + tgt.WithEnum(enumValues...) + enumTypeName := reflect.TypeOf(enumValues[0]).String() + _ = swaggerSchemaForType(enumTypeName, tgt) } - case *types.Basic: - if sfnm, isf := strfmtName(cmt); isf { - tgt.Typed("string", sfnm) - return nil + if len(enumDesces) > 0 { + tgt.WithEnumDescription(strings.Join(enumDesces, "\n")) } + return nil + } - if enumName, ok := enumName(cmt); ok { - enumValues, enumDesces, _ := s.ctx.FindEnumValues(pkg, enumName) - if len(enumValues) > 0 { - tgt.WithEnum(enumValues...) - enumTypeName := reflect.TypeOf(enumValues[0]).String() - _ = swaggerSchemaForType(enumTypeName, tgt) - } - if len(enumDesces) > 0 { - tgt.WithEnumDescription(strings.Join(enumDesces, "\n")) - } - return nil - } + if defaultName, ok := defaultName(cmt); ok { + debugLog("default name: %s", defaultName) + return nil + } - if defaultName, ok := defaultName(cmt); ok { - debugLog(defaultName) //nolint:govet + if typeName, ok := typeName(cmt); ok { + _ = swaggerSchemaForType(typeName, tgt) + return nil + + } + + if isAliasParam(tgt) || aliasParam(cmt) { + err := swaggerSchemaForType(utitpe.Name(), tgt) + if err == nil { return nil } + } - if typeName, ok := typeName(cmt); ok { - _ = swaggerSchemaForType(typeName, tgt) - return nil + if decl, ok := s.ctx.FindModel(tio.Pkg().Path(), tio.Name()); ok { + return s.makeRef(decl, tgt) + } - } + return swaggerSchemaForType(utitpe.String(), tgt) + case *types.Array: + debugLog("found array type: %s.%s", tio.Pkg().Path(), tio.Name()) - if isAliasParam(tgt) || aliasParam(cmt) { - err := swaggerSchemaForType(utitpe.Name(), tgt) - if err == nil { - return nil - } + if sfnm, isf := strfmtName(cmt); isf { + if sfnm == "byte" { + tgt.Typed("string", sfnm) + return nil } - if decl, ok := s.ctx.FindModel(tio.Pkg().Path(), tio.Name()); ok { - return s.makeRef(decl, tgt) + if sfnm == "bsonobjectid" { + tgt.Typed("string", sfnm) + return nil } - return swaggerSchemaForType(utitpe.String(), tgt) - case *types.Array: - if sfnm, isf := strfmtName(cmt); isf { - if sfnm == "byte" { - tgt.Typed("string", sfnm) - return nil - } - if sfnm == "bsonobjectid" { - tgt.Typed("string", sfnm) - return nil - } - tgt.Items().Typed("string", sfnm) + tgt.Items().Typed("string", sfnm) + return nil + } + if decl, ok := s.ctx.FindModel(tio.Pkg().Path(), tio.Name()); ok { + return s.makeRef(decl, tgt) + } + return s.buildFromType(utitpe.Elem(), tgt.Items()) + case *types.Slice: + debugLog("found slice type: %s.%s", tio.Pkg().Path(), tio.Name()) + + if sfnm, isf := strfmtName(cmt); isf { + if sfnm == "byte" { + tgt.Typed("string", sfnm) return nil } - if decl, ok := s.ctx.FindModel(tio.Pkg().Path(), tio.Name()); ok { - return s.makeRef(decl, tgt) + tgt.Items().Typed("string", sfnm) + return nil + } + if decl, ok := s.ctx.FindModel(tio.Pkg().Path(), tio.Name()); ok { + return s.makeRef(decl, tgt) + } + return s.buildFromType(utitpe.Elem(), tgt.Items()) + case *types.Map: + debugLog("found map type: %s.%s", tio.Pkg().Path(), tio.Name()) + + if decl, ok := s.ctx.FindModel(tio.Pkg().Path(), tio.Name()); ok { + return s.makeRef(decl, tgt) + } + return nil + case *types.TypeParam: + log.Printf("WARNING: generic type parameters are not supported yet %[1]v (%[1]T). Skipped", utitpe) + return nil + case *types.Chan: + log.Printf("WARNING: channels are not supported %[1]v (%[1]T). Skipped", utitpe) + return nil + case *types.Signature: + log.Printf("WARNING: functions are not supported %[1]v (%[1]T). Skipped", utitpe) + return nil + default: + log.Printf( + "WARNING: can't figure out object type for named type (%T): %v [alias: %t]", + titpe.Underlying(), titpe.Underlying(), titpe.Obj().IsAlias(), + ) + + return nil + } +} + +// buildDeclAlias builds a top-level alias declaration. +func (s *schemaBuilder) buildDeclAlias(tpe *types.Alias, tgt swaggerTypable) error { + if unsupportedBuiltinType(tpe) { + log.Printf("WARNING: skipped unsupported builtin type: %v", tpe) + return nil + } + + o := tpe.Obj() + if isAny(o) { + _ = tgt.Schema() // this is mutating tgt to create an empty schema + return nil + } + if isStdError(o) { + tgt.AddExtension("x-go-type", o.Name()) + return swaggerSchemaForType(o.Name(), tgt) + } + mustNotBeABuiltinType(o) + + if isStdTime(o) { + tgt.Typed("string", "date-time") + return nil + } + + mustHaveRightHandSide(tpe) + rhs := tpe.Rhs() + + decl, ok := s.ctx.FindModel(o.Pkg().Path(), o.Name()) + if !ok { + return fmt.Errorf("can't find source file for aliased type: %v -> %v", tpe, rhs) + } + + s.postDecls = append(s.postDecls, decl) // mark the left-hand side as discovered + + if !s.ctx.app.refAliases { + // expand alias + return s.buildFromType(tpe.Underlying(), tgt) + } + + // resolve alias to named type as $ref + switch rtpe := rhs.(type) { + // named declarations: we construct a $ref to the right-hand side target of the alias + case *types.Named: + ro := rtpe.Obj() + rdecl, found := s.ctx.FindModel(ro.Pkg().Path(), ro.Name()) + if !found { + return fmt.Errorf("can't find source file for target type of alias: %v -> %v", tpe, rtpe) + } + + return s.makeRef(rdecl, tgt) + case *types.Alias: + ro := rtpe.Obj() + if unsupportedBuiltin(rtpe) { + log.Printf("WARNING: skipped unsupported builtin type: %v", rtpe) + return nil + } + if isAny(ro) { + // e.g. type X = any + _ = tgt.Schema() // this is mutating tgt to create an empty schema + return nil + } + if isStdError(ro) { + // e.g. type X = error + tgt.AddExtension("x-go-type", o.Name()) + return swaggerSchemaForType(o.Name(), tgt) + } + mustNotBeABuiltinType(ro) // TODO(fred): there are a few other cases + + rdecl, found := s.ctx.FindModel(ro.Pkg().Path(), ro.Name()) + if !found { + return fmt.Errorf("can't find source file for target type of alias: %v -> %v", tpe, rtpe) + } + + return s.makeRef(rdecl, tgt) + } + + // alias to anonymous type + return s.buildFromType(rhs, tgt) +} + +func (s *schemaBuilder) buildAnonymousInterface(it *types.Interface, tgt swaggerTypable, decl *entityDecl) error { + tgt.Typed("object", "") + + for i := range it.NumExplicitMethods() { + fld := it.ExplicitMethod(i) + if !fld.Exported() { + continue + } + sig, isSignature := fld.Type().(*types.Signature) + if !isSignature { + continue + } + if sig.Params().Len() > 0 { + continue + } + if sig.Results() == nil || sig.Results().Len() != 1 { + continue + } + + var afld *ast.Field + ans, _ := astutil.PathEnclosingInterval(decl.File, fld.Pos(), fld.Pos()) + // debugLog("got %d nodes (exact: %t)", len(ans), isExact) + for _, an := range ans { + at, valid := an.(*ast.Field) + if !valid { + continue } - return s.buildFromType(utitpe.Elem(), tgt.Items()) - case *types.Slice: - if sfnm, isf := strfmtName(cmt); isf { - if sfnm == "byte" { - tgt.Typed("string", sfnm) - return nil + + debugLog("maybe interface field %s: %s(%T)", fld.Name(), fld.Type().String(), fld.Type()) + afld = at + break + } + + if afld == nil { + debugLog("can't find source associated with %s for %s", fld.String(), it.String()) + continue + } + + // if the field is annotated with swagger:ignore, ignore it + if ignored(afld.Doc) { + continue + } + + name := fld.Name() + if afld.Doc != nil { + for _, cmt := range afld.Doc.List { + for _, ln := range strings.Split(cmt.Text, "\n") { + matches := rxName.FindStringSubmatch(ln) + ml := len(matches) + if ml > 1 { + name = matches[ml-1] + } } - tgt.Items().Typed("string", sfnm) - return nil - } - if decl, ok := s.ctx.FindModel(tio.Pkg().Path(), tio.Name()); ok { - return s.makeRef(decl, tgt) - } - return s.buildFromType(utitpe.Elem(), tgt.Items()) - case *types.Map: - if decl, ok := s.ctx.FindModel(tio.Pkg().Path(), tio.Name()); ok { - return s.makeRef(decl, tgt) } - return nil + } - default: - log.Printf("WARNING: can't figure out object type for named type (%T): %v [alias: %t]", tpe.Underlying(), tpe.Underlying(), titpe.Obj().IsAlias()) + if tgt.Schema().Properties == nil { + tgt.Schema().Properties = make(map[string]spec.Schema) + } + ps := tgt.Schema().Properties[name] + if err := s.buildFromType(sig.Results().At(0).Type(), schemaTypable{&ps, 0}); err != nil { + return err + } + if sfName, isStrfmt := strfmtName(afld.Doc); isStrfmt { + ps.Typed("string", sfName) + ps.Ref = spec.Ref{} + ps.Items = nil + } - return nil + if err := s.createParser(name, tgt.Schema(), &ps, afld).Parse(afld.Doc); err != nil { + return err } - default: - panic(fmt.Sprintf("WARNING: can't determine refined type %s (%T)", titpe.String(), titpe)) + + if ps.Ref.String() == "" && name != fld.Name() { + ps.AddExtension("x-go-name", fld.Name()) + } + + if s.ctx.app.setXNullableForPointers { + if _, isPointer := fld.Type().(*types.Signature).Results().At(0).Type().(*types.Pointer); isPointer && (ps.Extensions == nil || (ps.Extensions["x-nullable"] == nil && ps.Extensions["x-isnullable"] == nil)) { + ps.AddExtension("x-nullable", true) + } + } + + // seen[name] = fld.Name() + tgt.Schema().Properties[name] = ps + } + + return nil +} + +// buildAlias builds a reference to an alias from another type. +func (s *schemaBuilder) buildAlias(tpe *types.Alias, tgt swaggerTypable) error { + if unsupportedBuiltinType(tpe) { + log.Printf("WARNING: skipped unsupported builtin type: %v", tpe) + + return nil + } + + o := tpe.Obj() + if isAny(o) { + _ = tgt.Schema() + return nil + } + mustNotBeABuiltinType(o) + + decl, ok := s.ctx.FindModel(o.Pkg().Path(), o.Name()) + if !ok { + return fmt.Errorf("can't find source file for aliased type: %v", tpe) + } + + return s.makeRef(decl, tgt) +} + +func (s *schemaBuilder) buildFromMap(titpe *types.Map, tgt swaggerTypable) error { + // check if key is a string type, or knows how to marshall to text. + // If not, print a message and skip the map property. + // + // Only maps with string keys can go into additional properties + + sch := tgt.Schema() + if sch == nil { + return errors.New("items doesn't support maps") + } + + eleProp := schemaTypable{sch, tgt.Level()} + key := titpe.Key() + if key.Underlying().String() == "string" || isTextMarshaler(key) { + return s.buildFromType(titpe.Elem(), eleProp.AdditionalProperties()) } return nil @@ -482,6 +795,7 @@ func (s *schemaBuilder) buildFromType(tpe types.Type, tgt swaggerTypable) error func (s *schemaBuilder) buildFromInterface(decl *entityDecl, it *types.Interface, schema *spec.Schema, seen map[string]string) error { if it.Empty() { + // return an empty schema for empty interfaces return nil } @@ -494,98 +808,91 @@ func (s *schemaBuilder) buildFromInterface(decl *entityDecl, it *types.Interface if specType, ok := decl.Spec.Type.(*ast.InterfaceType); ok { flist = make([]*ast.Field, it.NumEmbeddeds()+it.NumExplicitMethods()) copy(flist, specType.Methods.List) - // for i := range specType.Methods.List { - // flist[i] = specType.Methods.List[i] - // } } // First collect the embedded interfaces - // create refs when the embedded interface is decorated with an allOf annotation - for i := 0; i < it.NumEmbeddeds(); i++ { + // create refs when: + // + // 1. the embedded interface is decorated with an allOf annotation + // 2. the embedded interface is an alias + for i := range it.NumEmbeddeds() { fld := it.EmbeddedType(i) + debugLog("inspecting embedded type in interface: %v", fld) + var ( + fieldHasAllOf bool + err error + ) + + if tgt == nil { + tgt = &spec.Schema{} + } switch ftpe := fld.(type) { case *types.Named: + debugLog("embedded named type (buildInterface): %v", ftpe) o := ftpe.Obj() - var afld *ast.Field - for _, an := range flist { - if len(an.Names) != 0 { - continue - } - - tpp := decl.Pkg.TypesInfo.Types[an.Type] - if tpp.Type.String() != o.Type().String() { - continue - } - - // decl. - debugLog("maybe interface field %s: %s(%T)", o.Name(), o.Type().String(), o.Type()) - afld = an - break - } - - if afld == nil { - debugLog("can't find source associated with %s for %s", fld.String(), it.String()) + if isAny(o) || isStdError(o) { + // ignore bultin interfaces continue } - // if the field is annotated with swagger:ignore, ignore it - if ignored(afld.Doc) { - continue + if fieldHasAllOf, err = s.buildNamedInterface(ftpe, flist, decl, schema, seen); err != nil { + return err } - - if !allOfMember(afld.Doc) { - var newSch spec.Schema - if err := s.buildEmbedded(o.Type(), &newSch, seen); err != nil { - return err - } - schema.AllOf = append(schema.AllOf, newSch) - hasAllOf = true - continue + case *types.Interface: + debugLog("embedded anonymous interface type (buildInterface): %v", ftpe) // e.g. type X interface{ interface{Error() string}} + var aliasedSchema spec.Schema + ps := schemaTypable{schema: &aliasedSchema} + if err = s.buildAnonymousInterface(ftpe, ps, decl); err != nil { + return err } - hasAllOf = true - if tgt == nil { - tgt = &spec.Schema{} + if aliasedSchema.Ref.String() != "" || len(aliasedSchema.Properties) > 0 || len(aliasedSchema.AllOf) > 0 { + schema.AddToAllOf(aliasedSchema) + fieldHasAllOf = true } - var newSch spec.Schema - // when the embedded struct is annotated with swagger:allOf it will be used as allOf property - // otherwise the fields will just be included as normal properties - if err := s.buildAllOf(o.Type(), &newSch); err != nil { + case *types.Alias: + debugLog("embedded alias (buildInterface): %v -> %v", ftpe, ftpe.Rhs()) + var aliasedSchema spec.Schema + ps := schemaTypable{schema: &aliasedSchema} + if err = s.buildAlias(ftpe, ps); err != nil { return err } - if afld.Doc != nil { - for _, cmt := range afld.Doc.List { - for _, ln := range strings.Split(cmt.Text, "\n") { - matches := rxAllOf.FindStringSubmatch(ln) - ml := len(matches) - if ml > 1 { - mv := matches[ml-1] - if mv != "" { - schema.AddExtension("x-class", mv) - } - } - } - } - } - schema.AllOf = append(schema.AllOf, newSch) + if aliasedSchema.Ref.String() != "" || len(aliasedSchema.Properties) > 0 || len(aliasedSchema.AllOf) > 0 { + schema.AddToAllOf(aliasedSchema) + fieldHasAllOf = true + } + case *types.Union: // e.g. type X interface{ ~uint16 | ~float32 } + log.Printf("WARNING: union type constraints are not supported yet %[1]v (%[1]T). Skipped", ftpe) + case *types.TypeParam: + log.Printf("WARNING: generic type parameters are not supported yet %[1]v (%[1]T). Skipped", ftpe) + case *types.Chan: + log.Printf("WARNING: channels are not supported %[1]v (%[1]T). Skipped", ftpe) + case *types.Signature: + log.Printf("WARNING: functions are not supported %[1]v (%[1]T). Skipped", ftpe) default: - log.Printf("WARNING: can't figure out object type for allOf named type (%T): %v", ftpe, ftpe.Underlying()) + log.Printf( + "WARNING: can't figure out object type for allOf named type (%T): %v", + ftpe, ftpe.Underlying(), + ) } - debugLog("got embedded interface: %s {%T}", fld.String(), fld) + + debugLog("got embedded interface: %v {%T}, fieldHasAllOf: %t", fld, fld, fieldHasAllOf) + hasAllOf = hasAllOf || fieldHasAllOf } if tgt == nil { tgt = schema } + // We can finally build the actual schema for the struct if tgt.Properties == nil { tgt.Properties = make(map[string]spec.Schema) } tgt.Typed("object", "") - for i := 0; i < it.NumExplicitMethods(); i++ { + for i := range it.NumExplicitMethods() { fld := it.ExplicitMethod(i) if !fld.Exported() { continue @@ -671,17 +978,91 @@ func (s *schemaBuilder) buildFromInterface(decl *entityDecl, it *types.Interface if hasAllOf && len(tgt.Properties) > 0 { schema.AllOf = append(schema.AllOf, *tgt) } + for k := range tgt.Properties { if _, ok := seen[k]; !ok { delete(tgt.Properties, k) } } + return nil } +func (s *schemaBuilder) buildNamedInterface(ftpe *types.Named, flist []*ast.Field, decl *entityDecl, schema *spec.Schema, seen map[string]string) (hasAllOf bool, err error) { + o := ftpe.Obj() + var afld *ast.Field + + for _, an := range flist { + if len(an.Names) != 0 { + continue + } + + tpp := decl.Pkg.TypesInfo.Types[an.Type] + if tpp.Type.String() != o.Type().String() { + continue + } + + // decl. + debugLog("maybe interface field %s: %s(%T)", o.Name(), o.Type().String(), o.Type()) + afld = an + break + } + + if afld == nil { + debugLog("can't find source associated with %s", ftpe.String()) + return hasAllOf, nil + } + + // if the field is annotated with swagger:ignore, ignore it + if ignored(afld.Doc) { + return hasAllOf, nil + } + + if !allOfMember(afld.Doc) { + var newSch spec.Schema + if err = s.buildEmbedded(o.Type(), &newSch, seen); err != nil { + return hasAllOf, err + } + schema.AllOf = append(schema.AllOf, newSch) + hasAllOf = true + + return hasAllOf, nil + } + + hasAllOf = true + + var newSch spec.Schema + // when the embedded struct is annotated with swagger:allOf it will be used as allOf property + // otherwise the fields will just be included as normal properties + if err = s.buildAllOf(o.Type(), &newSch); err != nil { + return hasAllOf, err + } + + if afld.Doc != nil { + for _, cmt := range afld.Doc.List { + for _, ln := range strings.Split(cmt.Text, "\n") { + matches := rxAllOf.FindStringSubmatch(ln) + ml := len(matches) + if ml <= 1 { + continue + } + + mv := matches[ml-1] + if mv != "" { + schema.AddExtension("x-class", mv) + } + } + } + } + + schema.AllOf = append(schema.AllOf, newSch) + + return hasAllOf, nil +} + func (s *schemaBuilder) buildFromStruct(decl *entityDecl, st *types.Struct, schema *spec.Schema, seen map[string]string) error { - s.ctx.FindComments(decl.Pkg, decl.Type.Obj().Name()) - cmt, hasComments := s.ctx.FindComments(decl.Pkg, decl.Type.Obj().Name()) + s.ctx.FindComments(decl.Pkg, decl.Obj().Name()) + cmt, hasComments := s.ctx.FindComments(decl.Pkg, decl.Obj().Name()) if !hasComments { cmt = new(ast.CommentGroup) } @@ -693,15 +1074,19 @@ func (s *schemaBuilder) buildFromStruct(decl *entityDecl, st *types.Struct, sche var tgt *spec.Schema hasAllOf := false - for i := 0; i < st.NumFields(); i++ { + for i := range st.NumFields() { fld := st.Field(i) if !fld.Anonymous() { + // e.g. struct { _ struct{} } debugLog("skipping field %q for allOf scan because not anonymous", fld.Name()) continue } tg := st.Tag(i) - debugLog("maybe allof field(%t) %s: %s (%T) [%q](anon: %t, embedded: %t)", fld.IsField(), fld.Name(), fld.Type().String(), fld.Type(), tg, fld.Anonymous(), fld.Embedded()) + debugLog( + "maybe allof field(%t) %s: %s (%T) [%q](anon: %t, embedded: %t)", + fld.IsField(), fld.Name(), fld.Type().String(), fld.Type(), tg, fld.Anonymous(), fld.Embedded(), + ) var afld *ast.Field ans, _ := astutil.PathEnclosingInterval(decl.File, fld.Pos(), fld.Pos()) // debugLog("got %d nodes (exact: %t)", len(ans), isExact) @@ -734,7 +1119,9 @@ func (s *schemaBuilder) buildFromStruct(decl *entityDecl, st *types.Struct, sche continue } - if !allOfMember(afld.Doc) { + _, isAliased := fld.Type().(*types.Alias) + + if !allOfMember(afld.Doc) && !isAliased { if tgt == nil { tgt = schema } @@ -743,6 +1130,11 @@ func (s *schemaBuilder) buildFromStruct(decl *entityDecl, st *types.Struct, sche } continue } + + if isAliased { + debugLog("alias member in struct: %v", fld) + } + // if this created an allOf property then we have to rejig the schema var // because all the fields collected that aren't from embedded structs should go in // their own proper schema @@ -789,7 +1181,7 @@ func (s *schemaBuilder) buildFromStruct(decl *entityDecl, st *types.Struct, sche } tgt.Typed("object", "") - for i := 0; i < st.NumFields(); i++ { + for i := range st.NumFields() { fld := st.Field(i) tg := st.Tag(i) @@ -804,7 +1196,6 @@ func (s *schemaBuilder) buildFromStruct(decl *entityDecl, st *types.Struct, sche var afld *ast.Field ans, _ := astutil.PathEnclosingInterval(decl.File, fld.Pos(), fld.Pos()) - // debugLog("got %d nodes (exact: %t)", len(ans), isExact) for _, an := range ans { at, valid := an.(*ast.Field) if !valid { @@ -894,79 +1285,174 @@ func (s *schemaBuilder) buildFromStruct(decl *entityDecl, st *types.Struct, sche func (s *schemaBuilder) buildAllOf(tpe types.Type, schema *spec.Schema) error { debugLog("allOf %s", tpe.Underlying()) + switch ftpe := tpe.(type) { case *types.Pointer: return s.buildAllOf(ftpe.Elem(), schema) case *types.Named: - switch utpe := ftpe.Underlying().(type) { - case *types.Struct: - decl, found := s.ctx.FindModel(ftpe.Obj().Pkg().Path(), ftpe.Obj().Name()) - if found { - if ftpe.Obj().Pkg().Path() == "time" && ftpe.Obj().Name() == "Time" { - schema.Typed("string", "date-time") - return nil - } - if sfnm, isf := strfmtName(decl.Comments); isf { - schema.Typed("string", sfnm) - return nil - } - if decl.HasModelAnnotation() { - return s.makeRef(decl, schemaTypable{schema, 0}) - } - return s.buildFromStruct(decl, utpe, schema, make(map[string]string)) - } + return s.buildNamedAllOf(ftpe, schema) + case *types.Alias: + debugLog("allOf member is alias %v => %v", ftpe, ftpe.Rhs()) + tgt := schemaTypable{schema: schema} + return s.buildAlias(ftpe, tgt) + case *types.TypeParam: + log.Printf("WARNING: generic type parameters are not supported yet %[1]v (%[1]T). Skipped", ftpe) + return nil + case *types.Chan: + log.Printf("WARNING: channels are not supported %[1]v (%[1]T). Skipped", ftpe) + return nil + case *types.Signature: + log.Printf("WARNING: functions are not supported %[1]v (%[1]T). Skipped", ftpe) + return nil + default: + log.Printf("WARNING: missing allOf parser for a %T, skipping field", ftpe) + return fmt.Errorf("unable to resolve allOf member for: %v", ftpe) + } +} + +func (s *schemaBuilder) buildNamedAllOf(ftpe *types.Named, schema *spec.Schema) error { + switch utpe := ftpe.Underlying().(type) { + case *types.Struct: + decl, found := s.ctx.FindModel(ftpe.Obj().Pkg().Path(), ftpe.Obj().Name()) + if !found { return fmt.Errorf("can't find source file for struct: %s", ftpe.String()) - case *types.Interface: - decl, found := s.ctx.FindModel(ftpe.Obj().Pkg().Path(), ftpe.Obj().Name()) - if found { - if sfnm, isf := strfmtName(decl.Comments); isf { - schema.Typed("string", sfnm) - return nil - } - if decl.HasModelAnnotation() { - return s.makeRef(decl, schemaTypable{schema, 0}) - } - return s.buildFromInterface(decl, utpe, schema, make(map[string]string)) - } + } + + if isStdTime(ftpe.Obj()) { + schema.Typed("string", "date-time") + return nil + } + + if sfnm, isf := strfmtName(decl.Comments); isf { + schema.Typed("string", sfnm) + return nil + } + + if decl.HasModelAnnotation() { + return s.makeRef(decl, schemaTypable{schema, 0}) + } + + return s.buildFromStruct(decl, utpe, schema, make(map[string]string)) + case *types.Interface: + decl, found := s.ctx.FindModel(ftpe.Obj().Pkg().Path(), ftpe.Obj().Name()) + if !found { return fmt.Errorf("can't find source file for interface: %s", ftpe.String()) - default: - log.Printf("WARNING: can't figure out object type for allOf named type (%T): %v", ftpe, ftpe.Underlying()) - return fmt.Errorf("unable to locate source file for allOf %s", utpe.String()) } + + if sfnm, isf := strfmtName(decl.Comments); isf { + schema.Typed("string", sfnm) + return nil + } + + if decl.HasModelAnnotation() { + return s.makeRef(decl, schemaTypable{schema, 0}) + } + + return s.buildFromInterface(decl, utpe, schema, make(map[string]string)) + case *types.TypeParam: + log.Printf("WARNING: generic type parameters are not supported yet %[1]v (%[1]T). Skipped", ftpe) + return nil + case *types.Chan: + log.Printf("WARNING: channels are not supported %[1]v (%[1]T). Skipped", ftpe) + return nil + case *types.Signature: + log.Printf("WARNING: functions are not supported %[1]v (%[1]T). Skipped", ftpe) + return nil default: - log.Printf("WARNING: Missing allOf parser for a %T, skipping field", ftpe) - return fmt.Errorf("unable to resolve allOf member for: %v", ftpe) + log.Printf( + "WARNING: can't figure out object type for allOf named type (%T): %v", + ftpe, utpe, + ) + return fmt.Errorf("unable to locate source file for allOf (%T): %v", + ftpe, utpe, + ) } } func (s *schemaBuilder) buildEmbedded(tpe types.Type, schema *spec.Schema, seen map[string]string) error { - debugLog("embedded %s", tpe.Underlying()) + debugLog("embedded %v", tpe.Underlying()) + switch ftpe := tpe.(type) { case *types.Pointer: return s.buildEmbedded(ftpe.Elem(), schema, seen) case *types.Named: - debugLog("embedded named type: %T", ftpe.Underlying()) - switch utpe := ftpe.Underlying().(type) { - case *types.Struct: - decl, found := s.ctx.FindModel(ftpe.Obj().Pkg().Path(), ftpe.Obj().Name()) - if found { - return s.buildFromStruct(decl, utpe, schema, seen) - } + return s.buildNamedEmbedded(ftpe, schema, seen) + case *types.Alias: + debugLog("embedded alias %v => %v", ftpe, ftpe.Rhs()) + tgt := schemaTypable{schema, 0} + return s.buildAlias(ftpe, tgt) + case *types.Union: // e.g. type X interface{ ~uint16 | ~float32 } + log.Printf("WARNING: union type constraints are not supported yet %[1]v (%[1]T). Skipped", ftpe) + return nil + case *types.TypeParam: + log.Printf("WARNING: generic type parameters are not supported yet %[1]v (%[1]T). Skipped", ftpe) + return nil + case *types.Chan: + log.Printf("WARNING: channels are not supported %[1]v (%[1]T). Skipped", ftpe) + return nil + case *types.Signature: + log.Printf("WARNING: functions are not supported %[1]v (%[1]T). Skipped", ftpe) + return nil + default: + log.Printf("WARNING: Missing embedded parser for a %T, skipping model\n", ftpe) + return nil + } +} + +func (s *schemaBuilder) buildNamedEmbedded(ftpe *types.Named, schema *spec.Schema, seen map[string]string) error { + debugLog("embedded named type: %T", ftpe.Underlying()) + if unsupportedBuiltin(ftpe) { + log.Printf("WARNING: skipped unsupported builtin type: %v", ftpe) + + return nil + } + + switch utpe := ftpe.Underlying().(type) { + case *types.Struct: + decl, found := s.ctx.FindModel(ftpe.Obj().Pkg().Path(), ftpe.Obj().Name()) + if !found { return fmt.Errorf("can't find source file for struct: %s", ftpe.String()) - case *types.Interface: - decl, found := s.ctx.FindModel(ftpe.Obj().Pkg().Path(), ftpe.Obj().Name()) - if found { - return s.buildFromInterface(decl, utpe, schema, seen) - } + } + + return s.buildFromStruct(decl, utpe, schema, seen) + case *types.Interface: + if utpe.Empty() { + return nil + } + o := ftpe.Obj() + if isAny(o) { + return nil + } + if isStdError(o) { + tgt := schemaTypable{schema: schema} + tgt.AddExtension("x-go-type", o.Name()) + return swaggerSchemaForType(o.Name(), tgt) + } + mustNotBeABuiltinType(o) + + decl, found := s.ctx.FindModel(o.Pkg().Path(), o.Name()) + if !found { return fmt.Errorf("can't find source file for struct: %s", ftpe.String()) - default: - log.Printf("WARNING: can't figure out object type for embedded named type (%T): %v", ftpe, ftpe.Underlying()) } + return s.buildFromInterface(decl, utpe, schema, seen) + case *types.Union: // e.g. type X interface{ ~uint16 | ~float32 } + log.Printf("WARNING: union type constraints are not supported yet %[1]v (%[1]T). Skipped", utpe) + return nil + case *types.TypeParam: + log.Printf("WARNING: generic type parameters are not supported yet %[1]v (%[1]T). Skipped", utpe) + return nil + case *types.Chan: + log.Printf("WARNING: channels are not supported %[1]v (%[1]T). Skipped", utpe) + return nil + case *types.Signature: + log.Printf("WARNING: functions are not supported %[1]v (%[1]T). Skipped", utpe) + return nil default: - log.Printf("WARNING: Missing embedded parser for a %T, skipping model\n", ftpe) + log.Printf("WARNING: can't figure out object type for embedded named type (%T): %v", + ftpe, utpe, + ) return nil } - return nil } func (s *schemaBuilder) makeRef(decl *entityDecl, prop swaggerTypable) error { @@ -991,7 +1477,7 @@ func (s *schemaBuilder) createParser(nm string, schema, ps *spec.Schema, fld *as if ps.Ref.String() == "" { sp.setDescription = func(lines []string) { ps.Description = joinDropLast(lines) - enumDesc := getEnumDesc(ps.VendorExtensible.Extensions) + enumDesc := getEnumDesc(ps.Extensions) if enumDesc != "" { ps.Description += "\n" + enumDesc } @@ -1070,7 +1556,7 @@ func (s *schemaBuilder) createParser(nm string, schema, ps *spec.Schema, fld *as } return otherTaggers, nil default: - return nil, fmt.Errorf("unknown field type ele for %q", nm) + return nil, fmt.Errorf("unknown field type element for %q", nm) } } // check if this is a primitive, if so parse the validations from the @@ -1178,3 +1664,29 @@ func isFieldStringable(tpe ast.Expr) bool { } return false } + +func isTextMarshaler(tpe types.Type) bool { + encodingPkg, err := importer.Default().Import("encoding") + if err != nil { + return false + } + ifc := encodingPkg.Scope().Lookup("TextMarshaler").Type().Underlying().(*types.Interface) // TODO: there is a better way to check this + + return types.Implements(tpe, ifc) +} + +func isStdTime(o *types.TypeName) bool { + return o.Pkg() != nil && o.Pkg().Name() == "time" && o.Name() == "Time" +} + +func isStdError(o *types.TypeName) bool { + return o.Pkg() == nil && o.Name() == "error" +} + +func isStdJSONRawMessage(o *types.TypeName) bool { + return o.Pkg() != nil && o.Pkg().Path() == "encoding/json" && o.Name() == "RawMessage" +} + +func isAny(o *types.TypeName) bool { + return o.Pkg() == nil && o.Name() == "any" +} diff --git a/vendor/github.com/go-swagger/go-swagger/codescan/spec.go b/vendor/github.com/go-swagger/go-swagger/codescan/spec.go index 20c4e1022..148360a3f 100644 --- a/vendor/github.com/go-swagger/go-swagger/codescan/spec.go +++ b/vendor/github.com/go-swagger/go-swagger/codescan/spec.go @@ -46,6 +46,8 @@ type specBuilder struct { } func (s *specBuilder) Build() (*spec.Swagger, error) { + // this initial scan step is skipped if !scanModels. + // Discovered dependencies should however be resolved. if err := s.buildModels(); err != nil { return nil, err } diff --git a/vendor/github.com/go-swagger/go-swagger/generator/debug.go b/vendor/github.com/go-swagger/go-swagger/generator/debug.go index 61b4b8d48..ceb64c724 100644 --- a/vendor/github.com/go-swagger/go-swagger/generator/debug.go +++ b/vendor/github.com/go-swagger/go-swagger/generator/debug.go @@ -36,7 +36,7 @@ func debugOptions() { } // debugLog wraps log.Printf with a debug-specific logger -func debugLog(frmt string, args ...interface{}) { +func debugLog(frmt string, args ...any) { if Debug { _, file, pos, _ := runtime.Caller(1) generatorLogger.Printf("%s:%d: %s", filepath.Base(file), pos, @@ -45,11 +45,11 @@ func debugLog(frmt string, args ...interface{}) { } // debugLogAsJSON unmarshals its last arg as pretty JSON -func debugLogAsJSON(frmt string, args ...interface{}) { +func debugLogAsJSON(frmt string, args ...any) { if Debug { var dfrmt string _, file, pos, _ := runtime.Caller(1) - dargs := make([]interface{}, 0, len(args)+2) + dargs := make([]any, 0, len(args)+2) dargs = append(dargs, filepath.Base(file), pos) if len(args) > 0 { dfrmt = "%s:%d: " + frmt + "\n%s" diff --git a/vendor/github.com/go-swagger/go-swagger/generator/doc.go b/vendor/github.com/go-swagger/go-swagger/generator/doc.go index 49cbf3950..bd4639a00 100644 --- a/vendor/github.com/go-swagger/go-swagger/generator/doc.go +++ b/vendor/github.com/go-swagger/go-swagger/generator/doc.go @@ -17,7 +17,7 @@ Package generator provides the code generation library for go-swagger. # Generating data types -The general idea is that you should rarely see interface{} in the generated code. +The general idea is that you should rarely see any in the generated code. You get a complete representation of a swagger document in somewhat idiomatic go. To do so, there is a set of mapping patterns that are applied, diff --git a/vendor/github.com/go-swagger/go-swagger/generator/language.go b/vendor/github.com/go-swagger/go-swagger/generator/language.go index 68e911663..bd49f9746 100644 --- a/vendor/github.com/go-swagger/go-swagger/generator/language.go +++ b/vendor/github.com/go-swagger/go-swagger/generator/language.go @@ -13,8 +13,9 @@ import ( "sort" "strings" - "github.com/go-openapi/swag" "golang.org/x/tools/imports" + + "github.com/go-openapi/swag" ) var ( @@ -30,15 +31,50 @@ func initLanguage() { moduleRe = regexp.MustCompile(`module[ \t]+([^\s]+)`) } +// FormatOption allows for more flexible code formatting settings +type FormatOption func(*formatOptions) + +type formatOptions struct { + imports.Options + localPrefixes []string +} + +// WithFormatLocalPrefixes adds local prefixes to group imports +func WithFormatLocalPrefixes(prefixes ...string) FormatOption { + return func(o *formatOptions) { + o.localPrefixes = append(o.localPrefixes, prefixes...) + } +} + +var defaultFormatOptions = formatOptions{ + Options: imports.Options{ + TabIndent: true, + TabWidth: 2, + Fragment: true, + Comments: true, + }, + localPrefixes: []string{"github.com/go-openapi"}, +} + +func formatOptionsWithDefault(opts []FormatOption) formatOptions { + o := defaultFormatOptions + + for _, apply := range opts { + apply(&o) + } + + return o +} + // LanguageOpts to describe a language to the code generator type LanguageOpts struct { ReservedWords []string - BaseImportFunc func(string) string `json:"-"` - ImportsFunc func(map[string]string) string `json:"-"` - ArrayInitializerFunc func(interface{}) (string, error) `json:"-"` + BaseImportFunc func(string) string `json:"-"` + ImportsFunc func(map[string]string) string `json:"-"` + ArrayInitializerFunc func(any) (string, error) `json:"-"` reservedWordsSet map[string]struct{} initialized bool - formatFunc func(string, []byte) ([]byte, error) + formatFunc func(string, []byte, ...FormatOption) ([]byte, error) fileNameFunc func(string) string // language specific source file naming rules dirNameFunc func(string) string // language specific directory naming rules } @@ -107,10 +143,12 @@ func (l *LanguageOpts) ManglePackagePath(name string, suffix string) string { } // FormatContent formats a file with a language specific formatter -func (l *LanguageOpts) FormatContent(name string, content []byte) ([]byte, error) { +func (l *LanguageOpts) FormatContent(name string, content []byte, opts ...FormatOption) ([]byte, error) { if l.formatFunc != nil { - return l.formatFunc(name, content) + return l.formatFunc(name, content, opts...) } + + // unformatted content return content, nil } @@ -123,7 +161,7 @@ func (l *LanguageOpts) imports(imports map[string]string) string { } // arrayInitializer builds a litteral array -func (l *LanguageOpts) arrayInitializer(data interface{}) (string, error) { +func (l *LanguageOpts) arrayInitializer(data any) (string, error) { if l.ArrayInitializerFunc != nil { return l.ArrayInitializerFunc(data) } @@ -204,13 +242,10 @@ func GoLangOpts() *LanguageOpts { "continue", "for", "import", "return", "var", } - opts.formatFunc = func(ffn string, content []byte) ([]byte, error) { - opts := new(imports.Options) - opts.TabIndent = true - opts.TabWidth = 2 - opts.Fragment = true - opts.Comments = true - return imports.Process(ffn, content, opts) + opts.formatFunc = func(ffn string, content []byte, opts ...FormatOption) ([]byte, error) { + o := formatOptionsWithDefault(opts) + imports.LocalPrefix = strings.Join(o.localPrefixes, ",") // regroup these packages + return imports.Process(ffn, content, &o.Options) } opts.fileNameFunc = func(name string) string { @@ -253,10 +288,10 @@ func GoLangOpts() *LanguageOpts { return strings.Join(result, "\n") } - opts.ArrayInitializerFunc = func(data interface{}) (string, error) { - // ArrayInitializer constructs a Go literal initializer from interface{} literals. - // e.g. []interface{}{"a", "b"} is transformed in {"a","b",} - // e.g. map[string]interface{}{ "a": "x", "b": "y"} is transformed in {"a":"x","b":"y",}. + opts.ArrayInitializerFunc = func(data any) (string, error) { + // ArrayInitializer constructs a Go literal initializer from any literals. + // e.g. []any{"a", "b"} is transformed in {"a","b",} + // e.g. map[string]any{ "a": "x", "b": "y"} is transformed in {"a":"x","b":"y",}. // // NOTE: this is currently used to construct simple slice intializers for default values. // This allows for nicer slice initializers for slices of primitive types and avoid systematic use for json.Unmarshal(). diff --git a/vendor/github.com/go-swagger/go-swagger/generator/media.go b/vendor/github.com/go-swagger/go-swagger/generator/media.go index 239926dc8..c3c57eb06 100644 --- a/vendor/github.com/go-swagger/go-swagger/generator/media.go +++ b/vendor/github.com/go-swagger/go-swagger/generator/media.go @@ -44,6 +44,7 @@ var knownProducers = map[string]string{ "xml": "runtime.XMLProducer()", "txt": "runtime.TextProducer()", "bin": "runtime.ByteStreamProducer()", + "csv": "runtime.CSVProducer()", "urlform": "runtime.DiscardProducer", "multipartform": "runtime.DiscardProducer", } @@ -54,6 +55,7 @@ var knownConsumers = map[string]string{ "xml": "runtime.XMLConsumer()", "txt": "runtime.TextConsumer()", "bin": "runtime.ByteStreamConsumer()", + "csv": "runtime.CSVConsumer()", "urlform": "runtime.DiscardConsumer", "multipartform": "runtime.DiscardConsumer", } diff --git a/vendor/github.com/go-swagger/go-swagger/generator/model.go b/vendor/github.com/go-swagger/go-swagger/generator/model.go index ca5b87a09..b9c7c93a6 100644 --- a/vendor/github.com/go-swagger/go-swagger/generator/model.go +++ b/vendor/github.com/go-swagger/go-swagger/generator/model.go @@ -153,12 +153,12 @@ func makeGenDefinition(name, pkg string, schema spec.Schema, specDoc *loads.Docu // this means that the immediate content of the top level definitions has at least one validation. // // If none is found at this level and that no special case where no Validate() method is exposed at all - // (e.g. io.ReadCloser and interface{} types and their aliases), then there is an empty Validate() method which + // (e.g. io.ReadCloser and any types and their aliases), then there is an empty Validate() method which // just return nil (the object abides by the runtime.Validatable interface, but knows it has nothing to validate). // // We do this at the top level because of the possibility of aliased types which always bubble up validation to types which // are referring to them. This results in correct but inelegant code with empty validations. - gd.GenSchema.HasValidations = shallowValidationLookup(gd.GenSchema) + gd.HasValidations = shallowValidationLookup(gd.GenSchema) } return gd, err } @@ -196,7 +196,7 @@ func shallowValidationLookup(sch GenSchema) bool { for _, p := range sch.Properties { // Using a base type within another structure triggers validation of the base type. // The discriminator property in the base type definition itself does not. - if (p.HasValidations || p.Required) && !(sch.IsBaseType && p.Name == sch.DiscriminatorField) || (p.IsAliased || p.IsComplexObject) && !(p.IsInterface || p.IsStream) { + if (p.HasValidations || p.Required) && (!sch.IsBaseType || p.Name != sch.DiscriminatorField) || (p.IsAliased || p.IsComplexObject) && !p.IsInterface && !p.IsStream { return true } } @@ -207,7 +207,7 @@ func shallowValidationLookup(sch GenSchema) bool { return false } - if sch.HasAdditionalProperties && sch.AdditionalProperties != nil && (sch.AdditionalProperties.HasValidations || sch.AdditionalProperties.Required || sch.AdditionalProperties.IsAliased && !(sch.AdditionalProperties.IsInterface || sch.AdditionalProperties.IsStream)) { + if sch.HasAdditionalProperties && sch.AdditionalProperties != nil && (sch.AdditionalProperties.HasValidations || sch.AdditionalProperties.Required || sch.AdditionalProperties.IsAliased && !sch.AdditionalProperties.IsInterface && !sch.AdditionalProperties.IsStream) { return true } @@ -318,8 +318,8 @@ func makeGenDefinitionHierarchy(name, pkg, container string, schema spec.Schema, if err != nil { return nil, err } - gs.GenSchema.IsBaseType = true - gs.GenSchema.IsExported = true + gs.IsBaseType = true + gs.IsExported = true pg.GenSchema.AllOf[i] = gs.GenSchema schPtr := &(pg.GenSchema.AllOf[i]) if schPtr.AdditionalItems != nil { @@ -367,6 +367,7 @@ func makeGenDefinitionHierarchy(name, pkg, container string, schema spec.Schema, TargetImportPath: opts.LanguageOpts.baseImport(opts.Target), }, Package: modelPkg, + CliPackage: opts.CliPackage, GenSchema: pg.GenSchema, DependsOn: pg.Dependencies, DefaultImports: defaultImports, @@ -802,7 +803,7 @@ func (sg *schemaGenContext) buildProperties() error { return err } - // whatever the validations says, if we have an interface{}, do not validate + // whatever the validations says, if we have an any, do not validate // NOTE: this may be the case when the type is left empty and we get a Enum validation. if emprop.GenSchema.IsInterface || emprop.GenSchema.IsStream { emprop.GenSchema.HasValidations = false @@ -829,7 +830,7 @@ func (sg *schemaGenContext) buildProperties() error { if rsch == nil { return errors.New("spec.ResolveRef returned nil schema") } - if rsch != nil && rsch.Ref.String() != "" { + if rsch.Ref.String() != "" { ref = rsch.Ref continue } @@ -868,7 +869,7 @@ func (sg *schemaGenContext) buildProperties() error { // a base type property is always validated against the base type // exception: for the base type definition itself (see shallowValidationLookup()) - if (hv || emprop.GenSchema.IsBaseType) && !(emprop.GenSchema.IsInterface || emprop.GenSchema.IsStream) { + if (hv || emprop.GenSchema.IsBaseType) && !emprop.GenSchema.IsInterface && !emprop.GenSchema.IsStream { emprop.GenSchema.HasValidations = true } if ttpe.HasAdditionalItems && sch.AdditionalItems.Schema != nil { @@ -962,7 +963,7 @@ func (sg *schemaGenContext) buildAllOf() error { if (tpe.IsAnonymous && len(sch.AllOf) > 0) || (sch.Ref.String() == "" && !tpe.IsComplexObject && (tpe.IsArray || tpe.IsInterface || tpe.IsPrimitive)) { // cases where anonymous structures cause the creation of a new type: // - nested allOf: this one is itself a AllOf: build a new type for it - // - anonymous simple types for edge cases: array, primitive, interface{} + // - anonymous simple types for edge cases: array, primitive, any // NOTE: when branches are aliased or anonymous, the nullable property in the branch type is lost. name := swag.ToVarName(goName(&sch, sg.makeRefName()+"AllOf"+strconv.Itoa(i))) debugLog("building anonymous nested allOf in %s: %s", sg.Name, name) @@ -1012,7 +1013,7 @@ func (sg *schemaGenContext) buildAllOf() error { } // lift validations when complex or ref'ed - if (comprop.GenSchema.IsComplexObject || comprop.Schema.Ref.String() != "") && !(comprop.GenSchema.IsInterface || comprop.GenSchema.IsStream) { + if (comprop.GenSchema.IsComplexObject || comprop.Schema.Ref.String() != "") && !comprop.GenSchema.IsInterface && !comprop.GenSchema.IsStream { comprop.GenSchema.HasValidations = true } sg.MergeResult(comprop, true) @@ -1132,7 +1133,7 @@ func (mt *mapStack) Build() error { mt.Context.GenSchema.AdditionalProperties = &cp.GenSchema // lift validations - if (csch.Ref.String() != "" || cp.GenSchema.IsAliased) && !(cp.GenSchema.IsInterface || cp.GenSchema.IsStream) { + if (csch.Ref.String() != "" || cp.GenSchema.IsAliased) && !cp.GenSchema.IsInterface && !cp.GenSchema.IsStream { // - we stopped on a ref, or anything else that require we call its Validate() method // - if the alias / ref is on an interface (or stream) type: no validation mt.Context.GenSchema.HasValidations = true @@ -1191,7 +1192,7 @@ func (mt *mapStack) Build() error { // lift validations c := &cur.Next.Context.GenSchema - if (cur.Next.Context.Schema.Ref.String() != "" || c.IsAliased) && !(c.IsInterface || c.IsStream) { + if (cur.Next.Context.Schema.Ref.String() != "" || c.IsAliased) && !c.IsInterface && !c.IsStream { // - we stopped on a ref, or anything else that require we call its Validate() // - if the alias / ref is on an interface (or stream) type: no validation cur.Context.GenSchema.HasValidations = true @@ -1218,8 +1219,8 @@ func (mt *mapStack) HasMore() bool { } /* currently unused: -func (mt *mapStack) Dict() map[string]interface{} { - res := make(map[string]interface{}) +func (mt *mapStack) Dict() map[string]any { + res := make(map[string]any) res["context"] = mt.Context.Schema if mt.Next != nil { res["next"] = mt.Next.Dict() @@ -1262,7 +1263,7 @@ func (sg *schemaGenContext) buildAdditionalProperties() error { if addp.Schema == nil { // this is for AdditionalProperties:true|false if addp.Allows { - // additionalProperties: true is rendered as: map[string]interface{} + // additionalProperties: true is rendered as: map[string]any addp.Schema = &spec.Schema{} addp.Schema.Typed("object", "") @@ -1281,7 +1282,7 @@ func (sg *schemaGenContext) buildAdditionalProperties() error { } sg.MergeResult(cp, false) sg.GenSchema.AdditionalProperties = &cp.GenSchema - debugLog("added interface{} schema for additionalProperties[allows == true], IsInterface=%t", cp.GenSchema.IsInterface) + debugLog("added any schema for additionalProperties[allows == true], IsInterface=%t", cp.GenSchema.IsInterface) } return nil } @@ -1348,6 +1349,9 @@ func (sg *schemaGenContext) buildAdditionalProperties() error { // rewrite value expression for arrays and arrays of arrays in maps (rendered as map[string][][]...) if sg.GenSchema.AdditionalProperties.IsArray { // maps of slices are where an override may take effect + if sg.GenSchema.AdditionalProperties.Items == nil { + return fmt.Errorf("items schema not defined for additional property in %q", sg.Name) + } sg.GenSchema.AdditionalProperties.Items.IsMapNullOverride = sg.GenSchema.AdditionalProperties.IsMapNullOverride sg.GenSchema.AdditionalProperties.Items.ValueExpression = sg.GenSchema.ValueExpression + "[" + comprop.KeyVar + "]" + "[" + sg.GenSchema.AdditionalProperties.IndexVar + "]" ap := sg.GenSchema.AdditionalProperties.Items @@ -1359,7 +1363,7 @@ func (sg *schemaGenContext) buildAdditionalProperties() error { } // lift validation - if (sg.GenSchema.AdditionalProperties.IsComplexObject || sg.GenSchema.AdditionalProperties.IsAliased || sg.GenSchema.AdditionalProperties.Required) && !(sg.GenSchema.AdditionalProperties.IsInterface || sg.GenSchema.IsStream) { + if (sg.GenSchema.AdditionalProperties.IsComplexObject || sg.GenSchema.AdditionalProperties.IsAliased || sg.GenSchema.AdditionalProperties.Required) && !sg.GenSchema.AdditionalProperties.IsInterface && !sg.GenSchema.IsStream { sg.GenSchema.HasValidations = true } return nil @@ -1508,7 +1512,7 @@ func (sg *schemaGenContext) buildArray() error { schemaCopy.HasValidations = true } - if (elProp.Schema.Ref.String() != "" || elProp.GenSchema.IsAliased) && !(elProp.GenSchema.IsInterface || elProp.GenSchema.IsStream) { + if (elProp.Schema.Ref.String() != "" || elProp.GenSchema.IsAliased) && !elProp.GenSchema.IsInterface && !elProp.GenSchema.IsStream { schemaCopy.HasValidations = true } @@ -1649,7 +1653,7 @@ func (sg *schemaGenContext) buildAdditionalItems() error { } // lift validations when complex is not anonymous or ref'ed - if (tpe.IsComplexObject || it.Schema.Ref.String() != "") && !(tpe.IsInterface || tpe.IsStream) { + if (tpe.IsComplexObject || it.Schema.Ref.String() != "") && !tpe.IsInterface && !tpe.IsStream { it.GenSchema.HasValidations = true } @@ -1742,7 +1746,7 @@ func (sg *schemaGenContext) shortCircuitNamedRef() (bool, error) { sg.MergeResult(pg, true) sg.GenSchema = pg.GenSchema sg.GenSchema.resolvedType = tpe - sg.GenSchema.resolvedType.IsSuperAlias = true + sg.GenSchema.IsSuperAlias = true sg.GenSchema.IsBaseType = tpe.IsBaseType return true, nil @@ -2063,7 +2067,7 @@ func (sg *schemaGenContext) makeGenSchema() error { sg.GenSchema.resolvedType = tpe sg.GenSchema.Required = sg.Required // assume we validate everything but interface and io.Reader - validation may be disabled by using the noValidation hint - sg.GenSchema.HasValidations = !(tpe.IsInterface || tpe.IsStream || tpe.SkipExternalValidation) + sg.GenSchema.HasValidations = !tpe.IsInterface && !tpe.IsStream && !tpe.SkipExternalValidation sg.GenSchema.IsAliased = sg.GenSchema.HasValidations log.Printf("INFO: type %s is external, with inferred spec type %s, referred to as %s", sg.GenSchema.Name, sg.GenSchema.GoType, extType) @@ -2145,10 +2149,10 @@ func (sg *schemaGenContext) makeGenSchema() error { // - aliased primitive of a formatter type which is not a stringer // // but not for: - // - interface{} + // - any // - io.Reader gs := sg.GenSchema - sg.GenSchema.WantsMarshalBinary = !(gs.IsInterface || gs.IsStream || gs.IsBaseType) && + sg.GenSchema.WantsMarshalBinary = !gs.IsInterface && !gs.IsStream && !gs.IsBaseType && (gs.IsTuple || gs.IsComplexObject || gs.IsAdditionalProperties || (gs.IsPrimitive && gs.IsAliased && gs.IsCustomFormatter && !strings.Contains(gs.Zero(), `("`))) debugLog("finished gen schema for %q", sg.Name) diff --git a/vendor/github.com/go-swagger/go-swagger/generator/operation.go b/vendor/github.com/go-swagger/go-swagger/generator/operation.go index a2098c375..a8ad73f6c 100644 --- a/vendor/github.com/go-swagger/go-swagger/generator/operation.go +++ b/vendor/github.com/go-swagger/go-swagger/generator/operation.go @@ -251,7 +251,7 @@ func paramMappings(params map[string]spec.Parameter) (map[string]map[string]stri // In order to avoid unstable generation, adopt same naming convention // for all parameters with same name across locations. - seenIDs := make(map[string]interface{}, len(params)) + seenIDs := make(map[string]any, len(params)) for id, p := range params { debugLog("paramMappings: params: id=%s, In=%q, Name=%q", id, p.In, p.Name) // guard against possible validation failures and/or skipped issues @@ -286,7 +286,7 @@ func paramMappings(params map[string]spec.Parameter) (map[string]map[string]stri // // NOTE: this merely protects the timeout field in the client parameter struct, // fields "Context" and "HTTPClient" remain exposed to name conflicts. -func renameTimeout(seenIDs map[string]interface{}, timeoutName string) string { +func renameTimeout(seenIDs map[string]any, timeoutName string) string { if seenIDs == nil { return timeoutName } @@ -520,6 +520,7 @@ func (b *codeGenOpBuilder) MakeOperation() (GenOperation, error) { PrincipalIsNullable: b.GenOpts.PrincipalIsNullable(), ExternalDocs: trimExternalDoc(operation.ExternalDocs), + ReturnErrors: b.GenOpts.ReturnErrors, }, nil } @@ -566,6 +567,7 @@ func (b *codeGenOpBuilder) MakeResponse(receiver, name string, isSuccess bool, r StrictResponders: b.GenOpts.StrictResponders, OperationName: b.Name, Examples: examples, + ReturnErrors: b.GenOpts.ReturnErrors, } // prepare response headers @@ -778,7 +780,7 @@ func (b *codeGenOpBuilder) MakeParameter(receiver string, resolver *typeResolver SchemaValidations: param.Validations(), } - res.ZeroValue = res.resolvedType.Zero() + res.ZeroValue = res.Zero() hasChildValidations := false if param.Items != nil { @@ -964,7 +966,7 @@ func (b *codeGenOpBuilder) setBodyParamValidation(p *GenParameter) { // composition of primitive fields must be properly identified: hack this through _, isPrimitive := primitives[s.GoType] _, isFormatter := customFormatters[s.GoType] - isComposedPrimitive := s.IsPrimitive && !(isPrimitive || isFormatter) + isComposedPrimitive := s.IsPrimitive && !isPrimitive && !isFormatter hasSimpleBodyParams = !s.IsComplexObject && !s.IsAliased && !isComposedPrimitive && !doNot hasModelBodyParams = (s.IsComplexObject || s.IsAliased || isComposedPrimitive) && !doNot @@ -972,12 +974,12 @@ func (b *codeGenOpBuilder) setBodyParamValidation(p *GenParameter) { if s.IsArray && s.Items != nil { it := s.Items doNot = it.IsInterface || it.IsStream || it.IsBase64 - hasSimpleBodyItems = !it.IsComplexObject && !(it.IsAliased || doNot) + hasSimpleBodyItems = !it.IsComplexObject && !it.IsAliased && !doNot hasModelBodyItems = (it.IsComplexObject || it.IsAliased) && !doNot } if s.IsMap && s.AdditionalProperties != nil { it := s.AdditionalProperties - hasSimpleBodyMap = !it.IsComplexObject && !(it.IsAliased || doNot) + hasSimpleBodyMap = !it.IsComplexObject && !it.IsAliased && !doNot hasModelBodyMap = !hasSimpleBodyMap && !doNot } } diff --git a/vendor/github.com/go-swagger/go-swagger/generator/shared.go b/vendor/github.com/go-swagger/go-swagger/generator/shared.go index 75ed251fe..abbc466d9 100644 --- a/vendor/github.com/go-swagger/go-swagger/generator/shared.go +++ b/vendor/github.com/go-swagger/go-swagger/generator/shared.go @@ -24,6 +24,7 @@ import ( "path" "path/filepath" "reflect" + "regexp" "sort" "strings" "text/template" @@ -351,6 +352,7 @@ type GenOptsCommon struct { StrictResponders bool AcceptDefinitionsOnly bool WantsRootedErrorPath bool + ReturnErrors bool templates *Repository // a shallow clone of the global template repository } @@ -503,7 +505,7 @@ func (g *GenOpts) EnsureDefaults() error { return nil } -func (g *GenOpts) location(t *TemplateOpts, data interface{}) (string, string, error) { +func (g *GenOpts) location(t *TemplateOpts, data any) (string, string, error) { v := reflect.Indirect(reflect.ValueOf(data)) fld := v.FieldByName("Name") var name string @@ -549,7 +551,7 @@ func (g *GenOpts) location(t *TemplateOpts, data interface{}) (string, string, e Name, CliAppName, Package, APIPackage, ServerPackage, ClientPackage, CliPackage, ModelPackage, MainPackage, Target string Tags []string UseTags bool - Context interface{} + Context any }{ Name: name, CliAppName: g.CliAppName, @@ -578,7 +580,7 @@ func (g *GenOpts) location(t *TemplateOpts, data interface{}) (string, string, e return pthBuf.String(), fileName(fNameBuf.String()), nil } -func (g *GenOpts) render(t *TemplateOpts, data interface{}) ([]byte, error) { +func (g *GenOpts) render(t *TemplateOpts, data any) ([]byte, error) { var templ *template.Template if strings.HasPrefix(strings.ToLower(t.Source), "asset:") { @@ -635,7 +637,7 @@ func (g *GenOpts) render(t *TemplateOpts, data interface{}) ([]byte, error) { // generated code is reformatted ("linted"), which gives an // additional level of checking. If this step fails, the generated // code is still dumped, for template debugging purposes. -func (g *GenOpts) write(t *TemplateOpts, data interface{}) error { +func (g *GenOpts) write(t *TemplateOpts, data any) error { dir, fname, err := g.location(t, data) if err != nil { return fmt.Errorf("failed to resolve template location for template %s: %w", t.Name, err) @@ -670,7 +672,8 @@ func (g *GenOpts) write(t *TemplateOpts, data interface{}) error { var writeerr error if !t.SkipFormat { - formatted, err = g.LanguageOpts.FormatContent(filepath.Join(dir, fname), content) + baseImport := g.LanguageOpts.baseImport(g.Target) + formatted, err = g.LanguageOpts.FormatContent(filepath.Join(dir, fname), content, WithFormatLocalPrefixes(baseImport)) if err != nil { log.Printf("source formatting failed on template-generated source (%q for %s). Check that your template produces valid code", filepath.Join(dir, fname), t.Name) writeerr = os.WriteFile(filepath.Join(dir, fname), content, 0o644) // #nosec @@ -854,7 +857,13 @@ func (g *GenOpts) PrincipalAlias() string { return principal } +var ifaceRex = regexp.MustCompile(`^interface\s\{\s*\}$`) + func (g *GenOpts) resolvePrincipal() (string, string, string) { + if ifaceRex.MatchString(g.Principal) { + return "", "any", "" + } + dotLocation := strings.LastIndex(g.Principal, ".") if dotLocation < 0 { return "", g.Principal, "" @@ -1085,12 +1094,12 @@ func gatherURISchemes(swsp *spec.Swagger, operation spec.Operation) ([]string, [ return schemes, extraSchemes } -func dumpData(data interface{}) error { +func dumpData(data any) error { bb, err := json.MarshalIndent(data, "", " ") if err != nil { return err } - fmt.Fprintln(os.Stdout, string(bb)) // TODO(fred): not testable + _, _ = fmt.Fprintln(os.Stdout, string(bb)) // TODO(fred): not testable return nil } diff --git a/vendor/github.com/go-swagger/go-swagger/generator/spec.go b/vendor/github.com/go-swagger/go-swagger/generator/spec.go index df3528a62..a177b0c1b 100644 --- a/vendor/github.com/go-swagger/go-swagger/generator/spec.go +++ b/vendor/github.com/go-swagger/go-swagger/generator/spec.go @@ -166,7 +166,7 @@ func findSwaggerSpec(nm string) (string, error) { // WithAutoXOrder amends the spec to specify property order as they appear // in the spec (supports yaml documents only). func WithAutoXOrder(specPath string) string { - lookFor := func(ele interface{}, key string) (yamlv2.MapSlice, bool) { + lookFor := func(ele any, key string) (yamlv2.MapSlice, bool) { if slice, ok := ele.(yamlv2.MapSlice); ok { for _, v := range slice { if v.Key == key { @@ -179,8 +179,8 @@ func WithAutoXOrder(specPath string) string { return nil, false } - var addXOrder func(interface{}) - addXOrder = func(element interface{}) { + var addXOrder func(any) + addXOrder = func(element any) { if props, ok := lookFor(element, "properties"); ok { for i, prop := range props { if pSlice, ok := prop.Value.(yamlv2.MapSlice); ok { @@ -249,8 +249,8 @@ func WithAutoXOrder(specPath string) string { } // BytesToYAMLDoc converts a byte slice into a YAML document -func BytesToYAMLv2Doc(data []byte) (interface{}, error) { - var canary map[interface{}]interface{} // validate this is an object and not a different type +func BytesToYAMLv2Doc(data []byte) (any, error) { + var canary map[any]any // validate this is an object and not a different type if err := yamlv2.Unmarshal(data, &canary); err != nil { return nil, err } diff --git a/vendor/github.com/go-swagger/go-swagger/generator/structs.go b/vendor/github.com/go-swagger/go-swagger/generator/structs.go index 145228881..61b63d6e0 100644 --- a/vendor/github.com/go-swagger/go-swagger/generator/structs.go +++ b/vendor/github.com/go-swagger/go-swagger/generator/structs.go @@ -29,6 +29,7 @@ type GenDefinition struct { GenCommon GenSchema Package string + CliPackage string Imports map[string]string DefaultImports map[string]string ExtraSchemas GenSchemaList @@ -94,7 +95,7 @@ type GenSchema struct { Parents []string IncludeValidator bool IncludeModel bool - Default interface{} + Default any WantsMarshalBinary bool // do we generate MarshalBinary interface? StructTags []string ExtraImports map[string]string // non-standard imports detected when using external types @@ -236,7 +237,7 @@ type sharedValidations struct { HasContextValidations bool Required bool HasSliceValidations bool - ItemsEnum []interface{} + ItemsEnum []any // NOTE: "patternProperties" and "dependencies" not supported by Swagger 2.0 } @@ -261,11 +262,12 @@ type GenResponse struct { Imports map[string]string DefaultImports map[string]string - Extensions map[string]interface{} + Extensions map[string]any StrictResponders bool OperationName string Examples GenResponseExamples + ReturnErrors bool } // GenResponseExamples is a sortable collection []GenResponseExample @@ -278,7 +280,7 @@ func (g GenResponseExamples) Less(i, j int) bool { return g[i].MediaType < g[j]. // GenResponseExample captures an example provided for a response for some mime type type GenResponseExample struct { MediaType string - Example interface{} + Example any } // GenHeader represents a header on a response for code generation @@ -297,7 +299,7 @@ type GenHeader struct { Title string Description string - Default interface{} + Default any HasDefault bool CollectionFormat string @@ -373,7 +375,7 @@ type GenParameter struct { // Unused // BodyParam *GenParameter - Default interface{} + Default any HasDefault bool ZeroValue string AllowEmptyValue bool @@ -393,7 +395,7 @@ type GenParameter struct { HasSimpleBodyMap bool HasModelBodyMap bool - Extensions map[string]interface{} + Extensions map[string]any } // IsQueryParam returns true when this parameter is a query param @@ -636,9 +638,10 @@ type GenOperation struct { ConsumesMediaTypes []string TimeoutName string - Extensions map[string]interface{} + Extensions map[string]any StrictResponders bool + ReturnErrors bool ExternalDocs *spec.ExternalDocumentation Produces []string // original produces for operation (for doc) Consumes []string // original consumes for operation (for doc) @@ -730,6 +733,16 @@ func (g GenSerGroups) Len() int { return len(g) } func (g GenSerGroups) Swap(i, j int) { g[i], g[j] = g[j], g[i] } func (g GenSerGroups) Less(i, j int) bool { return g[i].Name < g[j].Name } +// NumSerializers yields the total number of serializer entries in this group. +func (g GenSerGroups) NumSerializers() int { + n := 0 + for _, group := range g { + n += len(group.AllSerializers) + } + + return n +} + // GenSerGroup represents a group of serializers: this links a serializer to a list of // prioritized media types (mime). type GenSerGroup struct { @@ -777,7 +790,7 @@ type GenSecurityScheme struct { Flow string AuthorizationURL string TokenURL string - Extensions map[string]interface{} + Extensions map[string]any ScopesDesc []GenSecurityScope } diff --git a/vendor/github.com/go-swagger/go-swagger/generator/template_repo.go b/vendor/github.com/go-swagger/go-swagger/generator/template_repo.go index 2c377372d..94a8493b4 100644 --- a/vendor/github.com/go-swagger/go-swagger/generator/template_repo.go +++ b/vendor/github.com/go-swagger/go-swagger/generator/template_repo.go @@ -3,6 +3,7 @@ package generator import ( "bytes" "encoding/json" + "errors" "fmt" "log" "math" @@ -18,10 +19,11 @@ import ( "unicode" "github.com/Masterminds/sprig/v3" + "github.com/kr/pretty" + "github.com/go-openapi/inflect" "github.com/go-openapi/runtime" "github.com/go-openapi/swag" - "github.com/kr/pretty" ) var ( @@ -34,6 +36,8 @@ var ( templates *Repository docFormat map[string]string + + errInternal = errors.New("internal error detected in templates") ) func initTemplateRepo() { @@ -109,7 +113,7 @@ func DefaultFuncMap(lang *LanguageOpts) template.FuncMap { "headerDocType": func(header GenHeader) string { return resolvedDocType(header.SwaggerType, header.SwaggerFormat, header.Child) }, - "schemaDocType": func(in interface{}) string { + "schemaDocType": func(in any) string { switch schema := in.(type) { case GenSchema: return resolvedDocSchemaType(schema.SwaggerType, schema.SwaggerFormat, schema.Items) @@ -139,7 +143,7 @@ func DefaultFuncMap(lang *LanguageOpts) template.FuncMap { "cleanupEnumVariant": cleanupEnumVariant, "gt0": gt0, "path": errorPath, - "cmdName": func(in interface{}) (string, error) { + "cmdName": func(in any) (string, error) { // builds the name of a CLI command for a single operation op, isOperation := in.(GenOperation) if !isOperation { @@ -153,7 +157,7 @@ func DefaultFuncMap(lang *LanguageOpts) template.FuncMap { return name, nil // TODO }, - "cmdGroupName": func(in interface{}) (string, error) { + "cmdGroupName": func(in any) (string, error) { // builds the name of a group of CLI commands opGroup, ok := in.(GenOperationGroup) if !ok { @@ -183,6 +187,19 @@ func DefaultFuncMap(lang *LanguageOpts) template.FuncMap { // builds a flag description variable in CLI commands return fmt.Sprintf("flag%sDescription", pascalize(in)) }, + "printGoLiteral": func(in any) string { + // printGoLiteral replaces printf "%#v" and replaces "interface {}" by "any" + return interfaceReplacer.Replace(fmt.Sprintf("%#v", in)) + }, + // assert is used to inject into templates and check for inconsistent/invalid data. + // This is for now being used during test & debug of templates. + "assert": func(msg string, assertion bool) (string, error) { + if !assertion { + return "", fmt.Errorf("%v: %w", msg, errInternal) + } + + return "", nil + }, } for k, v := range extra { @@ -503,26 +520,26 @@ func findDependencies(n parse.Node) []string { } } case *parse.IfNode: - for _, dep := range findDependencies(node.BranchNode.List) { + for _, dep := range findDependencies(node.List) { depMap[dep] = true } - for _, dep := range findDependencies(node.BranchNode.ElseList) { + for _, dep := range findDependencies(node.ElseList) { depMap[dep] = true } case *parse.RangeNode: - for _, dep := range findDependencies(node.BranchNode.List) { + for _, dep := range findDependencies(node.List) { depMap[dep] = true } - for _, dep := range findDependencies(node.BranchNode.ElseList) { + for _, dep := range findDependencies(node.ElseList) { depMap[dep] = true } case *parse.WithNode: - for _, dep := range findDependencies(node.BranchNode.List) { + for _, dep := range findDependencies(node.List) { depMap[dep] = true } - for _, dep := range findDependencies(node.BranchNode.ElseList) { + for _, dep := range findDependencies(node.ElseList) { depMap[dep] = true } @@ -542,7 +559,7 @@ func (t *Repository) flattenDependencies(templ *template.Template, dependencies dependencies = make(map[string]bool) } - deps := findDependencies(templ.Tree.Root) + deps := findDependencies(templ.Root) for _, d := range deps { if _, found := dependencies[d]; !found { @@ -615,7 +632,7 @@ func (t *Repository) DumpTemplates() { fmt.Fprintf(buf, "## %s\n", name) fmt.Fprintf(buf, "Defined in `%s`\n", t.files[name]) - if deps := findDependencies(templ.Tree.Root); len(deps) > 0 { + if deps := findDependencies(templ.Root); len(deps) > 0 { fmt.Fprintf(buf, "####requires \n - %v\n\n\n", strings.Join(deps, "\n - ")) } fmt.Fprintln(buf, "\n---") @@ -625,7 +642,7 @@ func (t *Repository) DumpTemplates() { // FuncMap functions -func asJSON(data interface{}) (string, error) { +func asJSON(data any) (string, error) { b, err := json.Marshal(data) if err != nil { return "", err @@ -633,7 +650,7 @@ func asJSON(data interface{}) (string, error) { return string(b), nil } -func asPrettyJSON(data interface{}) (string, error) { +func asPrettyJSON(data any) (string, error) { b, err := json.MarshalIndent(data, "", " ") if err != nil { return "", err @@ -658,7 +675,7 @@ func dropPackage(str string) string { // return true if the GoType str contains pkg. For example "model.MyType" -> true, "MyType" -> false func containsPkgStr(str string) bool { dropped := dropPackage(str) - return !(dropped == str) + return dropped != str } func padSurround(entry, padWith string, i, ln int) string { @@ -749,11 +766,11 @@ func cleanupEnumVariant(in string) string { return replaced } -func dict(values ...interface{}) (map[string]interface{}, error) { +func dict(values ...any) (map[string]any, error) { if len(values)%2 != 0 { return nil, fmt.Errorf("expected even number of arguments, got %d", len(values)) } - dict := make(map[string]interface{}, len(values)/2) + dict := make(map[string]any, len(values)/2) for i := 0; i < len(values); i += 2 { key, ok := values[i].(string) if !ok { @@ -764,7 +781,7 @@ func dict(values ...interface{}) (map[string]interface{}, error) { return dict, nil } -func isInteger(arg interface{}) bool { +func isInteger(arg any) bool { // is integer determines if a value may be represented by an integer switch val := arg.(type) { case int8, int16, int32, int, int64, uint8, uint16, uint32, uint, uint64: @@ -893,7 +910,7 @@ func gt0(in *int64) bool { return in != nil && *in > 0 } -func errorPath(in interface{}) (string, error) { +func errorPath(in any) (string, error) { // For schemas: // errorPath returns an empty string litteral when the schema path is empty. // It provides a shorthand for template statements such as: @@ -981,7 +998,10 @@ func errorPath(in interface{}) (string, error) { const mdNewLine = "</br>" -var mdNewLineReplacer = strings.NewReplacer("\r\n", mdNewLine, "\n", mdNewLine, "\r", mdNewLine) +var ( + mdNewLineReplacer = strings.NewReplacer("\r\n", mdNewLine, "\n", mdNewLine, "\r", mdNewLine) + interfaceReplacer = strings.NewReplacer("interface {}", "any") +) func markdownBlock(in string) string { in = strings.TrimSpace(in) diff --git a/vendor/github.com/go-swagger/go-swagger/generator/templates/cli/cli.gotmpl b/vendor/github.com/go-swagger/go-swagger/generator/templates/cli/cli.gotmpl index 073e33cfa..93f3d432e 100644 --- a/vendor/github.com/go-swagger/go-swagger/generator/templates/cli/cli.gotmpl +++ b/vendor/github.com/go-swagger/go-swagger/generator/templates/cli/cli.gotmpl @@ -2,7 +2,7 @@ {{ if .Copyright -}}// {{ comment .Copyright -}}{{ end }} -package {{ .GenOpts.CliPackage }} +package {{ toPackageName .GenOpts.CliPackage }} // This file was generated by the swagger tool. // Editing this file might prove futile when you re-run the swagger generate command @@ -35,7 +35,7 @@ var ( ) // logDebugf writes debug log to stdout -func logDebugf(format string, v ...interface{}) { +func logDebugf(format string, v ...any) { if !debug{ return } diff --git a/vendor/github.com/go-swagger/go-swagger/generator/templates/cli/completion.gotmpl b/vendor/github.com/go-swagger/go-swagger/generator/templates/cli/completion.gotmpl index c115cc1a9..cb8e8008b 100644 --- a/vendor/github.com/go-swagger/go-swagger/generator/templates/cli/completion.gotmpl +++ b/vendor/github.com/go-swagger/go-swagger/generator/templates/cli/completion.gotmpl @@ -4,7 +4,7 @@ {{ if .Copyright -}}// {{ comment .Copyright -}}{{ end }} -package {{ .GenOpts.CliPackage }} +package {{ toPackageName .GenOpts.CliPackage }} // This file was generated by the swagger tool. // Editing this file might prove futile when you re-run the swagger generate command @@ -14,7 +14,6 @@ import( ) func makeGenCompletionCmd() *cobra.Command{ - var completionCmd = &cobra.Command{ Use: "completion [bash|zsh|fish|powershell]", Short: "Generate completion script", @@ -59,19 +58,22 @@ PowerShell: `, DisableFlagsInUseLine: true, ValidArgs: []string{"bash", "zsh", "fish", "powershell"}, - Args: cobra.ExactValidArgs(1), - Run: func(cmd *cobra.Command, args []string) { + Args: cobra.MatchAll(cobra.ExactArgs(1), cobra.OnlyValidArgs), + RunE: func(cmd *cobra.Command, args []string) error { switch args[0] { case "bash": - cmd.Root().GenBashCompletion(os.Stdout) + return cmd.Root().GenBashCompletion(os.Stdout) case "zsh": - cmd.Root().GenZshCompletion(os.Stdout) + return cmd.Root().GenZshCompletion(os.Stdout) case "fish": - cmd.Root().GenFishCompletion(os.Stdout, true) + return cmd.Root().GenFishCompletion(os.Stdout, true) case "powershell": - cmd.Root().GenPowerShellCompletionWithDesc(os.Stdout) + return cmd.Root().GenPowerShellCompletionWithDesc(os.Stdout) + default: + return fmt.Errorf("unsupported shell %q", args[0]) } }, } + return completionCmd -}
\ No newline at end of file +} diff --git a/vendor/github.com/go-swagger/go-swagger/generator/templates/cli/modelcli.gotmpl b/vendor/github.com/go-swagger/go-swagger/generator/templates/cli/modelcli.gotmpl index 49b106bf9..6f3e62aaa 100644 --- a/vendor/github.com/go-swagger/go-swagger/generator/templates/cli/modelcli.gotmpl +++ b/vendor/github.com/go-swagger/go-swagger/generator/templates/cli/modelcli.gotmpl @@ -4,7 +4,7 @@ {{ if .Copyright -}}// {{ comment .Copyright -}}{{ end }} -package cli +package {{ toPackageName .CliPackage }} // This file was generated by the swagger tool. // Editing this file might prove futile when you re-run the swagger generate command diff --git a/vendor/github.com/go-swagger/go-swagger/generator/templates/cli/operation.gotmpl b/vendor/github.com/go-swagger/go-swagger/generator/templates/cli/operation.gotmpl index dc09dac07..5a39709d8 100644 --- a/vendor/github.com/go-swagger/go-swagger/generator/templates/cli/operation.gotmpl +++ b/vendor/github.com/go-swagger/go-swagger/generator/templates/cli/operation.gotmpl @@ -120,7 +120,7 @@ func retrieveOperation{{pascalize $operationGroup }}{{ pascalize $operation }}{{ {{/*Note anonymous body schema is not pointer*/}} {{ flagValueVar .Name }} := {{if containsPkgStr .GoType}}{{ .GoType }}{{else}}{{ .Pkg }}.{{.GoType}}{{ end }}{} if err := json.Unmarshal([]byte({{ flagValueVar .Name }}Str), &{{ flagValueVar .Name }}); err!= nil{ - return fmt.Errorf("cannot unmarshal {{ $flagStr }} string in {{.GoType}}: %v", err), false + return fmt.Errorf("cannot unmarshal {{ $flagStr }} string in {{.GoType}}: %w", err), false } m.{{ .ID }} = {{- if .IsNullable }}&{{- end }}{{ flagValueVar .Name }} {{- else }} @@ -165,10 +165,12 @@ func retrieveOperation{{pascalize $operationGroup }}{{ pascalize $operation }}{{ {{- /*TODO: handle multiple success response case*/}} func parseOperation{{pascalize .Package}}{{ pascalize .Name }}Result({{- if .SuccessResponse }}{{ range $i, $v := .SuccessResponses }} resp{{$i}} *{{$v.Package}}.{{pascalize $v.Name}},{{- end }}{{- end }} respErr error) (string, error){ if respErr != nil { - {{- /*error is of type default model. If we can cast, then print the resp.*/}} - {{ if .DefaultResponse }} {{with .DefaultResponse}} - {{ if .Schema }} - var iRespD interface{} = respErr +{{- /*error is of type default model. If we can cast, then print the resp.*/}} +{{- if .DefaultResponse }} + // default response + {{- with .DefaultResponse}} + {{- if .Schema }} + var iRespD any = respErr respD, ok := iRespD.(*{{ .Package }}.{{ pascalize .Name }}) if ok { if !swag.IsZero(respD) && !swag.IsZero(respD.Payload) { @@ -179,31 +181,39 @@ func parseOperation{{pascalize .Package}}{{ pascalize .Name }}Result({{- if .Suc return string(msgStr), nil } } - {{ else }} + {{- else }} // Non schema case: warning {{.Name}} is not supported - {{ end }} - {{ end }} {{ end }} - {{- range $i, $v := .Responses }} - {{ if .Schema }} - var iResp{{$i}} interface{} = respErr - resp{{$i}}, ok := iResp{{$i}}.(*{{ .Package }}.{{ pascalize .Name }}) + {{- end }} + {{- end }} +{{- end }} + + // responses +{{- range $i, $v := .Responses }} + {{- if .Schema }} + var iResp{{$i}} any = respErr + eresp{{$i}}, ok := iResp{{$i}}.(*{{ .Package }}.{{ pascalize .Name }}) if ok { - if !swag.IsZero(resp{{$i}}) && !swag.IsZero(resp{{$i}}.Payload) { - msgStr,err := json.Marshal(resp{{$i}}.Payload) + // the error response has a payload + if !swag.IsZero(eresp{{$i}}) && !swag.IsZero(eresp{{$i}}.Payload) { + msgStr,err := json.Marshal(eresp{{$i}}.Payload) if err != nil{ return "", err } return string(msgStr), nil } } - {{ else }} + + {{- else }} // Non schema case: warning {{.Name}} is not supported - {{ end }} - {{ end }} + + {{- end }} +{{- end }} return "", respErr } - {{- range $i, $v := .SuccessResponses }} - {{ if .Schema }} + + // success responses +{{- range $i, $v := .SuccessResponses }} + {{- if .Schema }} {{- with .Schema}} if !swag.IsZero(resp{{$i}}) && !swag.IsZero(resp{{$i}}.Payload) { {{- if or .IsComplexObject .IsArray .IsMap }} @@ -216,11 +226,13 @@ func parseOperation{{pascalize .Package}}{{ pascalize .Name }}Result({{- if .Suc {{- end }} return string(msgStr), nil } + {{- end }} - {{ else }} + {{- else }} // warning: non schema response {{.Name}} is not supported by go-swagger cli yet. - {{ end }} - {{ end }} + + {{- end }} +{{- end }} return "", nil } diff --git a/vendor/github.com/go-swagger/go-swagger/generator/templates/cli/registerflag.gotmpl b/vendor/github.com/go-swagger/go-swagger/generator/templates/cli/registerflag.gotmpl index fb0dba04b..eb576f1a3 100644 --- a/vendor/github.com/go-swagger/go-swagger/generator/templates/cli/registerflag.gotmpl +++ b/vendor/github.com/go-swagger/go-swagger/generator/templates/cli/registerflag.gotmpl @@ -21,7 +21,7 @@ {{ end }} {{ define "flagdefaultvar" }} - var {{ flagDefaultVar .Name }} {{ .GoType }} {{ if .Default }}= {{ printf "%#v" .Default }}{{ end }} + var {{ flagDefaultVar .Name }} {{ .GoType }} {{ if .Default }}= {{ printGoLiteral .Default }}{{ end }} {{ end }} {{/* Not used. CLI does not mark flag as required, and required will be checked by validation in future */}} diff --git a/vendor/github.com/go-swagger/go-swagger/generator/templates/client/client.gotmpl b/vendor/github.com/go-swagger/go-swagger/generator/templates/client/client.gotmpl index 85a996372..44d7ecc27 100644 --- a/vendor/github.com/go-swagger/go-swagger/generator/templates/client/client.gotmpl +++ b/vendor/github.com/go-swagger/go-swagger/generator/templates/client/client.gotmpl @@ -133,7 +133,7 @@ type ClientService interface { {{ blockcomment .Description }}{{ end }}{{ else if .Description}}{{ blockcomment .Description }}{{ else }}{{ humanize .Name }} API{{ end }} */ func (a *Client) {{ pascalize .Name }}(params *{{ pascalize .Name }}Params{{ if .Authorized }}, authInfo runtime.ClientAuthInfoWriter{{end}}{{ if .HasStreamingResponse }}, writer io.Writer{{ end }}, opts ...ClientOption) {{ if .SuccessResponse }}({{ range .SuccessResponses }}*{{ pascalize .Name }}, {{ end }}{{ end }}error{{ if .SuccessResponse }}){{ end }} { - // TODO: Validate the params before sending + // NOTE: parameters are not validated before sending if params == nil { params = New{{ pascalize .Name }}Params() } @@ -141,9 +141,9 @@ func (a *Client) {{ pascalize .Name }}(params *{{ pascalize .Name }}Params{{ if ID: {{ printf "%q" .Name }}, Method: {{ printf "%q" .Method }}, PathPattern: {{ printf "%q" .Path }}, - ProducesMediaTypes: {{ printf "%#v" .ProducesMediaTypes }}, - ConsumesMediaTypes: {{ printf "%#v" .ConsumesMediaTypes }}, - Schemes: {{ printf "%#v" .Schemes }}, + ProducesMediaTypes: {{ printGoLiteral .ProducesMediaTypes }}, + ConsumesMediaTypes: {{ printGoLiteral .ConsumesMediaTypes }}, + Schemes: {{ printGoLiteral .Schemes }}, Params: params, Reader: &{{ pascalize .Name }}Reader{formats: a.formats{{ if .HasStreamingResponse }}, writer: writer{{ end }}},{{ if .Authorized }} AuthInfo: authInfo,{{ end}} @@ -153,44 +153,63 @@ func (a *Client) {{ pascalize .Name }}(params *{{ pascalize .Name }}Params{{ if for _, opt := range opts { opt(op) } - {{ $length := len .SuccessResponses }} + {{- $length := len .SuccessResponses }} {{ if .SuccessResponse }}result{{else}}_{{ end }}, err := a.transport.Submit(op) if err != nil { return {{ if .SuccessResponse }}{{ padSurround "nil" "nil" 0 $length }}, {{ end }}err } {{- if .SuccessResponse }} {{- if eq $length 1 }} + + // only one success response has to be checked success, ok := result.(*{{ pascalize .SuccessResponse.Name }}) if ok { return success,nil } - // unexpected success response - {{- if .DefaultResponse }}{{/* if a default response is provided, fill this and return an error */}} + + // unexpected success response. + {{- if .DefaultResponse }} + // + // a default response is provided: fill this and return an error unexpectedSuccess := result.(*{{ pascalize .DefaultResponse.Name }}) + return nil, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) {{- else }} - // safeguard: normally, absent a default response, unknown success responses return an error above: so this is a codegen issue + + // no default response is defined. + // + // safeguard: normally, in the absence of a default response, unknown success responses return an error above: so this is a codegen issue msg := fmt.Sprintf("unexpected success response for {{ .Name }}: API contract not enforced by server. Client expected to get an error, but got: %T", result) panic(msg) {{- end }} - {{- else }}{{/* several possible success responses */}} + {{- else }} + + // several success responses have to be checked switch value := result.(type) { {{- range $i, $v := .SuccessResponses }} case *{{ pascalize $v.Name }}: return {{ padSurround "value" "nil" $i $length }}, nil {{- end }} } - {{- if .DefaultResponse }}{{/* if a default response is provided, fill this and return an error */}} - // unexpected success response + {{- if .DefaultResponse }} + + // unexpected success response. + // + // a default response is provided: fill this and return an error unexpectedSuccess := result.(*{{ pascalize .DefaultResponse.Name }}) return {{ padSurround "nil" "nil" 0 $length }}, runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) {{- else }} - // safeguard: normally, absent a default response, unknown success responses return an error above: so this is a codegen issue + + // no default response is defined. + // + // safeguard: normally, in the absence of a default response, unknown success responses return an error above: so this is a codegen issue msg := fmt.Sprintf("unexpected success response for {{ $.Name }}: API contract not enforced by server. Client expected to get an error, but got: %T", result) panic(msg) {{- end }} {{- end }} {{- else }} + // no success response is defined: return nil + return nil {{- end }} } diff --git a/vendor/github.com/go-swagger/go-swagger/generator/templates/client/facade.gotmpl b/vendor/github.com/go-swagger/go-swagger/generator/templates/client/facade.gotmpl index 287a75f92..5f2afc91c 100644 --- a/vendor/github.com/go-swagger/go-swagger/generator/templates/client/facade.gotmpl +++ b/vendor/github.com/go-swagger/go-swagger/generator/templates/client/facade.gotmpl @@ -30,14 +30,14 @@ var Default = NewHTTPClient(nil) const ( // DefaultHost is the default Host // found in Meta (info) section of spec file - DefaultHost string = {{ printf "%#v" .Host }} + DefaultHost string = {{ printGoLiteral .Host }} // DefaultBasePath is the default BasePath // found in Meta (info) section of spec file - DefaultBasePath string = {{ printf "%#v" .BasePath }} + DefaultBasePath string = {{ printGoLiteral .BasePath }} ) // DefaultSchemes are the default schemes found in Meta (info) section of spec file -var DefaultSchemes = {{ printf "%#v" .Schemes }} +var DefaultSchemes = {{ printGoLiteral .Schemes }} // NewHTTPClient creates a new {{ humanize .Name }} HTTP client. func NewHTTPClient(formats strfmt.Registry) *{{ pascalize .Name }} { diff --git a/vendor/github.com/go-swagger/go-swagger/generator/templates/client/response.gotmpl b/vendor/github.com/go-swagger/go-swagger/generator/templates/client/response.gotmpl index dce21aa2f..52439945a 100644 --- a/vendor/github.com/go-swagger/go-swagger/generator/templates/client/response.gotmpl +++ b/vendor/github.com/go-swagger/go-swagger/generator/templates/client/response.gotmpl @@ -197,7 +197,7 @@ func ({{ .ReceiverName }} *{{ pascalize .Name }}) readResponse(response runtime. {{- if not .Schema.IsBaseType }} // response payload - if err := consumer.Consume(response.Body(), {{ if not (or .Schema.IsComplexObject .Schema.IsStream) }}&{{ end}}{{ .ReceiverName }}.Payload); err != nil && err != io.EOF { + if err := consumer.Consume(response.Body(), {{ if not (or .Schema.IsComplexObject .Schema.IsStream) }}&{{ end}}{{ .ReceiverName }}.Payload); err != nil && !stderrors.Is(err,io.EOF) { return err } {{- end }} @@ -232,6 +232,7 @@ package {{ .Package }} import ( + stderrors "errors" "io" "net/http" @@ -254,7 +255,7 @@ type {{ pascalize .Name }}Reader struct { } // ReadResponse reads a server response into the received {{ .ReceiverName }}. -func ({{ .ReceiverName }} *{{ pascalize .Name }}Reader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) { +func ({{ .ReceiverName }} *{{ pascalize .Name }}Reader) ReadResponse(response runtime.ClientResponse, consumer runtime.Consumer) (any, error) { {{- if .Responses}} switch response.Code() { {{- end }} diff --git a/vendor/github.com/go-swagger/go-swagger/generator/templates/contrib/stratoscale/client/client.gotmpl b/vendor/github.com/go-swagger/go-swagger/generator/templates/contrib/stratoscale/client/client.gotmpl index 3398815ec..a87d5a8ec 100644 --- a/vendor/github.com/go-swagger/go-swagger/generator/templates/contrib/stratoscale/client/client.gotmpl +++ b/vendor/github.com/go-swagger/go-swagger/generator/templates/contrib/stratoscale/client/client.gotmpl @@ -64,15 +64,15 @@ type Client struct { {{ blockcomment .Description }}{{ end }}{{ else if .Description}}{{ blockcomment .Description }}{{ else }}{{ humanize .Name }} API{{ end }} */ func (a *Client) {{ pascalize .Name }}(ctx context.Context, params *{{ pascalize .Name }}Params{{ if .HasStreamingResponse }}, writer io.Writer{{ end }}) {{ if .SuccessResponse }}({{ range .SuccessResponses }}*{{ pascalize .Name }}, {{ end }}{{ end }}error{{ if .SuccessResponse }}){{ end }} { - {{ $length := len .SuccessResponses }} - {{ $success := .SuccessResponses }} + {{- $length := len .SuccessResponses }} + {{- $success := .SuccessResponses }} {{ if .Responses }}result{{else}}_{{end}}, err := a.transport.Submit(&runtime.ClientOperation{ ID: {{ printf "%q" .Name }}, Method: {{ printf "%q" .Method }}, PathPattern: {{ printf "%q" .Path }}, - ProducesMediaTypes: {{ printf "%#v" .ProducesMediaTypes }}, - ConsumesMediaTypes: {{ printf "%#v" .ConsumesMediaTypes }}, - Schemes: {{ printf "%#v" .Schemes }}, + ProducesMediaTypes: {{ printGoLiteral .ProducesMediaTypes }}, + ConsumesMediaTypes: {{ printGoLiteral .ConsumesMediaTypes }}, + Schemes: {{ printGoLiteral .Schemes }}, Params: params, Reader: &{{ pascalize .Name }}Reader{formats: a.formats{{ if .HasStreamingResponse }}, writer: writer{{ end }}}, {{ if .Authorized -}} @@ -85,25 +85,44 @@ func (a *Client) {{ pascalize .Name }}(ctx context.Context, params *{{ pascalize return {{ if $success }}{{ padSurround "nil" "nil" 0 $length }}, {{ end }}err } {{- if .Responses }} + {{- if gt (len .Responses) 1 }} + switch value := result.(type) { {{- range $i, $v := .Responses }} case *{{ pascalize $v.Name }}: - {{- if $v.IsSuccess }} + {{- if $v.IsSuccess }} return {{ if $success }}{{ padSurround "value" "nil" $i $length }},{{ end }}nil - {{- else }} + {{- else }} return {{ if $success }}{{ padSurround "nil" "nil" 0 $length }},{{ end }}runtime.NewAPIError("unsuccessful response", value, value.Code()) - {{- end }} + {{- end }} {{- end }} } - {{- if .DefaultResponse }} - // unexpected success response + {{- else }} + {{- $v := (index .Responses 0) }} + if value, ok := result.(*{{ pascalize $v.Name }}) ; ok { + {{- if $v.IsSuccess }} + return {{ if $success }}{{ padSurround "value" "nil" 0 $length }},{{ end }}nil + {{- else }} + return {{ if $success }}{{ padSurround "nil" "nil" 0 $length }},{{ end }}runtime.NewAPIError("unsuccessful response", value, value.Code()) + {{- end }} + } + {{- end }} + + // unexpected response. + {{- if .DefaultResponse }} + // + // a default response is provided: fill this and return an error unexpectedSuccess := result.(*{{ pascalize .DefaultResponse.Name }}) + return {{ if $success }}{{ padSurround "nil" "nil" 0 $length }}, {{ end }}runtime.NewAPIError("unexpected success response: content available as default response in error", unexpectedSuccess, unexpectedSuccess.Code()) - {{- else }} - // safeguard: normally, absent a default response, unknown success responses return an error above: so this is a codegen issue + {{- else }} + + // no default response is defined. + // + // safeguard: normally, in the absence of a default response, unknown responses return an error above: so this is a codegen issue msg := fmt.Sprintf("unexpected success response for {{ .Name }}: API contract not enforced by server. Client expected to get an error, but got: %T", result) panic(msg) - {{- end }} + {{- end }} {{- else }} return nil {{- end }} diff --git a/vendor/github.com/go-swagger/go-swagger/generator/templates/contrib/stratoscale/client/facade.gotmpl b/vendor/github.com/go-swagger/go-swagger/generator/templates/contrib/stratoscale/client/facade.gotmpl index 1d658978b..6b4245668 100644 --- a/vendor/github.com/go-swagger/go-swagger/generator/templates/contrib/stratoscale/client/facade.gotmpl +++ b/vendor/github.com/go-swagger/go-swagger/generator/templates/contrib/stratoscale/client/facade.gotmpl @@ -28,14 +28,14 @@ import ( const ( // DefaultHost is the default Host // found in Meta (info) section of spec file - DefaultHost string = {{ printf "%#v" .Host }} + DefaultHost string = {{ printGoLiteral .Host }} // DefaultBasePath is the default BasePath // found in Meta (info) section of spec file - DefaultBasePath string = {{ printf "%#v" .BasePath }} + DefaultBasePath string = {{ printGoLiteral .BasePath }} ) // DefaultSchemes are the default schemes found in Meta (info) section of spec file -var DefaultSchemes = {{ printf "%#v" .Schemes }} +var DefaultSchemes = {{ printGoLiteral .Schemes }} type Config struct { // URL is the base URL of the upstream server diff --git a/vendor/github.com/go-swagger/go-swagger/generator/templates/contrib/stratoscale/server/configureapi.gotmpl b/vendor/github.com/go-swagger/go-swagger/generator/templates/contrib/stratoscale/server/configureapi.gotmpl index 03f8d6745..ecb7a6753 100644 --- a/vendor/github.com/go-swagger/go-swagger/generator/templates/contrib/stratoscale/server/configureapi.gotmpl +++ b/vendor/github.com/go-swagger/go-swagger/generator/templates/contrib/stratoscale/server/configureapi.gotmpl @@ -27,30 +27,29 @@ import ( type contextKey string const AuthKey contextKey = "Auth" +{{- range .OperationGroups }} -{{ range .OperationGroups -}} //go:generate mockery --name {{ pascalize .Name}}API --inpackage /* {{ pascalize .Name }}API {{ .Description }} */ type {{ pascalize .Name }}API interface { -{{ range .Operations -}} - {{ if .Summary -}} +{{- range .Operations }} + {{- if .Summary }} /* {{ pascalize .Name }} {{ .Summary }} */ - {{ else if .Description -}} + {{- else if .Description }} /* {{ pascalize .Name }} {{ .Description }} */ - {{ end -}} + {{- end }} {{ pascalize .Name }}(ctx context.Context, params {{.Package}}.{{ pascalize .Name }}Params) middleware.Responder - -{{ end -}} +{{- end }} } -{{ end }} +{{- end }} // Config is configuration for Handler type Config struct { - {{ range .OperationGroups -}} + {{- range .OperationGroups }} {{ pascalize .Name }}API - {{ end -}} - Logger func(string, ...interface{}) + {{- end }} + Logger func(string, ...any) // InnerMiddleware is for the handler executors. These do not apply to the swagger.json document. // The middleware executes after routing but before authentication, binding and validation InnerMiddleware func(http.Handler) http.Handler @@ -58,21 +57,23 @@ type Config struct { // Authorizer is used to authorize a request after the Auth function was called using the "Auth*" functions // and the principal was stored in the context in the "AuthKey" context value. Authorizer func(*http.Request) error + {{- range .SecurityDefinitions }} + {{- if .IsBasicAuth }} - {{ range .SecurityDefinitions -}} - {{ if .IsBasicAuth -}} // Auth{{ pascalize .ID }} for basic authentication - Auth{{ pascalize .ID }} func(user string, pass string) ({{ if .PrincipalIsNullable }}*{{ end }}{{ .Principal }}, error) - {{ end -}} - {{ if .IsAPIKeyAuth -}} + Auth{{ pascalize .ID }} func(user string, password string) ({{ if .PrincipalIsNullable }}*{{ end }}{{ .Principal }}, error) + {{- end }} + {{- if .IsAPIKeyAuth }} + // Auth{{ pascalize .ID }} Applies when the "{{ .Name }}" {{ .Source }} is set Auth{{ pascalize .ID }} func(token string) ({{ if .PrincipalIsNullable }}*{{ end }}{{ .Principal }}, error) - {{ end }} - {{ if .IsOAuth2 -}} - // Auth{{ pascalize .ID }} For OAuth2 authentication + {{- end }} + {{- if .IsOAuth2 }} + + // Auth{{ pascalize .ID }} for OAuth2 authentication Auth{{ pascalize .ID }} func(token string, scopes []string) ({{ if .PrincipalIsNullable }}*{{ end }}{{ .Principal }}, error) - {{ end -}} - {{ end -}} + {{- end }} + {{- end }} // Authenticator to use for all APIKey authentication APIKeyAuthenticator func(string, string, security.TokenAuthentication) runtime.Authenticator @@ -80,13 +81,13 @@ type Config struct { BasicAuthenticator func(security.UserPassAuthentication) runtime.Authenticator // Authenticator to use for all Basic authentication BearerAuthenticator func(string, security.ScopedTokenAuthentication) runtime.Authenticator + {{- range .Consumes }} + {{- if .Implementation }} - {{ range .Consumes -}} - {{ if .Implementation -}} // {{ pascalize .Name }}Consumer is a {{ .Name }} consumer that will replace the default if not nil. {{ pascalize .Name }}Consumer runtime.Consumer - {{ end -}} - {{ end -}} + {{- end }} + {{- end }} } // Handler returns an http.Handler given the handler configuration @@ -102,7 +103,7 @@ func Handler(c Config) (http.Handler, error) { func HandlerAPI(c Config) (http.Handler, *{{.Package}}.{{ pascalize .Name }}API, error) { spec, err := loads.Analyzed(swaggerCopy(SwaggerJSON), "") if err != nil { - return nil, nil, fmt.Errorf("analyze swagger: %v", err) + return nil, nil, fmt.Errorf("analyze swagger: %w", err) } api := {{.Package}}.New{{ pascalize .Name }}API(spec) api.ServeError = errors.ServeError @@ -117,83 +118,96 @@ func HandlerAPI(c Config) (http.Handler, *{{.Package}}.{{ pascalize .Name }}API, if c.BearerAuthenticator != nil { api.BearerAuthenticator = c.BearerAuthenticator } + {{- range .Consumes }} - {{ range .Consumes -}} if c.{{ pascalize .Name }}Consumer != nil { api.{{ pascalize .Name }}Consumer = c.{{ pascalize .Name }}Consumer } else { - {{ if .Implementation -}} + {{- if .Implementation }} api.{{ pascalize .Name }}Consumer = {{ .Implementation }} - {{ else }} - api.{{ pascalize .Name }}Consumer = runtime.ConsumerFunc(func(r io.Reader, target interface{}) error { + {{- else }} + api.{{ pascalize .Name }}Consumer = runtime.ConsumerFunc(func(r io.Reader, target any) error { + _ = r + _ = target + return errors.NotImplemented("{{.Name}} consumer has not yet been implemented") }) - {{ end -}} + {{- end }} } - {{ end -}} - {{ range .Produces -}} - {{ if .Implementation -}} + {{- end }} + {{- range .Produces }} + {{- if .Implementation }} api.{{ pascalize .Name }}Producer = {{ .Implementation }} - {{ else -}} - api.{{ pascalize .Name }}Producer = runtime.ProducerFunc(func(w io.Writer, data interface{}) error { + {{- else }} + api.{{ pascalize .Name }}Producer = runtime.ProducerFunc(func(w io.Writer, data any) error { + _ = w + _ = data + return errors.NotImplemented("{{.Name}} producer has not yet been implemented") }) - {{ end -}} - {{ end -}} + {{- end }} + {{- end }} + {{- range .SecurityDefinitions }} + {{- if .IsBasicAuth }} - {{ range .SecurityDefinitions -}} - {{ if .IsBasicAuth -}} - api.{{ pascalize .ID }}Auth = func(user string, pass string) ({{if .PrincipalIsNullable }}*{{ end }}{{.Principal}}, error) { + api.{{ pascalize .ID }}Auth = func(user string, password string) ({{if .PrincipalIsNullable }}*{{ end }}{{.Principal}}, error) { if c.Auth{{ pascalize .ID }} == nil { - {{- if eq .Principal "interface{}" }} + {{- if eq .Principal "any" }} return "", nil - {{- else }} - panic("you specified a custom principal type, but did not provide the authenticator to provide this") - {{- end }} + {{- else }} + panic("you specified a custom principal type, but did not provide the authenticator to resolve a principal") + {{- end }} } - return c.Auth{{ pascalize .ID }}(user, pass) + + return c.Auth{{ pascalize .ID }}(user, password) } - {{ end -}} - {{ if .IsAPIKeyAuth -}} + {{- end }} + {{- if .IsAPIKeyAuth }} + api.{{ pascalize .ID }}Auth = func(token string) ({{ if .PrincipalIsNullable }}*{{ end }}{{.Principal}}, error) { if c.Auth{{ pascalize .ID }} == nil { - {{- if eq .Principal "interface{}" }} + {{- if eq .Principal "any" }} return token, nil - {{- else }} - panic("you specified a custom principal type, but did not provide the authenticator to provide this") - {{- end }} + {{- else }} + panic("you specified a custom principal type, but did not provide the authenticator to resolve a principal") + {{- end }} } + return c.Auth{{ pascalize .ID }}(token) } - {{ end }} - {{ if .IsOAuth2 -}} + {{- end }} + {{- if .IsOAuth2 }} + api.{{ pascalize .ID }}Auth = func(token string, scopes []string) ({{ if .PrincipalIsNullable }}*{{ end }}{{.Principal}}, error) { if c.Auth{{ pascalize .ID }} == nil { - {{- if eq .Principal "interface{}" }} + {{- if eq .Principal "any" }} return token, nil - {{- else }} - panic("you specified a custom principal type, but did not provide the authenticator to provide this") - {{- end }} + {{- else }} + panic("you specified a custom principal type, but did not provide the authenticator to resolve a principal") + {{- end }} } + return c.Auth{{ pascalize .ID }}(token, scopes) } - {{ end -}} - {{ end -}} + {{- end }} + {{- end }} + {{- if .SecurityDefinitions }} - {{ if .SecurityDefinitions -}} api.APIAuthorizer = authorizer(c.Authorizer) - {{ end -}} + {{- end }} + + {{- range .Operations }} - {{ range .Operations -}} api.{{if ne .Package $package}}{{pascalize .Package}}{{end}}{{ pascalize .Name }}Handler = {{- .PackageAlias }}.{{ pascalize .Name }}HandlerFunc(func(params {{.PackageAlias}}.{{ pascalize .Name }}Params{{if .Authorized}}, principal {{ if .PrincipalIsNullable }}*{{ end }}{{ .Principal }}{{end}}) middleware.Responder { ctx := params.HTTPRequest.Context() - {{ if .Authorized -}} + {{- if .Authorized }} ctx = storeAuth(ctx, principal) - {{ end -}} - return c.{{pascalize .Package}}API.{{pascalize .Name}}(ctx, params) + {{- end }} + + return c.{{pascalize .Name}}(ctx, params) }) - {{ end -}} + {{- end }} api.ServerShutdown = func() { } return api.Serve(c.InnerMiddleware), api, nil @@ -209,7 +223,7 @@ func swaggerCopy(orig json.RawMessage) json.RawMessage { // authorizer is a helper function to implement the runtime.Authorizer interface. type authorizer func(*http.Request) error -func (a authorizer) Authorize(req *http.Request, principal interface{}) error { +func (a authorizer) Authorize(req *http.Request, principal any) error { if a == nil { return nil } @@ -217,6 +231,6 @@ func (a authorizer) Authorize(req *http.Request, principal interface{}) error { return a(req.WithContext(ctx)) } -func storeAuth(ctx context.Context, principal interface{}) context.Context { +func storeAuth(ctx context.Context, principal any) context.Context { return context.WithValue(ctx, AuthKey, principal) } diff --git a/vendor/github.com/go-swagger/go-swagger/generator/templates/header.gotmpl b/vendor/github.com/go-swagger/go-swagger/generator/templates/header.gotmpl index a60cae1ea..4fc2ba18d 100644 --- a/vendor/github.com/go-swagger/go-swagger/generator/templates/header.gotmpl +++ b/vendor/github.com/go-swagger/go-swagger/generator/templates/header.gotmpl @@ -10,6 +10,8 @@ package {{.Package}} // Editing this file might prove futile when you re-run the swagger generate command import ( + stderrors "errors" + "github.com/go-openapi/strfmt" {{- if .DefaultImports }} {{ imports .DefaultImports }} diff --git a/vendor/github.com/go-swagger/go-swagger/generator/templates/schemaembedded.gotmpl b/vendor/github.com/go-swagger/go-swagger/generator/templates/schemaembedded.gotmpl index f86c27bc6..58e1a949c 100644 --- a/vendor/github.com/go-swagger/go-swagger/generator/templates/schemaembedded.gotmpl +++ b/vendor/github.com/go-swagger/go-swagger/generator/templates/schemaembedded.gotmpl @@ -4,7 +4,7 @@ type {{ pascalize .Name }} struct { } func ({{.ReceiverName }} {{ if or .IsTuple .IsComplexObject }}*{{ end }}{{ if .Discriminates }}{{ camelize .Name }}{{ else if .IsExported }}{{ pascalize .Name }}{{ else }}{{ .Name }}{{ end }}) Validate(formats strfmt.Registry) error { - var f interface{} = {{ .ReceiverName }}.{{ dropPackage .ElemType.GoType }} + var f any = {{ .ReceiverName }}.{{ dropPackage .ElemType.GoType }} if v, ok := f.(runtime.Validatable) ; ok { return v.Validate(formats) } @@ -12,7 +12,7 @@ func ({{.ReceiverName }} {{ if or .IsTuple .IsComplexObject }}*{{ end }}{{ if .D } func ({{.ReceiverName }} {{ if or .IsTuple .IsComplexObject }}*{{ end }}{{ if .Discriminates }}{{ camelize .Name }}{{ else if .IsExported }}{{ pascalize .Name }}{{ else }}{{ .Name }}{{ end }}) ContextValidate(ctx context.Context, formats strfmt.Registry) error { - var f interface{} = {{ .ReceiverName }}.{{ dropPackage .ElemType.GoType }} + var f any = {{ .ReceiverName }}.{{ dropPackage .ElemType.GoType }} if v, ok := f.(runtime.ContextValidatable) ; ok { return v.ContextValidate(ctx, formats) } diff --git a/vendor/github.com/go-swagger/go-swagger/generator/templates/schemavalidator.gotmpl b/vendor/github.com/go-swagger/go-swagger/generator/templates/schemavalidator.gotmpl index cee8a5dd6..341c34ef0 100644 --- a/vendor/github.com/go-swagger/go-swagger/generator/templates/schemavalidator.gotmpl +++ b/vendor/github.com/go-swagger/go-swagger/generator/templates/schemavalidator.gotmpl @@ -1,16 +1,24 @@ {{ define "primitivefieldcontextvalidator" }} - {{ if .ReadOnly }} - if err := validate.ReadOnly(ctx, {{ path . }}, {{ printf "%q" .Location }}, {{ if not (or .IsAnonymous .IsNullable) }}{{ .GoType }}({{ end }}{{.ValueExpression }}{{ if not (or .IsAnonymous .IsNullable) }}){{ end }}); err != nil{ + {{- if .ReadOnly }} + if err := validate.ReadOnly(ctx, {{ path . }}, {{ printf "%q" .Location }}, {{.ValueExpression }}); err != nil{ return err } - {{ end }} + {{- end }} {{ end }} {{ define "primitivefieldvalidator" }} {{ if .Required }} + {{- /* NOTE(fredbi): we have introduced a type conversion here a long time ago, and I can't remember why we did so. + + In all known cases this type conversion was superfluous. + + If there is a valid case when we need to coerce the .ValueExpression to the .GoType, + I've failed so far to produce a test for it. Removed the type conversion until we find when it could be + useful. + */}} {{- if and (eq .GoType "string") (not .IsNullable) }} - if err := validate.RequiredString({{ path . }}, {{ printf "%q" .Location }}, {{ if .IsAliased }}{{ .GoType }}({{ end }}{{.ValueExpression }}{{ if .IsAliased }}){{ end }}); err != nil { + if err := validate.RequiredString({{ path . }}, {{ printf "%q" .Location }}, {{.ValueExpression }}); err != nil { {{- else }} - if err := validate.Required({{ path . }}, {{ printf "%q" .Location }}, {{ if not (or .IsAnonymous .IsNullable) }}{{ .GoType }}({{ end }}{{.ValueExpression }}{{ if not (or .IsAnonymous .IsNullable) }}){{ end }}); err != nil { + if err := validate.Required({{ path . }}, {{ printf "%q" .Location }}, {{.ValueExpression }}); err != nil { {{- end }} return err } @@ -52,7 +60,7 @@ {{ define "slicecontextvalidator" }} {{ if .ReadOnly }} - if err := validate.ReadOnly(ctx, {{ path . }}, {{ printf "%q" .Location }}, {{ if not (or .IsAnonymous .IsNullable) }}{{ .GoType }}({{ end }}{{.ValueExpression }}{{ if not (or .IsAnonymous .IsNullable) }}){{ end }}); err != nil{ + if err := validate.ReadOnly(ctx, {{ path . }}, {{ printf "%q" .Location }}, {{.ValueExpression }}); err != nil{ return err } {{ end }} @@ -70,11 +78,15 @@ if {{ .ValueExpression }} != nil { {{- end }} if err := {{.ValueExpression }}.ContextValidate(ctx, formats); err != nil { - if ve, ok := err.(*errors.Validation); ok { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { return ve.ValidateName({{ path . }}) - } else if ce, ok := err.(*errors.CompositeError); ok { + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { return ce.ValidateName({{ path . }}) } + return err } {{- if and .IsNullable (not .IsMapNullOverride) }} @@ -137,11 +149,15 @@ if {{ .ValueExpression }} != nil { {{- end }} if err := {{.ValueExpression }}.Validate(formats); err != nil { - if ve, ok := err.(*errors.Validation); ok { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { return ve.ValidateName({{ path . }}) - } else if ce, ok := err.(*errors.CompositeError); ok { + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { return ce.ValidateName({{ path . }}) } + return err } {{- if and .IsNullable (not .IsMapNullOverride) }} @@ -312,11 +328,15 @@ if val != nil { {{- end }} if err := val.Validate(formats); err != nil { - if ve, ok := err.(*errors.Validation); ok { - return ve.ValidateName({{ path . }}) - } else if ce, ok := err.(*errors.CompositeError); ok { - return ce.ValidateName({{ path . }}) + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName({{ path . }}) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName({{ path . }}) } + return err } {{- if and .IsNullable (not .IsMapNullOverride) }} @@ -372,11 +392,15 @@ if val != nil { {{- end }} if err := val.Validate(formats); err != nil { - if ve, ok := err.(*errors.Validation); ok { - return ve.ValidateName({{ path . }}) - } else if ce, ok := err.(*errors.CompositeError); ok { - return ce.ValidateName({{ path . }}) + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName({{ path . }}) + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName({{ path . }}) } + return err } {{- if and .IsNullable (not .IsMapNullOverride) }} @@ -467,11 +491,15 @@ } {{ end }} if err := {{.ValueExpression }}.ContextValidate(ctx, formats); err != nil { - if ve, ok := err.(*errors.Validation); ok { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { return ve.ValidateName({{ path . }}) - } else if ce, ok := err.(*errors.CompositeError); ok { + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { return ce.ValidateName({{ path . }}) } + return err } {{- if and .IsNullable (not .IsMapNullOverride) }} @@ -568,11 +596,15 @@ if {{ .ValueExpression }} != nil { {{- end }} if err := {{.ValueExpression }}.Validate(formats); err != nil { - if ve, ok := err.(*errors.Validation); ok { + ve := new(errors.Validation) + if stderrors.As(err, &ve) { return ve.ValidateName({{ path . }}) - } else if ce, ok := err.(*errors.CompositeError); ok { + } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { return ce.ValidateName({{ path . }}) } + return err } {{- if or (and (or .IsNullable) (not .IsMapNullOverride)) .IsMap .IsArray }} @@ -608,7 +640,7 @@ // at https://github.com/go-swagger/go-swagger/issues {{- if .ReadOnly }} - if err := validate.ReadOnly{{ if and (eq .GoType "string") (not .IsNullable) }}String{{ end }}({{ path . }}, {{ printf "%q" .Location }}, {{ if not (or .IsAnonymous .IsNullable) }}{{ .GoType }}({{ end }}{{.ValueExpression }}{{ if not (or .IsAnonymous .IsNullable) }}){{ end }}); err != nil { + if err := validate.ReadOnly{{ if and (eq .GoType "string") (not .IsNullable) }}String{{ end }}({{ path . }}, {{ printf "%q" .Location }}, {{.ValueExpression }}; err != nil { return err } {{- end }} @@ -619,7 +651,7 @@ {{- end }} {{- else if .IsArray }} {{ template "slicecontextvalidator" . }} - {{- else if and .IsMap (or (not .IsAliased) (and .IsAliased .IsInterface)) }}{{/* except for interface, the renderinf for aliased maps is performed by objectvalidator */}} + {{- else if and .IsMap (or (not .IsAliased) (and .IsAliased .IsInterface)) }}{{/* except for interface, the rendering for aliased maps is performed by objectvalidator */}} {{ template "mapcontextvalidator" . }} {{- else if or .IsComplexObject .IsTuple .IsAdditionalProperties .IsAliased }} {{ template "objectcontextvalidator" . }} @@ -631,7 +663,7 @@ {{- if .IsPrimitive }} {{- if .IsAliased }} {{- if and .Required (not .IsAnonymous) }} - if err := validate.Required{{ if and (eq .GoType "string") (not .IsNullable) }}String{{ end }}({{ path . }}, {{ printf "%q" .Location }}, {{ if not (or .IsAnonymous .IsNullable) }}{{ .GoType }}({{ end }}{{.ValueExpression }}{{ if not (or .IsAnonymous .IsNullable) }}){{ end }}); err != nil { + if err := validate.Required{{ if and (eq .GoType "string") (not .IsNullable) }}String{{ end }}({{ path . }}, {{ printf "%q" .Location }}, {{.ValueExpression }}); err != nil { return err } {{- end }} @@ -641,7 +673,7 @@ {{- end }} {{- else if and .IsCustomFormatter (or .HasValidations .Required) }}{{/* custom format not captured as primitive */}} {{- if .Required }} - if err := validate.Required{{ if and (eq .GoType "string") (not .IsNullable) }}String{{ end }}({{ path . }}, {{ printf "%q" .Location }}, {{ if not (or .IsAnonymous .IsNullable) }}{{ .GoType }}({{ end }}{{.ValueExpression }}{{ if not (or .IsAnonymous .IsNullable) }}){{ end }}); err != nil { + if err := validate.Required{{ if and (eq .GoType "string") (not .IsNullable) }}String{{ end }}({{ path . }}, {{ printf "%q" .Location }}, {{.ValueExpression }}); err != nil { return err } {{- end }} @@ -660,7 +692,7 @@ return errors.Required({{ path . }}, {{ printf "%q" .Location }}, {{ .ValueExpression }}) } {{- else }} - if err := validate.Required{{ if and (eq .GoType "string") (not .IsNullable) }}String{{ end }}({{ path . }}, {{ printf "%q" .Location }}, {{ if not (or .IsAnonymous .IsNullable) }}{{ .GoType }}({{ end }}{{.ValueExpression }}{{ if not (or .IsAnonymous .IsNullable) }}){{ end }}); err != nil { + if err := validate.Required{{ if and (eq .GoType "string") (not .IsNullable) }}String{{ end }}({{ path . }}, {{ printf "%q" .Location }}, {{.ValueExpression }}); err != nil { return err } {{- end }} @@ -672,7 +704,7 @@ return errors.Required({{ path . }}, {{ printf "%q" .Location }}, {{ .ValueExpression }}) } {{- else }} - if err := validate.Required{{ if and (eq .GoType "string") (not .IsNullable) }}String{{ end }}({{ path . }}, {{ printf "%q" .Location }}, {{ if not (or .IsAnonymous .IsNullable) }}{{ .GoType }}({{ end }}{{.ValueExpression }}{{ if not (or .IsAnonymous .IsNullable) }}){{ end }}); err != nil { + if err := validate.Required{{ if and (eq .GoType "string") (not .IsNullable) }}String{{ end }}({{ path . }}, {{ printf "%q" .Location }}, {{.ValueExpression }}); err != nil { return err } {{- end }} @@ -703,7 +735,7 @@ {{ template "primitivefieldvalidator" . }} {{- else if and .IsCustomFormatter (or .HasValidations .Required) }}{{/* custom format not captured as primitive */}} {{- if .Required }} - if err := validate.Required{{ if and (eq .GoType "string") (not .IsNullable) }}String{{ end }}({{ path . }}, {{ printf "%q" .Location }}, {{ if not (or .IsAnonymous .IsNullable) }}{{ .GoType }}({{ end }}{{.ValueExpression }}{{ if not (or .IsAnonymous .IsNullable) }}){{ end }}); err != nil { + if err := validate.Required{{ if and (eq .GoType "string") (not .IsNullable) }}String{{ end }}({{ path . }}, {{ printf "%q" .Location }}, {{.ValueExpression }}); err != nil { return err } {{- end }} @@ -804,7 +836,7 @@ const ( {{ end }} // for schema -var {{ camelize .Name }}Enum []interface{} +var {{ camelize .Name }}Enum []any func init() { var res []{{ template "dereffedSchemaType" . }} if err := json.Unmarshal([]byte(`{{ json .Enum }}`), &res); err != nil { @@ -823,7 +855,7 @@ func ({{ .ReceiverName }} {{ if not .IsPrimitive }}*{{ end }}{{ if .IsExported } } {{ end }} {{ if .ItemsEnum }} -var {{ camelize .Name }}ItemsEnum []interface{} +var {{ camelize .Name }}ItemsEnum []any func init() { var res []{{ template "dereffedSchemaType" .Items }} @@ -845,7 +877,7 @@ func ({{ .ReceiverName }} *{{ if $.IsExported }}{{ pascalize $.Name }}{{ else }} {{ with .AdditionalProperties }} {{ if .Enum }} // for additional props -var {{ camelize .Name }}ValueEnum []interface{} +var {{ camelize .Name }}ValueEnum []any func init() { var res []{{ template "dereffedSchemaType" . }} @@ -929,7 +961,7 @@ func ({{.ReceiverName }} {{ if or .IsTuple .IsComplexObject .IsAdditionalPropert {{ range .Properties }} {{ if or .Required .HasValidations }} {{ if .Enum }} -var {{ camelize $.Name }}Type{{ pascalize .Name }}PropEnum []interface{} +var {{ camelize $.Name }}Type{{ pascalize .Name }}PropEnum []any func init() { var res []{{ template "dereffedSchemaType" . }} @@ -962,7 +994,7 @@ func ({{ .ReceiverName }} *{{ if $.Discriminates }}{{ camelize $.Name }}{{ else } {{ end }} {{ if .ItemsEnum }} -var {{ camelize $.Name }}{{ pascalize .Name }}ItemsEnum []interface{} +var {{ camelize $.Name }}{{ pascalize .Name }}ItemsEnum []any func init() { var res []{{ template "dereffedSchemaType" .Items }} if err := json.Unmarshal([]byte(`{{ json .ItemsEnum }}`), &res); err != nil { @@ -982,7 +1014,7 @@ func ({{ .ReceiverName }} *{{ if $.Discriminates }}{{ camelize $.Name }}{{ else {{ end }} {{ if .AdditionalItems }} {{ if .AdditionalItems.Enum }} -var {{ camelize $.Name }}Type{{ pascalize .Name }}PropEnum []interface{} +var {{ camelize $.Name }}Type{{ pascalize .Name }}PropEnum []any func init() { var res []{{ template "dereffedSchemaType" .AdditionalItems }} @@ -1005,7 +1037,7 @@ func ({{ .ReceiverName }} *{{ if $.Discriminates }}{{ camelize $.Name }}{{ else {{ with .AdditionalProperties }} {{ if .Enum }} // additional properties value enum -var {{ camelize $.Name }}{{ pascalize .Name }}ValueEnum []interface{} +var {{ camelize $.Name }}{{ pascalize .Name }}ValueEnum []any func init() { var res []{{ template "dereffedSchemaType" . }} @@ -1063,7 +1095,7 @@ func ({{.ReceiverName }} *{{ if $.Discriminates }}{{ camelize $.Name }}{{ else i {{ range .Properties }} {{ if and (ne $.DiscriminatorField .Name) (or .Required .HasValidations) }} {{ if .Enum }} -var {{ camelize $.Name }}Type{{ pascalize .Name }}PropEnum []interface{} +var {{ camelize $.Name }}Type{{ pascalize .Name }}PropEnum []any func init() { var res []{{ template "dereffedSchemaType" . }} @@ -1084,7 +1116,7 @@ func ({{ .ReceiverName }} *{{ if $.Discriminates }}{{ camelize $.Name }}{{ else } {{ end }} {{ if .ItemsEnum }} -var {{ camelize $.Name }}{{ pascalize .Name }}ItemsEnum []interface{} +var {{ camelize $.Name }}{{ pascalize .Name }}ItemsEnum []any func init() { var res []{{ template "dereffedSchemaType" .Items }} @@ -1105,7 +1137,7 @@ func ({{ .ReceiverName }} *{{ if $.Discriminates }}{{ camelize $.Name }}{{ else {{ end }} {{ if .AdditionalItems }} {{ if .AdditionalItems.Enum }} -var {{ camelize $.Name }}Type{{ pascalize .Name }}PropEnum []interface{} +var {{ camelize $.Name }}Type{{ pascalize .Name }}PropEnum []any func init() { var res []{{ template "dereffedSchemaType" .AdditionalItems }} @@ -1127,7 +1159,7 @@ func ({{ .ReceiverName }} *{{ if $.Discriminates }}{{ camelize $.Name }}{{ else {{ end }} {{ with .AdditionalProperties }} {{ if .Enum }} -var {{ camelize $.Name }}{{ pascalize .Name }}ValueEnum []interface{} +var {{ camelize $.Name }}{{ pascalize .Name }}ValueEnum []any func init() { var res []{{ template "dereffedSchemaType" . }} if err := json.Unmarshal([]byte(`{{ json .Enum }}`), &res); err != nil { @@ -1169,7 +1201,7 @@ func ({{.ReceiverName }} *{{ if $.Discriminates }}{{ camelize $.Name }}{{ else i {{ if .HasAdditionalItems }} {{ if .AdditionalItems.Enum }} -var {{ camelize .Name }}ItemsEnum []interface{} +var {{ camelize .Name }}ItemsEnum []any func init() { var res []{{ template "dereffedSchemaType" .AdditionalItems }} diff --git a/vendor/github.com/go-swagger/go-swagger/generator/templates/serializers/additionalpropertiesserializer.gotmpl b/vendor/github.com/go-swagger/go-swagger/generator/templates/serializers/additionalpropertiesserializer.gotmpl index a09058683..8abad384b 100644 --- a/vendor/github.com/go-swagger/go-swagger/generator/templates/serializers/additionalpropertiesserializer.gotmpl +++ b/vendor/github.com/go-swagger/go-swagger/generator/templates/serializers/additionalpropertiesserializer.gotmpl @@ -13,7 +13,7 @@ func ({{.ReceiverName}} *{{ pascalize .Name }}) UnmarshalJSON(data []byte) error *{{ .ReceiverName }} = rcv // stage 2, remove properties and add to map - stage2 := make(map[string]{{ if .AdditionalProperties }}json.RawMessage{{ else }}interface{}{{ end }}) + stage2 := make(map[string]{{ if .AdditionalProperties }}json.RawMessage{{ else }}any{{ end }}) if err := json.Unmarshal(data, &stage2); err != nil { return err } diff --git a/vendor/github.com/go-swagger/go-swagger/generator/templates/serializers/subtypeserializer.gotmpl b/vendor/github.com/go-swagger/go-swagger/generator/templates/serializers/subtypeserializer.gotmpl index b15613efc..819e67ff1 100644 --- a/vendor/github.com/go-swagger/go-swagger/generator/templates/serializers/subtypeserializer.gotmpl +++ b/vendor/github.com/go-swagger/go-swagger/generator/templates/serializers/subtypeserializer.gotmpl @@ -28,14 +28,14 @@ func ({{.ReceiverName}} *{{ pascalize .Name }}) UnmarshalJSON(raw []byte) error var allOf{{ pascalize .Name }} {{ if .IsArray }}[]{{ pascalize .Items.GoType }}{{ else }}{{ pascalize .GoType }}{{ end }} if string(data.{{ pascalize .Name }}) != "null" { {{ camelize .Name }}, err := Unmarshal{{ if .IsArray }}{{ pascalize .Items.GoType }}Slice{{ else }}{{ pascalize .GoType }}{{ end }}(bytes.NewBuffer(data.{{ pascalize .Name }}), runtime.JSONConsumer()) - if err != nil && err != io.EOF { + if err != nil && !stderrors.Is(err, io.EOF) { return err } allOf{{ pascalize .Name }} = {{ camelize .Name }} } {{- else }} allOf{{ pascalize .Name }}, err := Unmarshal{{ if .IsArray }}{{ pascalize .Items.GoType }}Slice{{ else }}{{ pascalize .GoType }}{{ end }}(bytes.NewBuffer(data.{{ pascalize .Name }}), runtime.JSONConsumer()) - if err != nil && err != io.EOF { + if err != nil && !stderrors.Is(err, io.EOF) { return err } {{- end }} @@ -49,14 +49,14 @@ func ({{.ReceiverName}} *{{ pascalize .Name }}) UnmarshalJSON(raw []byte) error var prop{{ pascalize .Name }} {{ if .IsArray }}[]{{ pascalize .Items.GoType }}{{ else }}{{ pascalize .GoType }}{{ end }} if string(data.{{ pascalize .Name }}) != "null" { {{ camelize .Name }}, err := Unmarshal{{ if .IsArray }}{{ pascalize .Items.GoType }}Slice{{ else }}{{ pascalize .GoType }}{{ end }}(bytes.NewBuffer(data.{{ pascalize .Name }}), runtime.JSONConsumer()) - if err != nil && err != io.EOF { + if err != nil && !stderrors.Is(err, io.EOF) { return err } prop{{ pascalize .Name }} = {{ camelize .Name }} } {{- else }} prop{{ pascalize .Name }}, err := Unmarshal{{ if .IsArray }}{{ pascalize .Items.GoType }}Slice{{ else }}{{ pascalize .GoType }}{{ end }}(bytes.NewBuffer(data.{{ pascalize .Name }}), runtime.JSONConsumer()) - if err != nil && err != io.EOF { + if err != nil && !stderrors.Is(err, io.EOF) { return err } {{- end }} @@ -119,7 +119,7 @@ func ({{.ReceiverName}} *{{ pascalize .Name }}) UnmarshalJSON(raw []byte) error {{ if .IsAdditionalProperties }} // Additional Properties: read raw, remove named properties, and add to map - rawProps := make(map[string]{{ if .AdditionalProperties }}json.RawMessage{{ else }}interface{}{{ end }}) + rawProps := make(map[string]{{ if .AdditionalProperties }}json.RawMessage{{ else }}any{{ end }}) if err := json.Unmarshal(raw, &rawProps); err != nil { return err } diff --git a/vendor/github.com/go-swagger/go-swagger/generator/templates/serializers/tupleserializer.gotmpl b/vendor/github.com/go-swagger/go-swagger/generator/templates/serializers/tupleserializer.gotmpl index c05e844bb..c493b766f 100644 --- a/vendor/github.com/go-swagger/go-swagger/generator/templates/serializers/tupleserializer.gotmpl +++ b/vendor/github.com/go-swagger/go-swagger/generator/templates/serializers/tupleserializer.gotmpl @@ -51,7 +51,7 @@ func ({{.ReceiverName}} *{{ pascalize .Name }}) UnmarshalJSON(raw []byte) error // MarshalJSON marshals this tuple type into a JSON array func ({{.ReceiverName}} {{ pascalize .Name }}) MarshalJSON() ([]byte, error) { - data := []interface{}{ + data := []any{ {{ range .Properties -}} {{.ReceiverName}}.{{ pascalize .Name }}, {{- end }} diff --git a/vendor/github.com/go-swagger/go-swagger/generator/templates/server/autoconfigureapi.gotmpl b/vendor/github.com/go-swagger/go-swagger/generator/templates/server/autoconfigureapi.gotmpl index 629b4b22b..77cc1ec3b 100644 --- a/vendor/github.com/go-swagger/go-swagger/generator/templates/server/autoconfigureapi.gotmpl +++ b/vendor/github.com/go-swagger/go-swagger/generator/templates/server/autoconfigureapi.gotmpl @@ -42,12 +42,13 @@ import ( {{- if .ExcludeSpec }} --exclude-spec{{ end }} {{- if .DumpData }} --dump-data{{ end }} {{- if .StrictResponders }} --strict-responders{{ end }} +{{- if .ReturnErrors }} --return-errors{{ end }} {{ end }} // This file auto configures the api backend implementation. // {{.ImplementationPackageAlias}} package must already exist. // {{.ImplementationPackageAlias}}.New() is implemented by user, and must return an object -// or interface that implements Handler interface defined below. +// or interface that implements Handler interface defined below. var Impl Handler = {{.ImplementationPackageAlias}}.New() // Handler handles all api server backend configurations and requests @@ -77,7 +78,7 @@ type Authable interface{ {{- range .SecurityDefinitions }} {{- if .IsBasicAuth }} // Applies when the Authorization header is set with the Basic scheme - {{ pascalize .ID }}Auth(user string, pass string) ({{ if .PrincipalIsNullable }}*{{ end }}{{.Principal}}, error) + {{ pascalize .ID }}Auth(user string, password string) ({{ if .PrincipalIsNullable }}*{{ end }}{{.Principal}}, error) {{- else if .IsAPIKeyAuth }} // Applies when the "{{ .Name }}" {{ .Source }} is set {{ pascalize .ID }}Auth(token string) ({{ if .PrincipalIsNullable }}*{{ end }}{{.Principal}}, error) @@ -101,7 +102,11 @@ type {{ pascalize .Name }}Handler interface { {{ end -}} {{ pascalize .Name }}(params {{ if ne .Package $package }}{{ .PackageAlias }}{{ else }}{{- $apipackagealias }}{{ end }}. {{- pascalize .Name }}Params {{- if .Authorized}}, principal {{ if .PrincipalIsNullable }}*{{ end }}{{.Principal}}{{end}}) - {{- if $.GenOpts.StrictResponders }} {{.Package}}.{{ pascalize .Name }}Responder {{ else }} middleware.Responder {{ end }} + {{- if $.GenOpts.ReturnErrors }} + {{- if $.GenOpts.StrictResponders }} ({{.Package}}.{{ pascalize .Name }}Responder, error) {{ else }} (middleware.Responder, error) {{ end }} + {{ else }} + {{- if $.GenOpts.StrictResponders }} {{.Package}}.{{ pascalize .Name }}Responder {{ else }} middleware.Responder {{ end }} + {{ end -}} {{ end -}} } {{ end }} @@ -120,7 +125,7 @@ func configureAPI(api *{{.APIPackageAlias}}.{{ pascalize .Name }}API) http.Handl {{- if .Implementation }} api.{{ pascalize .Name }}Consumer = {{ .Implementation }} {{- else }} - api.{{ pascalize .Name }}Consumer = runtime.ConsumerFunc(func(r io.Reader, target interface{}) error { + api.{{ pascalize .Name }}Consumer = runtime.ConsumerFunc(func(r io.Reader, target any) error { return Impl.{{ pascalize .Name }}Consume(r, target) }) {{- end }} @@ -129,7 +134,7 @@ func configureAPI(api *{{.APIPackageAlias}}.{{ pascalize .Name }}API) http.Handl {{- if .Implementation }} api.{{ pascalize .Name }}Producer = {{ .Implementation }} {{- else }} - api.{{ pascalize .Name }}Producer = runtime.ProducerFunc(func(w io.Writer, data interface{}) error { + api.{{ pascalize .Name }}Producer = runtime.ProducerFunc(func(w io.Writer, data any) error { return Impl.{{ pascalize .Name }}Produce(w, target) }) {{- end }} @@ -137,10 +142,10 @@ func configureAPI(api *{{.APIPackageAlias}}.{{ pascalize .Name }}API) http.Handl {{ range .SecurityDefinitions }} {{- if .IsBasicAuth }} // Applies when the Authorization header is set with the Basic scheme - api.{{ pascalize .ID }}Auth = func(user string, pass string) ({{ if .PrincipalIsNullable }}*{{ end }}{{.Principal}}, error) { - return Impl.{{ pascalize .ID }}Auth(user, pass) + api.{{ pascalize .ID }}Auth = func(user string, password string) ({{ if .PrincipalIsNullable }}*{{ end }}{{.Principal}}, error) { + return Impl.{{ pascalize .ID }}Auth(user, password) } - + {{- else if .IsAPIKeyAuth }} // Applies when the "{{ .Name }}" {{ .Source }} is set api.{{ pascalize .ID }}Auth = func(token string) ({{ if .PrincipalIsNullable }}*{{ end }}{{.Principal}}, error) { @@ -162,8 +167,12 @@ func configureAPI(api *{{.APIPackageAlias}}.{{ pascalize .Name }}API) http.Handl {{- else }} {{- $apipackagealias }}.{{- pascalize .Name }}HandlerFunc(func(params {{ $apipackagealias }}.{{- pascalize .Name }}Params {{- end }} - {{- if .Authorized}}, principal {{ if .PrincipalIsNullable }}*{{ end }}{{.Principal}}{{end}}) - {{- if $.GenOpts.StrictResponders }} {{.Package}}.{{ pascalize .Name }}Responder { {{ else }} middleware.Responder { {{ end }} + {{- if .Authorized}}, principal {{ if .PrincipalIsNullable }}*{{ end }}{{.Principal}}{{end}}) + {{- if $.GenOpts.ReturnErrors }} + {{- if $.GenOpts.StrictResponders }} ({{.Package}}.{{ pascalize .Name }}Responder, error) { {{ else }} (middleware.Responder, error) { {{ end }} + {{ else }} + {{- if $.GenOpts.StrictResponders }} {{.Package}}.{{ pascalize .Name }}Responder { {{ else }} middleware.Responder { {{ end }} + {{ end }} return Impl.{{ pascalize .Name }}(params {{- if .Authorized}}, principal {{ end }}) }) {{- end }} diff --git a/vendor/github.com/go-swagger/go-swagger/generator/templates/server/builder.gotmpl b/vendor/github.com/go-swagger/go-swagger/generator/templates/server/builder.gotmpl index fda11859a..a290a18a1 100644 --- a/vendor/github.com/go-swagger/go-swagger/generator/templates/server/builder.gotmpl +++ b/vendor/github.com/go-swagger/go-swagger/generator/templates/server/builder.gotmpl @@ -51,7 +51,10 @@ func New{{ pascalize .Name }}API(spec *loads.Document) *{{ pascalize .Name }}API {{- if .Implementation }} {{ pascalize .Name }}Consumer: {{ .Implementation }}, {{- else }} - {{ pascalize .Name }}Consumer: runtime.ConsumerFunc(func(r io.Reader, target interface{}) error { + {{ pascalize .Name }}Consumer: runtime.ConsumerFunc(func(r io.Reader, target any) error { + _ = r + _ = target + return errors.NotImplemented("{{.Name}} consumer has not yet been implemented") }), {{- end }} @@ -60,38 +63,62 @@ func New{{ pascalize .Name }}API(spec *loads.Document) *{{ pascalize .Name }}API {{- if .Implementation }} {{ pascalize .Name }}Producer: {{ .Implementation }}, {{- else }} - {{ pascalize .Name }}Producer: runtime.ProducerFunc(func(w io.Writer, data interface{}) error { + {{ pascalize .Name }}Producer: runtime.ProducerFunc(func(w io.Writer, data any) error { + _ = w + _ = data + return errors.NotImplemented("{{.Name}} producer has not yet been implemented") }), {{- end }} {{- end }} {{ range .Operations }} + {{ $mayBePackage := "" }} + {{ if ne .Package $package -}} + {{ $mayBePackage = printf "%s." .PackageAlias }} + {{ end -}} + {{ if ne .Package $package }}{{ pascalize .Package }}{{ end }}{{ pascalize .Name }}Handler: - {{- if ne .Package $package }}{{ .PackageAlias }}.{{ end }}{{ pascalize .Name }}HandlerFunc(func(params {{ if ne .Package $package }}{{ .PackageAlias }}.{{end }} - {{- if $.GenOpts.StrictResponders}} - {{- pascalize .Name }}Params{{if .Authorized}}, principal {{if .PrincipalIsNullable }}*{{ end }}{{.Principal}}{{end}}) {{if ne .Package $package }}{{ .Package }}.{{ end }}{{ pascalize .Name }}Responder { - return {{if ne .Package $package }}{{ .Package }}.{{ end }}{{ pascalize .Name }}NotImplemented() - {{else}} - {{- pascalize .Name }}Params{{if .Authorized}}, principal {{if .PrincipalIsNullable }}*{{ end }}{{.Principal}}{{end}}) middleware.Responder { - return middleware.NotImplemented("operation {{ if ne .Package $package }}{{ .Package }}.{{ end }}{{pascalize .Name}} has not yet been implemented") - {{ end -}} + {{ $mayBePackage }}{{ pascalize .Name }}HandlerFunc(func(params {{ $mayBePackage }}{{ pascalize .Name }}Params{{if .Authorized}}, principal {{if .PrincipalIsNullable }}*{{ end }}{{.Principal}}{{end}}) + {{- if $.GenOpts.ReturnErrors }} + {{- if $.GenOpts.StrictResponders }} ({{ $mayBePackage }}{{ pascalize .Name }}Responder, error) { {{ else }} (middleware.Responder, error) { {{ end }} + {{ else }} + {{- if $.GenOpts.StrictResponders }} {{ $mayBePackage }}{{ pascalize .Name }}Responder { {{ else }} middleware.Responder { {{ end }} + {{ end -}} + _ = params + {{- if .Authorized }} + _ = principal + {{- end }} + + {{ if $.GenOpts.StrictResponders }} + return {{ $mayBePackage }}{{ pascalize .Name }}NotImplemented(){{ if $.GenOpts.ReturnErrors }}, nil {{- end -}} + {{ else }} + return middleware.NotImplemented("operation {{ $mayBePackage }}{{pascalize .Name}} has not yet been implemented"){{ if $.GenOpts.ReturnErrors }}, nil {{- end -}} + {{- end }} }), {{- end }} {{ range .SecurityDefinitions }} {{- if .IsBasicAuth }} // Applies when the Authorization header is set with the Basic scheme - {{ pascalize .ID }}Auth: func(user string, pass string) ({{if .PrincipalIsNullable }}*{{ end }}{{.Principal}}, error) { + {{ pascalize .ID }}Auth: func(user string, password string) ({{if .PrincipalIsNullable }}*{{ end }}{{.Principal}}, error) { + _ = user + _ = password + return nil, errors.NotImplemented("basic auth ({{ .ID }}) has not yet been implemented") }, {{- end }} {{- if .IsAPIKeyAuth }} // Applies when the "{{ .Name }}" {{ .Source }} is set {{ pascalize .ID }}Auth: func(token string) ({{if .PrincipalIsNullable }}*{{ end }}{{.Principal}}, error) { + _ = token + return nil, errors.NotImplemented("api key auth ({{ .ID }}) {{.Name}} from {{.Source}} param [{{ .Name }}] has not yet been implemented") }, {{- end }} {{- if .IsOAuth2 }} {{ pascalize .ID }}Auth: func(token string, scopes []string) ({{if .PrincipalIsNullable }}*{{ end }}{{.Principal}}, error) { + _ = token + _ = scopes + return nil, errors.NotImplemented("oauth2 bearer auth ({{ .ID }}) has not yet been implemented") }, {{- end }} @@ -188,7 +215,7 @@ type {{ pascalize .Name }}API struct { CommandLineOptionsGroups []swag.CommandLineOptionsGroup // User defined logger function. - Logger func(string, ...interface{}) + Logger func(string, ...any) } // UseRedoc for documentation at /docs @@ -266,37 +293,51 @@ func ({{.ReceiverName}} *{{ pascalize .Name }}API) Validate() error { return nil } + // ServeErrorFor gets a error handler for a given operation id func ({{.ReceiverName}} *{{ pascalize .Name }}API) ServeErrorFor(operationID string) func(http.ResponseWriter, *http.Request, error) { return {{.ReceiverName}}.ServeError } +{{- define "defForScheme" }} + {{- if .IsBasicAuth }} + result[name] = {{.ReceiverName}}.BasicAuthenticator({{ if not ( eq .Principal "any" ) }}func(username, password string) (any, error) { + return {{ end }}{{.ReceiverName}}.{{ pascalize .ID }}Auth{{ if not ( eq .Principal "any" ) }}(username, password) + }{{ end }}) + {{- else if .IsAPIKeyAuth }} + scheme := schemes[name] + result[name] = {{.ReceiverName}}.APIKeyAuthenticator(scheme.Name, scheme.In, {{ if not ( eq .Principal "any" ) }}func(token string) (any, error) { + return {{ end }}{{.ReceiverName}}.{{ pascalize .ID }}Auth{{ if not ( eq .Principal "any" ) }}(token) + }{{ end }}) + {{- else if .IsOAuth2 }} + result[name] = {{.ReceiverName}}.BearerAuthenticator(name, {{ if not ( eq .Principal "any" ) }}func(token string, scopes []string) (any, error) { + return {{ end }}{{.ReceiverName}}.{{ pascalize .ID }}Auth{{ if not ( eq .Principal "any" ) }}(token, scopes) + }{{ end }}) + {{- end }} +{{- end }} + // AuthenticatorsFor gets the authenticators for the specified security schemes func ({{.ReceiverName}} *{{ pascalize .Name }}API) AuthenticatorsFor(schemes map[string]spec.SecurityScheme) map[string]runtime.Authenticator { {{- if .SecurityDefinitions }} result := make(map[string]runtime.Authenticator) for name := range schemes { + {{- if gt (len .SecurityDefinitions) 1 }} switch name { {{- range .SecurityDefinitions }} case "{{.ID}}": - {{- if .IsBasicAuth }} - result[name] = {{.ReceiverName}}.BasicAuthenticator({{ if not ( eq .Principal "interface{}" ) }}func(username, password string) (interface{}, error) { - return {{ end }}{{.ReceiverName}}.{{ pascalize .ID }}Auth{{ if not ( eq .Principal "interface{}" ) }}(username, password) - }{{ end }}) - {{- end }} - {{- if .IsAPIKeyAuth }} - scheme := schemes[name] - result[name] = {{.ReceiverName}}.APIKeyAuthenticator(scheme.Name, scheme.In, {{ if not ( eq .Principal "interface{}" ) }}func(token string) (interface{}, error) { - return {{ end }}{{.ReceiverName}}.{{ pascalize .ID }}Auth{{ if not ( eq .Principal "interface{}" ) }}(token) - }{{ end }}) - {{- end }} - {{- if .IsOAuth2 }} - result[name] = {{.ReceiverName}}.BearerAuthenticator(name, {{ if not ( eq .Principal "interface{}" ) }}func(token string, scopes []string) (interface{}, error) { - return {{ end }}{{.ReceiverName}}.{{ pascalize .ID }}Auth{{ if not ( eq .Principal "interface{}" ) }}(token, scopes) - }{{ end }}) - {{- end }} - {{end}} + {{- template "defForScheme" . }} + {{ end }} + } + {{- else }} + {{- /* whenever we only have one security definition, write this as a if statement rather than a switch */}} + {{- $definition := (index .SecurityDefinitions 0) }} + {{- with $definition }} + if name == "{{ .ID }}" { + {{- template "defForScheme" . }} } + {{- end }} + {{- end }} } + return result {{- else }} return nil @@ -313,24 +354,37 @@ func ({{.ReceiverName}} *{{ pascalize .Name }}API) Authorizer() runtime.Authoriz } // ConsumersFor gets the consumers for the specified media types. +// // MIME type parameters are ignored here. func ({{.ReceiverName}} *{{ pascalize .Name }}API) ConsumersFor(mediaTypes []string) map[string]runtime.Consumer { {{- if .Consumes }} result := make(map[string]runtime.Consumer, len(mediaTypes)) for _, mt := range mediaTypes { + {{- if gt .Consumes.NumSerializers 1 }} switch mt { - {{- range .Consumes }} - {{- range .AllSerializers }} + {{- range .Consumes }} + {{- range .AllSerializers }} case "{{ .MediaType }}": result["{{ .MediaType }}"] = {{.ReceiverName}}.{{ pascalize .Name }}Consumer + {{- end }} {{- end }} - {{- end }} } + {{- else }} + {{- /* whenever we only have one serializer, write this as a if statement rather than a switch */}} + {{- $serializerGroup := (index .Consumes 0) }} + {{- $serializer := (index $serializerGroup.AllSerializers 0) }} + {{- with $serializer }} + if mt == "{{ .MediaType }}" { + result["{{ .MediaType }}"] = {{.ReceiverName}}.{{ pascalize .Name }}Consumer + } + {{- end }} + {{- end }} if c, ok := {{.ReceiverName}}.customConsumers[mt]; ok { result[mt] = c } } + return result {{- else }} return nil @@ -338,11 +392,13 @@ func ({{.ReceiverName}} *{{ pascalize .Name }}API) ConsumersFor(mediaTypes []str } // ProducersFor gets the producers for the specified media types. +// // MIME type parameters are ignored here. func ({{.ReceiverName}} *{{ pascalize .Name }}API) ProducersFor(mediaTypes []string) map[string]runtime.Producer { {{- if .Produces }} result := make(map[string]runtime.Producer, len(mediaTypes)) for _, mt := range mediaTypes { + {{- if gt .Produces.NumSerializers 1 }} switch mt { {{- range .Produces }} {{- range .AllSerializers }} @@ -351,11 +407,22 @@ func ({{.ReceiverName}} *{{ pascalize .Name }}API) ProducersFor(mediaTypes []str {{- end }} {{- end }} } + {{- else }} + {{- /* whenever we only have one serializer, write this as a if statement rather than a switch */}} + {{- $serializerGroup := (index .Produces 0) }} + {{- $serializer := (index $serializerGroup.AllSerializers 0) }} + {{- with $serializer }} + if mt == "{{ .MediaType }}" { + result["{{ .MediaType }}"] = {{.ReceiverName}}.{{ pascalize .Name }}Producer + } + {{- end }} + {{- end }} if p, ok := {{.ReceiverName}}.customProducers[mt]; ok { result[mt] = p } } + return result {{- else }} return nil diff --git a/vendor/github.com/go-swagger/go-swagger/generator/templates/server/configureapi.gotmpl b/vendor/github.com/go-swagger/go-swagger/generator/templates/server/configureapi.gotmpl index cbbb0bfd1..7d8167d95 100644 --- a/vendor/github.com/go-swagger/go-swagger/generator/templates/server/configureapi.gotmpl +++ b/vendor/github.com/go-swagger/go-swagger/generator/templates/server/configureapi.gotmpl @@ -40,9 +40,11 @@ import ( {{- if .ExcludeSpec }} --exclude-spec{{ end }} {{- if .DumpData }} --dump-data{{ end }} {{- if .StrictResponders }} --strict-responders{{ end }} +{{- if .ReturnErrors }} --return-errors{{ end }} {{ end }} func configureFlags(api *{{.APIPackageAlias}}.{{ pascalize .Name }}API) { // api.CommandLineOptionsGroups = []swag.CommandLineOptionsGroup{ ... } + _ = api } func configureAPI(api *{{.APIPackageAlias}}.{{ pascalize .Name }}API) http.Handler { @@ -50,7 +52,7 @@ func configureAPI(api *{{.APIPackageAlias}}.{{ pascalize .Name }}API) http.Handl api.ServeError = errors.ServeError // Set your custom logger if needed. Default one is log.Printf - // Expected interface func(string, ...interface{}) + // Expected interface func(string, ...any) // // Example: // api.Logger = log.Printf @@ -63,7 +65,10 @@ func configureAPI(api *{{.APIPackageAlias}}.{{ pascalize .Name }}API) http.Handl {{- if .Implementation }} api.{{ pascalize .Name }}Consumer = {{ .Implementation }} {{- else }} - api.{{ pascalize .Name }}Consumer = runtime.ConsumerFunc(func(r io.Reader, target interface{}) error { + api.{{ pascalize .Name }}Consumer = runtime.ConsumerFunc(func(r io.Reader, target any) error { + _ = r + _ = target + return errors.NotImplemented("{{.Name}} consumer has not yet been implemented") }) {{- end }} @@ -72,7 +77,10 @@ func configureAPI(api *{{.APIPackageAlias}}.{{ pascalize .Name }}API) http.Handl {{- if .Implementation }} api.{{ pascalize .Name }}Producer = {{ .Implementation }} {{- else }} - api.{{ pascalize .Name }}Producer = runtime.ProducerFunc(func(w io.Writer, data interface{}) error { + api.{{ pascalize .Name }}Producer = runtime.ProducerFunc(func(w io.Writer, data any) error { + _ = w + _ = data + return errors.NotImplemented("{{.Name}} producer has not yet been implemented") }) {{- end }} @@ -81,7 +89,10 @@ func configureAPI(api *{{.APIPackageAlias}}.{{ pascalize .Name }}API) http.Handl {{- if .IsBasicAuth }} // Applies when the Authorization header is set with the Basic scheme if api.{{ pascalize .ID }}Auth == nil { - api.{{ pascalize .ID }}Auth = func(user string, pass string) ({{ if .PrincipalIsNullable }}*{{ end }}{{.Principal}}, error) { + api.{{ pascalize .ID }}Auth = func(user string, password string) ({{ if .PrincipalIsNullable }}*{{ end }}{{.Principal}}, error) { + _ = user + _ = password + return nil, errors.NotImplemented("basic auth ({{ .ID }}) has not yet been implemented") } } @@ -89,12 +100,17 @@ func configureAPI(api *{{.APIPackageAlias}}.{{ pascalize .Name }}API) http.Handl // Applies when the "{{ .Name }}" {{ .Source }} is set if api.{{ pascalize .ID }}Auth == nil { api.{{ pascalize .ID }}Auth = func(token string) ({{ if .PrincipalIsNullable }}*{{ end }}{{.Principal}}, error) { + _ = token + return nil, errors.NotImplemented("api key auth ({{ .ID }}) {{.Name}} from {{.Source}} param [{{ .Name }}] has not yet been implemented") } } {{- else if .IsOAuth2 }} if api.{{ pascalize .ID }}Auth == nil { api.{{ pascalize .ID }}Auth = func(token string, scopes []string) ({{ if .PrincipalIsNullable }}*{{ end }}{{.Principal}}, error) { + _ = token + _ = scopes + return nil, errors.NotImplemented("oauth2 bearer auth ({{ .ID }}) has not yet been implemented") } } @@ -124,13 +140,22 @@ func configureAPI(api *{{.APIPackageAlias}}.{{ pascalize .Name }}API) http.Handl {{- else }} {{- $apipackagealias }}.{{- pascalize .Name }}HandlerFunc(func(params {{ $apipackagealias }}.{{- pascalize .Name }}Params {{- end }} - {{- if $.GenOpts.StrictResponders }} - {{- if .Authorized}}, principal {{ if .PrincipalIsNullable }}*{{ end }}{{.Principal}}{{end}}) {{.Package}}.{{ pascalize .Name }}Responder { - return {{.Package}}.{{ pascalize .Name }}NotImplemented() - {{ else }} - {{- if .Authorized}}, principal {{if .PrincipalIsNullable }}*{{ end }}{{.Principal}}{{end}}) middleware.Responder { - return middleware.NotImplemented("operation {{ .Package}}.{{pascalize .Name}} has not yet been implemented") - {{ end -}} + {{- if .Authorized}}, principal {{ if .PrincipalIsNullable }}*{{ end }}{{.Principal}}{{end}}) + {{- if $.GenOpts.ReturnErrors }} + {{- if $.GenOpts.StrictResponders }} ({{.Package}}.{{ pascalize .Name }}Responder, error) { {{ else }} (middleware.Responder, error) { {{ end }} + {{ else }} + {{- if $.GenOpts.StrictResponders }} {{.Package}}.{{ pascalize .Name }}Responder { {{ else }} middleware.Responder { {{ end }} + {{ end -}} + _ = params + {{- if .Authorized }} + _ = principal + {{- end }} + + {{ if $.GenOpts.StrictResponders }} + return {{.Package}}.{{ pascalize .Name }}NotImplemented(){{ if $.GenOpts.ReturnErrors }}, nil {{- end -}} + {{ else }} + return middleware.NotImplemented("operation {{ .Package}}.{{pascalize .Name}} has not yet been implemented"){{ if $.GenOpts.ReturnErrors }}, nil {{- end -}} + {{- end }} }) } {{- end }} @@ -145,13 +170,17 @@ func configureAPI(api *{{.APIPackageAlias}}.{{ pascalize .Name }}API) http.Handl // The TLS configuration before HTTPS server starts. func configureTLS(tlsConfig *tls.Config) { // Make all necessary changes to the TLS configuration here. + _ = tlsConfig } // As soon as server is initialized but not run yet, this function will be called. // If you need to modify a config, store server instance to stop it individually later, this is the place. // This function can be called multiple times, depending on the number of serving schemes. // scheme value will be set accordingly: "http", "https" or "unix". -func configureServer(s *http.Server, scheme, addr string) { +func configureServer(server *http.Server, scheme, addr string) { + _ = server + _ = scheme + _ = addr } // The middleware configuration is for the handler executors. These do not apply to the swagger.json document. diff --git a/vendor/github.com/go-swagger/go-swagger/generator/templates/server/main.gotmpl b/vendor/github.com/go-swagger/go-swagger/generator/templates/server/main.gotmpl index a6447ede7..4e9b86632 100644 --- a/vendor/github.com/go-swagger/go-swagger/generator/templates/server/main.gotmpl +++ b/vendor/github.com/go-swagger/go-swagger/generator/templates/server/main.gotmpl @@ -1,12 +1,93 @@ -// Code generated by go-swagger; DO NOT EDIT. +{{- define "specTitle" }} + {{- if .Info }} + {{- if .Info.Title }} + {{- printf "%q" .Info.Title }} + {{- else }} + {{- if .ExcludeSpec }}""{{ else }}swaggerSpec.Spec().Info.Title{{ end }} + {{- end }} + {{- else }} + {{- if .ExcludeSpec }}""{{ else }}swaggerSpec.Spec().Info.Title{{ end }} + {{- end}} +{{- end }} + +{{- define "specDescription" }} + {{- if .Info }} + {{- if .Info.Description }} + {{- printf "%q" .Info.Description }} + {{- else }} + {{- if .ExcludeSpec }}""{{ else }}swaggerSpec.Spec().Info.Description{{ end }} + {{- end }} + {{- else }} + {{- if .ExcludeSpec }}""{{ else }}swaggerSpec.Spec().Info.Description{{ end }} + {{- end}} +{{- end }} + +{{- define "printUsage" }} fmt.Fprint(os.Stderr, "Usage:\n") + fmt.Fprint(os.Stderr, " {{ dasherize .Name }}-server [OPTIONS]\n\n") + + title := {{ template "specTitle" . }} + if title != "" { + fmt.Fprintf(os.Stderr, "%s\n\n", title) + } + desc := {{ template "specDescription" . }} + if desc != "" { + fmt.Fprintf(os.Stderr, "%s\n\n", desc) + } +{{- end }} + +{{- define "argsParser" }} + {{- if .UsePFlags }}{{/* CLI flags by github.com/spf13/pflag */}} + flag.Usage = func() { + {{ template "printUsage" . }} + fmt.Fprintln(os.Stderr, flag.CommandLine.FlagUsages()) + } + + // parse the CLI flags + flag.Parse() // exit on error + {{- else if .UseGoStructFlags }}{{/* CLI flags by github.com/jessevdk/go-flags */}} + parser := flags.NewParser(server, flags.Default) + parser.ShortDescription = {{ template "specTitle" . }} + parser.LongDescription = {{ template "specDescription" . }} + {{- if not .ExcludeSpec }} + for _, optsGroup := range api.CommandLineOptionsGroups { + _, err := parser.AddGroup(optsGroup.ShortDescription, optsGroup.LongDescription, optsGroup.Options) + if err != nil { + log.Fatalln(err) + } + } + {{- end }} + if _, err := parser.Parse(); err != nil { + code := 1 + fe := new(flags.Error) + if errors.As(err, &fe) { + if fe.Type == flags.ErrHelp { + code = 0 + } + } + os.Exit(code) + } + {{- else if .UseFlags }}{{/* CLI flags by standard library */}} + flag.Usage = func() { + {{ template "printUsage" . }} + flag.CommandLine.SetOutput(os.Stderr) + flag.PrintDefaults() + } - {{ if .Copyright -}}// {{ comment .Copyright -}}{{ end }} + // parse the CLI flags + flag.Parse() // exit on error + {{- else }} + // missing a CLI flag library setting + {{- end }} +{{- end }} +// Code generated by go-swagger; DO NOT EDIT. +{{ if .Copyright -}}// {{ comment .Copyright -}}{{ end }} package main import ( + "errors" "fmt" "log" "net/http" @@ -15,12 +96,12 @@ import ( "github.com/go-openapi/loads" {{- if .UseGoStructFlags }} flags "github.com/jessevdk/go-flags" - {{- end }} - {{- if .UsePFlags }} + {{- else if .UsePFlags }} flag "github.com/spf13/pflag" - {{- end }} - {{- if .UseFlags }} + {{- else if .UseFlags }} "flag" + {{- else }} + // missing a CLI flag library setting {{- end }} {{ imports .DefaultImports }} @@ -29,63 +110,21 @@ import ( // This file was generated by the swagger tool. // Make sure not to overwrite this file after you generated it because all your edits would be lost! -{{ if .ExcludeSpec }} +{{- if .ExcludeSpec }}{{/* spec excluded means that it is not built inside the generated code and loaded at runtime */}} + func init() { loads.AddLoader(fmts.YAMLMatcher, fmts.YAMLDoc) } -{{ end }} +{{- end }} func main() { - {{ if .UsePFlags }} - {{- if not .ExcludeSpec }} - swaggerSpec, err := loads.Embedded({{ .ServerPackageAlias }}.SwaggerJSON, {{ .ServerPackageAlias }}.FlatSwaggerJSON) - if err != nil { - log.Fatalln(err) - } - {{- end }} - - var server *{{ .ServerPackageAlias }}.Server // make sure init is called - - flag.Usage = func() { - fmt.Fprint(os.Stderr, "Usage:\n") - fmt.Fprint(os.Stderr, " {{ dasherize .Name }}-server [OPTIONS]\n\n") - - title := {{ if .Info }}{{ if .Info.Title }}{{ printf "%q" .Info.Title }}{{ else }}{{ if .ExcludeSpec }}""{{ else }}swaggerSpec.Spec().Info.Title{{ end }}{{ end }}{{ else }}{{ if .ExcludeSpec }}""{{ else }}swaggerSpec.Spec().Info.Title{{ end }}{{ end}} - fmt.Fprint(os.Stderr, title+"\n\n") - desc := {{ if .Info }}{{ if .Info.Description }}{{ printf "%q" .Info.Description }}{{ else }}{{ if .ExcludeSpec }}""{{ else }}swaggerSpec.Spec().Info.Description{{ end }}{{ end }}{{ else }}{{ if .ExcludeSpec }}""{{ else }}swaggerSpec.Spec().Info.Description{{ end }}{{ end}} - if desc != "" { - fmt.Fprintf(os.Stderr, desc+"\n\n") - } - fmt.Fprintln(os.Stderr, flag.CommandLine.FlagUsages()) - } - // parse the CLI flags - flag.Parse() - {{- if .ExcludeSpec }} - - server = {{ .ServerPackageAlias }}.NewServer(nil) - swaggerSpec, err := loads.Spec(string(server.Spec)) - if err != nil { - log.Fatalln(err) - } - api := {{.APIPackageAlias}}.New{{ pascalize .Name }}API(swaggerSpec) - server.SetAPI(api) - {{- else }} - - api := {{.APIPackageAlias}}.New{{ pascalize .Name }}API(swaggerSpec) - // get server with flag values filled out - server = {{ .ServerPackageAlias }}.NewServer(api) - {{- end }} - defer server.Shutdown() - - server.ConfigureAPI() - if err := server.Serve(); err != nil { - log.Fatalln(err) - } - {{ end }} - {{ if .UseGoStructFlags}} - {{- if .ExcludeSpec }} +{{- if .ExcludeSpec }} + {{- if not .UseGoStructFlags }}{{/* with pflag and flag, an init() func injects args */}} + var server *{{ .ServerPackageAlias }}.Server + {{- else }} server := {{ .ServerPackageAlias }}.NewServer(nil) - {{- else }} + {{- end }} +{{- else }} swaggerSpec, err := loads.Embedded({{ .ServerPackageAlias }}.SwaggerJSON, {{ .ServerPackageAlias }}.FlatSwaggerJSON) if err != nil { log.Fatalln(err) @@ -93,94 +132,34 @@ func main() { api := {{.APIPackageAlias}}.New{{ pascalize .Name }}API(swaggerSpec) server := {{ .ServerPackageAlias }}.NewServer(api) - defer server.Shutdown() - {{- end }} - - parser := flags.NewParser(server, flags.Default) - parser.ShortDescription = {{ if .Info }}{{ if .Info.Title }}{{ printf "%q" .Info.Title }}{{ else }}{{ if .ExcludeSpec }}""{{ else }}swaggerSpec.Spec().Info.Title{{ end }}{{ end }}{{ else }}{{ if .ExcludeSpec }}""{{ else }}swaggerSpec.Spec().Info.Title{{ end }}{{ end}} - parser.LongDescription = {{ if .Info }}{{ if .Info.Description }}{{ printf "%q" .Info.Description }}{{ else }}{{ if .ExcludeSpec }}""{{ else }}swaggerSpec.Spec().Info.Description{{ end }}{{ end }}{{ else }}{{ if .ExcludeSpec }}""{{ else }}swaggerSpec.Spec().Info.Description{{ end }}{{ end}} - - {{- if not .ExcludeSpec }} - server.ConfigureFlags() - for _, optsGroup := range api.CommandLineOptionsGroups { - _, err := parser.AddGroup(optsGroup.ShortDescription, optsGroup.LongDescription, optsGroup.Options) - if err != nil { - log.Fatalln(err) - } - } - {{- end }} - - if _, err := parser.Parse(); err != nil { - code := 1 - if fe, ok := err.(*flags.Error); ok { - if fe.Type == flags.ErrHelp { - code = 0 - } - } - os.Exit(code) - } - {{- if .ExcludeSpec }} - swaggerSpec, err := loads.Spec(string(server.Spec)) - if err != nil { - log.Fatalln(err) - } - - api := {{.APIPackageAlias}}.New{{ pascalize .Name }}API(swaggerSpec) - server.SetAPI(api) - defer server.Shutdown() - {{- end }} + server.ConfigureFlags() // inject API-specific custom flags. Must be called before args parsing +{{- end }} - server.ConfigureAPI() +{{ template "argsParser" . }} - if err := server.Serve(); err != nil { - log.Fatalln(err) - } - {{ end }} - {{ if .UseFlags}} - {{- if not .ExcludeSpec }} +{{- if .ExcludeSpec }}{{/* since the API is not loaded, we can't configure API-specific flags in this mode */}} + {{- if not .UseGoStructFlags }}{{/* with pflag and flag, args are retrieved using New */}} + server = {{ .ServerPackageAlias }}.NewServer(nil) // the server has no API set yet, but configuration from flags is retrieved at this point + {{- end }} - swaggerSpec, err := loads.Embedded({{ .ServerPackageAlias }}.SwaggerJSON, {{ .ServerPackageAlias }}.FlatSwaggerJSON) - if err != nil { - log.Fatalln(err) + // spec loaded at run time from the provided CLI flags + if server.Spec == "" { + log.Fatalln("a spec must be provided by the command line") } - {{- end }} - var server *{{ .ServerPackageAlias }}.Server // make sure init is called - flag.Usage = func() { - fmt.Fprint(os.Stderr, "Usage:\n") - fmt.Fprint(os.Stderr, " {{ dasherize .Name }}-server [OPTIONS]\n\n") - - title := {{ if .Info }}{{ if .Info.Title }}{{ printf "%q" .Info.Title }}{{ else }}{{ if .ExcludeSpec }}""{{ else }}swaggerSpec.Spec().Info.Title{{ end }}{{ end }}{{ else }}{{ if .ExcludeSpec }}""{{ else }}swaggerSpec.Spec().Info.Title{{ end }}{{ end}} - fmt.Fprint(os.Stderr, title+"\n\n") - desc := {{ if .Info }}{{ if .Info.Description }}{{ printf "%q" .Info.Description }}{{ else }}{{ if .ExcludeSpec }}""{{ else }}swaggerSpec.Spec().Info.Description{{ end }}{{ end }}{{ else }}{{ if .ExcludeSpec }}""{{ else }}swaggerSpec.Spec().Info.Description{{ end }}{{ end}} - if desc != "" { - fmt.Fprintf(os.Stderr, desc+"\n\n") - } - flag.CommandLine.SetOutput(os.Stderr) - flag.PrintDefaults() - } - // parse the CLI flags - flag.Parse() - - {{- if .ExcludeSpec }} - - server = {{ .ServerPackageAlias }}.NewServer(nil) - swaggerSpec, err := loads.Spec(string(server.Spec)) + swaggerSpec, err := loads.Spec({{ if .UseGoStructFlags }}string({{ end }}server.Spec{{ if .UseGoStructFlags }}){{ end }}) if err != nil { log.Fatalln(err) } api := {{.APIPackageAlias}}.New{{ pascalize .Name }}API(swaggerSpec) server.SetAPI(api) - {{- else }} - api := {{.APIPackageAlias}}.New{{ pascalize .Name }}API(swaggerSpec) - // get server with flag values filled out - server = {{ .ServerPackageAlias }}.NewServer(api) - {{- end }} - defer server.Shutdown() +{{- end }} + + server.ConfigureAPI() // configure handlers, routes and middleware - server.ConfigureAPI() if err := server.Serve(); err != nil { + _ = server.Shutdown() + log.Fatalln(err) } - {{ end }} } diff --git a/vendor/github.com/go-swagger/go-swagger/generator/templates/server/operation.gotmpl b/vendor/github.com/go-swagger/go-swagger/generator/templates/server/operation.gotmpl index 041c00e44..d01d59acb 100644 --- a/vendor/github.com/go-swagger/go-swagger/generator/templates/server/operation.gotmpl +++ b/vendor/github.com/go-swagger/go-swagger/generator/templates/server/operation.gotmpl @@ -11,6 +11,9 @@ package {{ .Package }} import ( "net/http" + {{- if .ExtraSchemas }} + stderrors "errors" + {{- end }} "github.com/go-openapi/errors" "github.com/go-openapi/runtime/middleware" @@ -24,16 +27,32 @@ import ( ) // {{ pascalize .Name }}HandlerFunc turns a function with the right signature into a {{ humanize .Name }} handler -type {{ pascalize .Name }}HandlerFunc func({{ pascalize .Name }}Params{{ if .Authorized }}, {{ if .PrincipalIsNullable }}*{{ end }}{{ .Principal }}{{ end }}) {{ if $.StrictResponders }} {{ pascalize .Name }}Responder {{else}} middleware.Responder {{end}} +type {{ pascalize .Name }}HandlerFunc func({{ pascalize .Name }}Params{{ if .Authorized }}, {{ if .PrincipalIsNullable }}*{{ end }}{{ .Principal }}{{ end }}) + {{- if $.ReturnErrors }} + {{- if $.StrictResponders }} ({{ pascalize .Name }}Responder, error) {{else}} (middleware.Responder, error) {{end}} + {{ else }} + {{- if $.StrictResponders }} {{ pascalize .Name }}Responder {{else}} middleware.Responder {{end}} + {{ end }} // Handle executing the request and returning a response -func (fn {{ pascalize .Name }}HandlerFunc) Handle(params {{ pascalize .Name }}Params{{ if .Authorized }}, principal {{ if .PrincipalIsNullable }}*{{ end }}{{ .Principal }}{{ end }}) {{ if $.StrictResponders }} {{ pascalize .Name }}Responder {{else}} middleware.Responder {{end}} { +func (fn {{ pascalize .Name }}HandlerFunc) Handle(params {{ pascalize .Name }}Params{{ if .Authorized }}, principal {{ if .PrincipalIsNullable }}*{{ end }}{{ .Principal }}{{ end }}) + {{- if $.ReturnErrors }} + {{- if $.StrictResponders }} ({{ pascalize .Name }}Responder, error) {{else}} (middleware.Responder, error) {{end}} { + {{ else }} + {{- if $.StrictResponders }} {{ pascalize .Name }}Responder {{else}} middleware.Responder {{end}} { + {{ end -}} + return fn(params{{ if .Authorized }}, principal{{ end }}) } // {{ pascalize .Name }}Handler interface for that can handle valid {{ humanize .Name }} params type {{ pascalize .Name }}Handler interface { - Handle({{ pascalize .Name }}Params{{ if .Authorized }}, {{ if .PrincipalIsNullable }}*{{ end }}{{ .Principal }}{{ end }}) {{ if $.StrictResponders }} {{ pascalize .Name }}Responder {{else}} middleware.Responder {{end}} + Handle({{ pascalize .Name }}Params{{ if .Authorized }}, {{ if .PrincipalIsNullable }}*{{ end }}{{ .Principal }}{{ end }}) + {{- if $.ReturnErrors }} + {{- if $.StrictResponders }} ({{ pascalize .Name }}Responder, error) {{else}} (middleware.Responder, error) {{end}} + {{ else }} + {{- if $.StrictResponders }} {{ pascalize .Name }}Responder {{else}} middleware.Responder {{end}} + {{ end }} } // New{{ pascalize .Name }} creates a new http.Handler for the {{ humanize .Name }} operation @@ -71,7 +90,7 @@ func ({{ .ReceiverName }} *{{ pascalize .Name }}) ServeHTTP(rw http.ResponseWrit } var principal {{ if .PrincipalIsNullable }}*{{ end }}{{ .Principal }} if uprinc != nil { - principal = {{ if eq .Principal "inferface{}" }}uprinc{{ else }}uprinc.({{ if .PrincipalIsNullable }}*{{ end }}{{ .Principal }}) // this is really a {{ .Principal }}, I promise{{ end }} + principal = {{ if or (eq .Principal "inferface{}") (eq .Principal "any") }}uprinc{{ else }}uprinc.({{ if .PrincipalIsNullable }}*{{ end }}{{ .Principal }}) // this is really a {{ .Principal }}, I promise{{ end }} } {{ end }} if err := {{ .ReceiverName }}.Context.BindValidRequest(r, route, &Params); err != nil { // bind params @@ -79,7 +98,16 @@ func ({{ .ReceiverName }} *{{ pascalize .Name }}) ServeHTTP(rw http.ResponseWrit return } - res := {{ .ReceiverName }}.Handler.Handle(Params{{ if .Authorized }}, principal{{ end }}) // actually handle the request + {{ if $.ReturnErrors }} + res, err := {{ .ReceiverName }}.Handler.Handle(Params{{ if .Authorized }}, principal{{ end }}) // actually handle the request + if err != nil { + {{ .ReceiverName }}.Context.Respond(rw, r, route.Produces, route, err) + return + } + {{ else }} + res := {{ .ReceiverName }}.Handler.Handle(Params{{ if .Authorized }}, principal{{ end }}) // actually handle the request + {{ end }} + {{ .ReceiverName }}.Context.Respond(rw, r, route.Produces, route, res) } diff --git a/vendor/github.com/go-swagger/go-swagger/generator/templates/server/parameter.gotmpl b/vendor/github.com/go-swagger/go-swagger/generator/templates/server/parameter.gotmpl index 1000a9f95..08f9e515c 100644 --- a/vendor/github.com/go-swagger/go-swagger/generator/templates/server/parameter.gotmpl +++ b/vendor/github.com/go-swagger/go-swagger/generator/templates/server/parameter.gotmpl @@ -161,7 +161,7 @@ if err := validate.EnumCase( {{- .ValueExpression -}}{{- if .Child.IsCustomFormatter }}.String(){{ end -}} {{- end -}} {{- end -}}, - {{- printf "%#v" .Enum -}}, {{ if .IsEnumCI }}false{{ else }}true{{ end }}); err != nil { + {{- printGoLiteral .Enum -}}, {{ if .IsEnumCI }}false{{ else }}true{{ end }}); err != nil { return err } {{- end }} @@ -186,11 +186,15 @@ if err := validate.EnumCase( {{- else if and .IsComplexObject .HasValidations }}{{/* dedicated to nested body params */}} {{ varname .ValueExpression }} := {{ varname .ValueExpression }}V if err := {{ .ValueExpression }}.Validate(formats) ; err != nil { - if ve, ok := err.(*errors.Validation); ok { - return ve.ValidateName({{ .Path }}) - } else if ce, ok := err.(*errors.CompositeError); ok { - return ce.ValidateName({{ .Path }}) + ve := new(errors.Validation) + if stderrors.As(err, &ve) { + return ve.ValidateName({{ path . }}) } + ce := new(errors.CompositeError) + if stderrors.As(err, &ce) { + return ce.ValidateName({{ path . }}) + } + return err } {{- else }} @@ -298,6 +302,7 @@ package {{ .Package }} // Editing this file might prove futile when you re-run the swagger generate command import ( + stderrors "errors" "fmt" "io" "net/http" @@ -339,15 +344,15 @@ func New{{ pascalize .Name }}Params() {{ pascalize .Name }}Params { {{ if .HasDefault -}} {{ if not .IsFileParam }}{{ varname .ID}}Default = {{- if and .IsPrimitive .IsCustomFormatter (not (stringContains .Zero "(\"" )) }}{{ .Zero }}{{/* strfmt type initializer requires UnmarshalText(), e.g. Date, Datetime, Duration */}} - {{- else if and .IsPrimitive .IsCustomFormatter (stringContains .Zero "(\"" ) }}{{.GoType}}({{- printf "%#v" .Default }}){{/* strfmt type initializer takes string */}} - {{- else if and .IsPrimitive (not .IsCustomFormatter) -}}{{.GoType}}({{- printf "%#v" .Default }}){{/* regular go primitive type initializer */}} + {{- else if and .IsPrimitive .IsCustomFormatter (stringContains .Zero "(\"" ) }}{{.GoType}}({{- printGoLiteral .Default }}){{/* strfmt type initializer takes string */}} + {{- else if and .IsPrimitive (not .IsCustomFormatter) -}}{{.GoType}}({{- printGoLiteral .Default }}){{/* regular go primitive type initializer */}} {{- else if .IsArray -}}{{- /* Do not initialize from possible defaults in nested arrays */ -}} {{- if and .Child.IsPrimitive .Child.IsCustomFormatter }}{{ .Zero }}{{/* initialization strategy with UnmarshalText() */}} {{- else if .Child.IsArray -}}{{ .Zero }}{{/* initialization strategy with json.Unmarshal() */}} {{- else if and .Child.IsPrimitive (not .Child.IsCustomFormatter) -}}{{.GoType}}{{- arrayInitializer .Default }}{{/* regular go primitive type initializer: simple slice initializer */}} - {{- else }}{{ printf "%#v" .Default }}{{/* all other cases (e.g. schema) [should not occur] */}} + {{- else }}{{ printGoLiteral .Default }}{{/* all other cases (e.g. schema) [should not occur] */}} {{- end }} - {{- else }}{{ printf "%#v" .Default }}{{/* case .Schema */}} + {{- else }}{{ printGoLiteral .Default }}{{/* case .Schema */}} {{- end }} {{- end }} {{- end }} @@ -378,11 +383,11 @@ func New{{ pascalize .Name }}Params() {{ pascalize .Name }}Params { // // swagger:parameters {{ .Name }} type {{ pascalize .Name }}Params struct { - // HTTP Request Object HTTPRequest *http.Request `json:"-"` + {{- range .Params }} - {{ range .Params }}/*{{ if .Description }}{{ blockcomment .Description }}{{ end }}{{ if .Required }} + /*{{ if .Description }}{{ blockcomment .Description }}{{ end }}{{ if .Required }} Required: true{{ end }}{{ if .Maximum }} Maximum: {{ if .ExclusiveMaximum }}< {{ end }}{{ .Maximum }}{{ end }}{{ if .Minimum }} Minimum: {{ if .ExclusiveMinimum }}> {{ end }}{{ .Minimum }}{{ end }}{{ if .MultipleOf }} @@ -395,10 +400,10 @@ type {{ pascalize .Name }}Params struct { Unique: true{{ end }}{{ if .Location }} In: {{ .Location }}{{ end }}{{ if .CollectionFormat }} Collection Format: {{ .CollectionFormat }}{{ end }}{{ if .HasDefault }} - Default: {{ printf "%#v" .Default }}{{ end }} + Default: {{ printGoLiteral .Default }}{{ end }} */ {{ if not .Schema }}{{ pascalize .ID }} {{ if and (not .IsArray) (not .HasDiscriminator) (not .IsInterface) (not .IsStream) .IsNullable }}*{{ end }}{{.GoType}}{{ else }}{{ pascalize .Name }} {{ if and (not .Schema.IsBaseType) .IsNullable (not .Schema.IsStream) }}*{{ end }}{{.GoType}}{{ end }} - {{ end}} + {{- end}} } // BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface @@ -409,19 +414,16 @@ func ({{ .ReceiverName }} *{{ pascalize .Name }}Params) BindRequest(r *http.Requ var res []error {{ .ReceiverName }}.HTTPRequest = r - {{- if .HasQueryParams }} - qs := runtime.Values(r.URL.Query()) {{- end }} - {{- if .HasFormParams }} if err := r.ParseMultipartForm({{ pascalize .Name }}MaxParseMemory); err != nil { - if err != http.ErrNotMultipart { - return errors.New(400,"%v",err) - } else if err := r.ParseForm(); err != nil { + if !stderrors.Is(err,http.ErrNotMultipart) { return errors.New(400,"%v",err) + } else if errParse := r.ParseForm(); errParse != nil { + return errors.New(400,"%v",errParse) } } {{- if .HasFormValueParams }} @@ -451,19 +453,24 @@ func ({{ .ReceiverName }} *{{ pascalize .Name }}Params) BindRequest(r *http.Requ {{- if .IsFileParam }} {{ camelize .Name }}, {{ camelize .Name }}Header, err := r.FormFile({{ .Path }}) - if err != nil {{ if .IsNullable }}&& err != http.ErrMissingFile{{ end }}{ - res = append(res, errors.New(400, "reading file %q failed: %v", {{ printf "%q" (camelize .Name) }}, err)) + if err != nil { {{- if .IsNullable }} - } else if err == http.ErrMissingFile { - // no-op for missing but optional file parameter + if !stderrors.Is(err, http.ErrMissingFile) { + res = append(res, errors.New(400, "reading file %q failed: %v", {{ printf "%q" (camelize .Name) }}, err)) + } + // no-op for missing but optional file parameter + {{- else }} + res = append(res, errors.New(400, "reading file %q failed: %v", {{ printf "%q" (camelize .Name) }}, err)) {{- end }} - } else if err := {{ .ReceiverName }}.bind{{ pascalize .ID }}({{ camelize .Name }}, {{ camelize .Name }}Header); err != nil { + } else { + if errBind := {{ .ReceiverName }}.bind{{ pascalize .ID }}({{ camelize .Name }}, {{ camelize .Name }}Header); errBind != nil { {{- if .Required }} - // Required: true + // Required: true {{- end }} - res = append(res, err) - } else { - {{ .ReceiverName }}.{{ pascalize .Name }} = &runtime.File{Data: {{ camelize .Name }}, Header: {{ camelize .Name }}Header} + res = append(res, errBind) + } else { + {{ .ReceiverName }}.{{ pascalize .Name }} = &runtime.File{Data: {{ camelize .Name }}, Header: {{ camelize .Name }}Header} + } } {{- else }} @@ -506,12 +513,14 @@ func ({{ .ReceiverName }} *{{ pascalize .Name }}Params) BindRequest(r *http.Requ {{- if .Schema.IsStream }} {{ .ReceiverName }}.{{ pascalize .Name }} = r.Body {{- else }} - defer r.Body.Close() + defer func() { + _ = r.Body.Close() + }() {{- if and .Schema.IsBaseType .Schema.IsExported }} body, err := {{ toPackageName .ModelsPackage }}.Unmarshal{{ dropPackage .GoType }}{{ if .IsArray }}Slice{{ end }}(r.Body, route.Consumer) if err != nil { {{- if .Required }} - if err == io.EOF { + if stderrors.Is(err,io.EOF) { err = errors.Required({{ .Path }}, {{ printf "%q" .Location }}, "") } {{- end }} @@ -520,7 +529,7 @@ func ({{ .ReceiverName }} *{{ pascalize .Name }}Params) BindRequest(r *http.Requ var body {{ .GoType }} if err := route.Consumer.Consume(r.Body, &body); err != nil { {{- if .Required }} - if err == io.EOF { + if stderrors.Is(err,io.EOF) { res = append(res, errors.Required({{ printf "%q" (camelize .Name) }}, {{ printf "%q" .Location }}, "")) } else { {{- end }} @@ -683,7 +692,7 @@ func ({{ .ReceiverName }} *{{ $className }}Params) bind{{ pascalize .ID }}(rawDa {{- if or (and (not .IsArray) .HasValidations) (and .IsArray .HasSliceValidations) }} -// validate{{ pascalize .ID }} carries on validations for parameter {{ .ID }} +// validate{{ pascalize .ID }} carries out validations for parameter {{ .ID }} func ({{ .ReceiverName }} *{{ $className }}Params) validate{{ pascalize .ID }}(formats strfmt.Registry) error { {{ template "propertyparamvalidator" . }} return nil diff --git a/vendor/github.com/go-swagger/go-swagger/generator/templates/server/responses.gotmpl b/vendor/github.com/go-swagger/go-swagger/generator/templates/server/responses.gotmpl index 1d844a890..39b3bea96 100644 --- a/vendor/github.com/go-swagger/go-swagger/generator/templates/server/responses.gotmpl +++ b/vendor/github.com/go-swagger/go-swagger/generator/templates/server/responses.gotmpl @@ -71,7 +71,7 @@ type {{ pascalize .Name }} struct { Max Items: {{ .MaxItems }}{{ end }}{{ if .MinItems }} Min Items: {{ .MinItems }}{{ end }}{{ if .UniqueItems }} Unique: true{{ end }}{{ if .HasDefault }} - Default: {{ printf "%#v" .Default }}{{ end }} + Default: {{ printGoLiteral .Default }}{{ end }} */ {{ pascalize .Name }} {{ .GoType }} `json:"{{.Name}}{{ if not .Required }},omitempty{{ end }}{{ if .IsJSONString }},string{{ end }}"` {{ end }} @@ -105,15 +105,15 @@ if code <= 0 { {{ if .HasDefault -}} {{ varname .ID}}Default = {{- if and .IsPrimitive .IsCustomFormatter (not (stringContains .Zero "(\"" )) }}{{ .Zero }}{{/* strfmt type initializer requires UnmarshalText(), e.g. Date, Datetime, Duration */}} - {{- else if and .IsPrimitive .IsCustomFormatter (stringContains .Zero "(\"" ) }}{{.GoType}}({{- printf "%#v" .Default }}){{/* strfmt type initializer takes string */}} - {{- else if and .IsPrimitive (not .IsCustomFormatter) -}}{{.GoType}}({{- printf "%#v" .Default }}){{/* regular go primitive type initializer */}} + {{- else if and .IsPrimitive .IsCustomFormatter (stringContains .Zero "(\"" ) }}{{.GoType}}({{- printGoLiteral .Default }}){{/* strfmt type initializer takes string */}} + {{- else if and .IsPrimitive (not .IsCustomFormatter) -}}{{.GoType}}({{- printGoLiteral .Default }}){{/* regular go primitive type initializer */}} {{- else if .IsArray -}}{{- /* Do not initialize from possible defaults in nested arrays */ -}} {{- if and .Child.IsPrimitive .Child.IsCustomFormatter }}{{ .Zero }}{{/* initialization strategy with UnmarshalText() */}} {{- else if .Child.IsArray -}}{{ .Zero }}{{/* initialization strategy with json.Unmarshal() */}} {{- else if and .Child.IsPrimitive (not .Child.IsCustomFormatter) -}}{{.GoType}}{{- arrayInitializer .Default }}{{/* regular go primitive type initializer: simple slice initializer */}} - {{- else }}{{ printf "%#v" .Default }}{{/* all other cases (e.g. schema) [should not occur] */}} + {{- else }}{{ printGoLiteral .Default }}{{/* all other cases (e.g. schema) [should not occur] */}} {{- end }} - {{- else }}{{ printf "%#v" .Default }}{{/* case .Schema */}} + {{- else }}{{ printGoLiteral .Default }}{{/* case .Schema */}} {{- end }} {{- end }} {{- end }} @@ -184,7 +184,7 @@ func ({{ .ReceiverName }} *{{ pascalize .Name }}) WriteResponse(rw http.Response {{ template "serverheaderbuilder" . -}} {{ end }} {{ if not .Schema }} - rw.Header().Del(runtime.HeaderContentType) //Remove Content-Type on empty responses + rw.Header().Del(runtime.HeaderContentType) // Remove Content-Type on empty responses {{ end }} rw.WriteHeader({{ if eq .Code -1 }}{{ .ReceiverName }}._statusCode{{ else }}{{ .Code }}{{ end }}) {{- if .Schema }} diff --git a/vendor/github.com/go-swagger/go-swagger/generator/templates/server/server.gotmpl b/vendor/github.com/go-swagger/go-swagger/generator/templates/server/server.gotmpl index ccbc520b0..db60ba325 100644 --- a/vendor/github.com/go-swagger/go-swagger/generator/templates/server/server.gotmpl +++ b/vendor/github.com/go-swagger/go-swagger/generator/templates/server/server.gotmpl @@ -56,9 +56,11 @@ func init() { } {{ if not .UseGoStructFlags}} -var ({{ if .ExcludeSpec }} +var ( + {{- if .ExcludeSpec }} specFile string - {{ end }}enabledListeners []string + {{- end }} + enabledListeners []string cleanupTimeout time.Duration gracefulTimeout time.Duration maxHeaderSize flagext.ByteSize @@ -83,7 +85,7 @@ var ({{ if .ExcludeSpec }} tlsCACertificate string ) -{{ if .UseFlags}} + {{ if .UseFlags}} // StringSliceVar support for flag type sliceValue []string @@ -97,22 +99,22 @@ func (s *sliceValue) Set(val string) error { return nil } -func (s *sliceValue) Get() interface{} { return []string(*s) } +func (s *sliceValue) Get() any { return []string(*s) } func (s *sliceValue) String() string { return strings.Join([]string(*s), ",") } // end StringSliceVar support for flag -{{ end }} + {{- end }} func init() { - maxHeaderSize = flagext.ByteSize(1000000){{ if .ExcludeSpec }} - flag.StringVarP(&specFile, "spec", "", "", "the swagger specification to serve") - {{ end }} - {{ if .UseFlags }} - flag.Var(newSliceValue(defaultSchemes, &enabledListeners), "schema", "the listeners to enable, this can be repeated and defaults to the schemes in the swagger spec") - {{ end }} - {{ if .UsePFlags }} + maxHeaderSize = flagext.ByteSize(1000000) + {{- if .ExcludeSpec }} + flag.StringVar(&specFile, "spec", "", "the swagger specification to serve") + {{- end }} + {{- if .UseFlags }} + flag.Var(newSliceValue(defaultSchemes, &enabledListeners), "scheme", "the listeners to enable, this can be repeated and defaults to the schemes in the swagger spec") + {{- else if .UsePFlags }} flag.StringSliceVar(&enabledListeners, "scheme", defaultSchemes, "the listeners to enable, this can be repeated and defaults to the schemes in the swagger spec") - {{ end }} + {{- end }} flag.DurationVar(&cleanupTimeout, "cleanup-timeout", 10*time.Second, "grace period for which to wait before killing idle connections") flag.DurationVar(&gracefulTimeout, "graceful-timeout", 15*time.Second, "grace period for which to wait before shutting down the server") flag.Var(&maxHeaderSize, "max-header-size", "controls the maximum number of bytes the server will read parsing the request header's keys and values, including the request line. It does not limit the size of the request body") @@ -165,7 +167,7 @@ func intEnvOverride(orig int, def int, keys ...string) int { } return orig } -{{ end }} +{{- end }} // NewServer creates a new api {{ humanize .Name }} server but does not configure it func NewServer(api *{{ .APIPackageAlias }}.{{ pascalize .Name }}API) *Server { @@ -192,7 +194,7 @@ func NewServer(api *{{ .APIPackageAlias }}.{{ pascalize .Name }}API) *Server { s.TLSReadTimeout = tlsReadTimeout s.TLSWriteTimeout = tlsWriteTimeout {{- if .ExcludeSpec }} - s.Spec = specFile + s.Spec = specFile {{- end }} {{- end }} s.shutdown = make(chan struct{}) @@ -255,7 +257,7 @@ type Server struct { } // Logf logs message either via defined user logger or via system one if no user logger is defined. -func (s *Server) Logf(f string, args ...interface{}) { +func (s *Server) Logf(f string, args ...any) { if s.api != nil && s.api.Logger != nil { s.api.Logger(f, args...) } else { @@ -265,7 +267,7 @@ func (s *Server) Logf(f string, args ...interface{}) { // Fatalf logs message either via defined user logger or via system one if no user logger is defined. // Exits with non-zero status after printing -func (s *Server) Fatalf(f string, args ...interface{}) { +func (s *Server) Fatalf(f string, args ...any) { if s.api != nil && s.api.Logger != nil { s.api.Logger(f, args...) os.Exit(1) @@ -332,15 +334,15 @@ func (s *Server) Serve() (err error) { domainSocket.IdleTimeout = s.CleanupTimeout } - configureServer(domainSocket, "unix", string(s.SocketPath)) + configureServer(domainSocket, "unix", {{ if .UseGoStructFlags }}string({{ end }}s.SocketPath{{ if .UseGoStructFlags }}){{ end }}) servers = append(servers, domainSocket) wg.Add(1) s.Logf("Serving {{ humanize .Name }} at unix://%s", s.SocketPath) go func(l net.Listener){ defer wg.Done() - if err := domainSocket.Serve(l); err != nil && err != http.ErrServerClosed { - s.Fatalf("%v", err) + if errServe := domainSocket.Serve(l); errServe != nil && !errors.Is(errServe,http.ErrServerClosed) { + s.Fatalf("%v", errServe) } s.Logf("Stopped serving {{ humanize .Name }} at unix://%s", s.SocketPath) }(s.domainSocketL) @@ -369,8 +371,8 @@ func (s *Server) Serve() (err error) { s.Logf("Serving {{ humanize .Name }} at http://%s", s.httpServerL.Addr()) go func(l net.Listener) { defer wg.Done() - if err := httpServer.Serve(l); err != nil && err != http.ErrServerClosed { - s.Fatalf("%v", err) + if errServe := httpServer.Serve(l); errServe != nil && !errors.Is(errServe,http.ErrServerClosed) { + s.Fatalf("%v", errServe) } s.Logf("Stopped serving {{ humanize .Name }} at http://%s", l.Addr()) }(s.httpServerL) @@ -433,7 +435,7 @@ func (s *Server) Serve() (err error) { caCertPool := x509.NewCertPool() ok := caCertPool.AppendCertsFromPEM(caCert) if !ok { - return fmt.Errorf("cannot parse CA certificate") + return errors.New("cannot parse CA certificate") } httpsServer.TLSConfig.ClientCAs = caCertPool httpsServer.TLSConfig.ClientAuth = tls.RequireAndVerifyClientCert @@ -464,8 +466,8 @@ func (s *Server) Serve() (err error) { s.Logf("Serving {{ humanize .Name }} at https://%s", s.httpsServerL.Addr()) go func(l net.Listener) { defer wg.Done() - if err := httpsServer.Serve(l); err != nil && err != http.ErrServerClosed { - s.Fatalf("%v", err) + if errServe := httpsServer.Serve(l); errServe != nil && !errors.Is(errServe,http.ErrServerClosed) { + s.Fatalf("%v", errServe) } s.Logf("Stopped serving {{ humanize .Name }} at https://%s", l.Addr()) }(tls.NewListener(s.httpsServerL, httpsServer.TLSConfig)) @@ -508,7 +510,7 @@ func (s *Server) Listen() error { } if s.hasScheme(schemeUnix) { - domSockListener, err := net.Listen("unix", string(s.SocketPath)) + domSockListener, err := net.Listen("unix", {{ if .UseGoStructFlags }}string({{ end }}s.SocketPath{{ if .UseGoStructFlags }}){{ end }}) if err != nil { return err } diff --git a/vendor/github.com/go-swagger/go-swagger/generator/templates/server/urlbuilder.gotmpl b/vendor/github.com/go-swagger/go-swagger/generator/templates/server/urlbuilder.gotmpl index 5d6010c0c..31ed0fd84 100644 --- a/vendor/github.com/go-swagger/go-swagger/generator/templates/server/urlbuilder.gotmpl +++ b/vendor/github.com/go-swagger/go-swagger/generator/templates/server/urlbuilder.gotmpl @@ -67,7 +67,7 @@ for _, {{ .Child.ValueExpression }} := range {{ .ValueExpression }} { if len({{ varname .ID }}) > 0 { psv := {{ varname .ID }}[0] if psv != "" { - _path = strings.Replace(_path, "{{ printf "{%s}" .Name }}", psv, -1) + _path = strings.ReplaceAll(_path, "{{ printf "{%s}" .Name }}", psv) } else { return nil, errors.New("{{ camelize .ID }} is required on {{ pascalize $.Name }}URL") } @@ -147,7 +147,7 @@ func ({{ .ReceiverName }} *{{ pascalize .Name }}URL) Build() (*url.URL, error) { {{ else }} {{ varname .ID }} := {{ if .Formatter }}{{ .Formatter }}({{ .ReceiverName }}.{{ pascalize .ID }}){{ else }}{{ .ReceiverName }}.{{ pascalize .ID }}{{ if .IsCustomFormatter }}.String(){{end}}{{end}} if {{ varname .ID }} != "" { - _path = strings.Replace(_path, "{{ printf "{%s}" .Name }}", {{ varname .ID }}, -1) + _path = strings.ReplaceAll(_path, "{{ printf "{%s}" .Name }}", {{ varname .ID }}) } else { return nil, errors.New("{{ camelize .ID }} is required on {{ pascalize $.Name }}URL") } diff --git a/vendor/github.com/go-swagger/go-swagger/generator/templates/simpleschema/defaultsvar.gotmpl b/vendor/github.com/go-swagger/go-swagger/generator/templates/simpleschema/defaultsvar.gotmpl index cfb9f80e6..44aaf0e56 100644 --- a/vendor/github.com/go-swagger/go-swagger/generator/templates/simpleschema/defaultsvar.gotmpl +++ b/vendor/github.com/go-swagger/go-swagger/generator/templates/simpleschema/defaultsvar.gotmpl @@ -3,12 +3,12 @@ {{- print " " }}={{ print " " }} {{- if .IsCustomFormatter }} {{- if stringContains .Zero "(\"" }} - {{- .GoType }}({{ printf "%#v" .Default }}){{/* strfmt type initializer that takes string */}} + {{- .GoType }}({{ printGoLiteral .Default }}){{/* strfmt type initializer that takes string */}} {{- else }} {{- .Zero }}{{/* strfmt type initializer that requires UnmarshalText(), e.g. Date, Datetime, Duration */}} {{- end }} {{- else }} - {{- .GoType }}({{ printf "%#v" .Default }}){{/* regular go primitive type initializer */}} + {{- .GoType }}({{ printGoLiteral .Default }}){{/* regular go primitive type initializer */}} {{- end }} {{- else if .IsArray }}{{/* do not initialize from possible defaults in nested arrays */}} {{- if .Child.IsPrimitive }} diff --git a/vendor/github.com/go-swagger/go-swagger/generator/templates/validation/primitive.gotmpl b/vendor/github.com/go-swagger/go-swagger/generator/templates/validation/primitive.gotmpl index 8dbf79643..c90fff607 100644 --- a/vendor/github.com/go-swagger/go-swagger/generator/templates/validation/primitive.gotmpl +++ b/vendor/github.com/go-swagger/go-swagger/generator/templates/validation/primitive.gotmpl @@ -23,7 +23,7 @@ if err := validate.Pattern({{ path . }}, {{ printf "%q" .Location }}, {{ .ToStri {{ template "validationMultipleOf" . }} {{end}} {{if .Enum}} -if err := validate.EnumCase({{ path . }}, {{ printf "%q" .Location }}, {{ if and (not .IsArray) (not .HasDiscriminator) (not .IsInterface) .IsNullable }}*{{ end }}{{.ValueExpression}}{{ if .IsCustomFormatter }}.String(){{ end }}, {{ printf "%#v" .Enum}}, {{ if .IsEnumCI }}false{{ else }}true{{ end }}); err != nil { +if err := validate.EnumCase({{ path . }}, {{ printf "%q" .Location }}, {{ if and (not .IsArray) (not .HasDiscriminator) (not .IsInterface) .IsNullable }}*{{ end }}{{.ValueExpression}}{{ if .IsCustomFormatter }}.String(){{ end }}, {{ printGoLiteral .Enum}}, {{ if .IsEnumCI }}false{{ else }}true{{ end }}); err != nil { return err } {{end}} diff --git a/vendor/github.com/go-swagger/go-swagger/generator/types.go b/vendor/github.com/go-swagger/go-swagger/generator/types.go index 59057ca8c..7995a957b 100644 --- a/vendor/github.com/go-swagger/go-swagger/generator/types.go +++ b/vendor/github.com/go-swagger/go-swagger/generator/types.go @@ -21,15 +21,16 @@ import ( "reflect" "strings" + "github.com/go-viper/mapstructure/v2" + "github.com/kr/pretty" + "github.com/go-openapi/loads" "github.com/go-openapi/spec" "github.com/go-openapi/swag" - "github.com/go-viper/mapstructure/v2" - "github.com/kr/pretty" ) const ( - iface = "interface{}" + iface = "any" array = "array" file = "file" number = "number" @@ -142,7 +143,7 @@ func newTypeResolver(pkg, _ string, doc *loads.Document) *typeResolver { } // knownDefGoType returns go type, package and package alias for definition -func (t typeResolver) knownDefGoType(def string, schema spec.Schema, clear func(string) string) (string, string, string) { +func (t typeResolver) knownDefGoType(def string, schema spec.Schema, clearFunc func(string) string) (string, string, string) { debugLog("known def type: %q", def) ext := schema.Extensions nm, hasGoName := ext.GetString(xGoName) @@ -153,12 +154,12 @@ func (t typeResolver) knownDefGoType(def string, schema spec.Schema, clear func( } extType, isExternalType := t.resolveExternalType(ext) if !isExternalType || extType.Embedded { - if clear == nil { + if clearFunc == nil { debugLog("known def type no clear: %q", def) return def, t.definitionPkg, "" } - debugLog("known def type clear: %q -> %q", def, clear(def)) - return clear(def), t.definitionPkg, "" + debugLog("known def type clear: %q -> %q", def, clearFunc(def)) + return clearFunc(def), t.definitionPkg, "" } // external type definition trumps regular type resolution @@ -467,6 +468,7 @@ func (t *typeResolver) resolveArray(schema *spec.Schema, isAnonymous, isRequired return } + // resolve anonymous items rt, er := t.ResolveSchema(schema.Items.Schema, true, false) if er != nil { err = er @@ -646,16 +648,16 @@ func (t *typeResolver) resolveObject(schema *spec.Schema, isAnonymous bool) (res return } - // an object without property and without AdditionalProperties schema is rendered as interface{} + // an object without property and without AdditionalProperties schema is rendered as any result.IsMap = true result.SwaggerType = object result.IsNullable = false - // an object without properties but with MinProperties or MaxProperties is rendered as map[string]interface{} + // an object without properties but with MinProperties or MaxProperties is rendered as map[string]any result.IsInterface = len(schema.Properties) == 0 && !schema.Validations().HasObjectValidations() if result.IsInterface { result.GoType = iface } else { - result.GoType = "map[string]interface{}" + result.GoType = "map[string]any" } return } @@ -697,7 +699,7 @@ func nullableNumber(schema *spec.Schema, isRequired bool) bool { isMinMax := (schema.Minimum != nil && schema.Maximum != nil && *schema.Minimum < *schema.Maximum) bcMinMax := (schema.Minimum != nil && schema.Maximum != nil && (*schema.Minimum < 0 && 0 < *schema.Maximum)) - nullable := !schema.ReadOnly && (isRequired || (hasDefault && !(isMin || isMax || isMinMax)) || bcMin || bcMax || bcMinMax) + nullable := !schema.ReadOnly && (isRequired || (hasDefault && !isMin && !isMax && !isMinMax) || bcMin || bcMax || bcMinMax) return nullable } @@ -963,7 +965,7 @@ func (t *typeResolver) ResolveSchema(schema *spec.Schema, isAnonymous, isRequire case "null": if schema.Validations().HasObjectValidations() { // no explicit object type, but inferred from object validations: - // this makes the type a map[string]interface{} instead of interface{} + // this makes the type a map[string]any instead of any result, err = t.resolveObject(schema, isAnonymous) if err != nil { result = resolvedType{} @@ -985,8 +987,8 @@ func (t *typeResolver) ResolveSchema(schema *spec.Schema, isAnonymous, isRequire return } -func warnSkipValidation(types interface{}) func(string, interface{}) { - return func(validation string, value interface{}) { +func warnSkipValidation(types any) func(string, any) { + return func(validation string, value any) { value = reflect.Indirect(reflect.ValueOf(value)).Interface() log.Printf("warning: validation %s (value: %v) not compatible with type %v. Skipped", validation, value, types) } @@ -1036,7 +1038,7 @@ func guardValidations(tpe string, schema interface { } } - // other cases: mapped as interface{}: no validations allowed but Enum + // other cases: mapped as any: no validations allowed but Enum } // guardFormatConflicts handles all conflicting properties diff --git a/vendor/github.com/huandu/xstrings/README.md b/vendor/github.com/huandu/xstrings/README.md index 750c3c7eb..e809c79ab 100644 --- a/vendor/github.com/huandu/xstrings/README.md +++ b/vendor/github.com/huandu/xstrings/README.md @@ -39,8 +39,8 @@ _Keep this table sorted by Function in ascending order._ | [Count](https://godoc.org/github.com/huandu/xstrings#Count) | `String#count` in Ruby | [#16](https://github.com/huandu/xstrings/issues/16) | | [Delete](https://godoc.org/github.com/huandu/xstrings#Delete) | `String#delete` in Ruby | [#17](https://github.com/huandu/xstrings/issues/17) | | [ExpandTabs](https://godoc.org/github.com/huandu/xstrings#ExpandTabs) | `str.expandtabs` in Python | [#27](https://github.com/huandu/xstrings/issues/27) | -| [FirstRuneToLower](https://godoc.org/github.com/huandu/xstrings#FirstRuneToLower) | `lcfirst` in PHP or Perl | [#15](https://github.com/huandu/xstrings/issues/15) | -| [FirstRuneToUpper](https://godoc.org/github.com/huandu/xstrings#FirstRuneToUpper) | `String#capitalize` in Ruby; `ucfirst` in PHP or Perl | [#15](https://github.com/huandu/xstrings/issues/15) | +| [FirstRuneToLower](https://godoc.org/github.com/huandu/xstrings#FirstRuneToLower) | `lcfirst` in PHP or Perl | [#15](https://github.com/huandu/xstrings/issues/15) | +| [FirstRuneToUpper](https://godoc.org/github.com/huandu/xstrings#FirstRuneToUpper) | `String#capitalize` in Ruby; `ucfirst` in PHP or Perl | [#15](https://github.com/huandu/xstrings/issues/15) | | [Insert](https://godoc.org/github.com/huandu/xstrings#Insert) | `String#insert` in Ruby | [#18](https://github.com/huandu/xstrings/issues/18) | | [LastPartition](https://godoc.org/github.com/huandu/xstrings#LastPartition) | `str.rpartition` in Python; `String#rpartition` in Ruby | [#19](https://github.com/huandu/xstrings/issues/19) | | [LeftJustify](https://godoc.org/github.com/huandu/xstrings#LeftJustify) | `str.ljust` in Python; `String#ljust` in Ruby | [#28](https://github.com/huandu/xstrings/issues/28) | @@ -50,14 +50,15 @@ _Keep this table sorted by Function in ascending order._ | [RightJustify](https://godoc.org/github.com/huandu/xstrings#RightJustify) | `str.rjust` in Python; `String#rjust` in Ruby | [#29](https://github.com/huandu/xstrings/issues/29) | | [RuneWidth](https://godoc.org/github.com/huandu/xstrings#RuneWidth) | - | [#27](https://github.com/huandu/xstrings/issues/27) | | [Scrub](https://godoc.org/github.com/huandu/xstrings#Scrub) | `String#scrub` in Ruby | [#20](https://github.com/huandu/xstrings/issues/20) | -| [Shuffle](https://godoc.org/github.com/huandu/xstrings#Shuffle) | `str_shuffle` in PHP | [#13](https://github.com/huandu/xstrings/issues/13) | -| [ShuffleSource](https://godoc.org/github.com/huandu/xstrings#ShuffleSource) | `str_shuffle` in PHP | [#13](https://github.com/huandu/xstrings/issues/13) | +| [Shuffle](https://godoc.org/github.com/huandu/xstrings#Shuffle) | `str_shuffle` in PHP | [#13](https://github.com/huandu/xstrings/issues/13) | +| [ShuffleSource](https://godoc.org/github.com/huandu/xstrings#ShuffleSource) | `str_shuffle` in PHP | [#13](https://github.com/huandu/xstrings/issues/13) | | [Slice](https://godoc.org/github.com/huandu/xstrings#Slice) | `mb_substr` in PHP | [#9](https://github.com/huandu/xstrings/issues/9) | | [Squeeze](https://godoc.org/github.com/huandu/xstrings#Squeeze) | `String#squeeze` in Ruby | [#11](https://github.com/huandu/xstrings/issues/11) | | [Successor](https://godoc.org/github.com/huandu/xstrings#Successor) | `String#succ` or `String#next` in Ruby | [#22](https://github.com/huandu/xstrings/issues/22) | | [SwapCase](https://godoc.org/github.com/huandu/xstrings#SwapCase) | `str.swapcase` in Python; `String#swapcase` in Ruby | [#12](https://github.com/huandu/xstrings/issues/12) | | [ToCamelCase](https://godoc.org/github.com/huandu/xstrings#ToCamelCase) | `String#camelize` in RoR | [#1](https://github.com/huandu/xstrings/issues/1) | | [ToKebab](https://godoc.org/github.com/huandu/xstrings#ToKebabCase) | - | [#41](https://github.com/huandu/xstrings/issues/41) | +| [ToPascalCase](https://godoc.org/github.com/huandu/xstrings#ToPascalCase) | - | [#1](https://github.com/huandu/xstrings/issues/1) | | [ToSnakeCase](https://godoc.org/github.com/huandu/xstrings#ToSnakeCase) | `String#underscore` in RoR | [#1](https://github.com/huandu/xstrings/issues/1) | | [Translate](https://godoc.org/github.com/huandu/xstrings#Translate) | `str.translate` in Python; `String#tr` in Ruby; `strtr` in PHP; `tr///` in Perl | [#21](https://github.com/huandu/xstrings/issues/21) | | [Width](https://godoc.org/github.com/huandu/xstrings#Width) | `mb_strwidth` in PHP | [#26](https://github.com/huandu/xstrings/issues/26) | diff --git a/vendor/github.com/huandu/xstrings/convert.go b/vendor/github.com/huandu/xstrings/convert.go index cba0d0725..5d8cfee47 100644 --- a/vendor/github.com/huandu/xstrings/convert.go +++ b/vendor/github.com/huandu/xstrings/convert.go @@ -13,17 +13,37 @@ import ( // // Some samples. // +// "some_words" => "someWords" +// "http_server" => "httpServer" +// "no_https" => "noHttps" +// "_complex__case_" => "_complex_Case_" +// "some words" => "someWords" +// "GOLANG_IS_GREAT" => "golangIsGreat" +func ToCamelCase(str string) string { + return toCamelCase(str, false) +} + +// ToPascalCase is to convert words separated by space, underscore and hyphen to pascal case. +// +// Some samples. +// // "some_words" => "SomeWords" // "http_server" => "HttpServer" // "no_https" => "NoHttps" // "_complex__case_" => "_Complex_Case_" // "some words" => "SomeWords" -func ToCamelCase(str string) string { +// "GOLANG_IS_GREAT" => "GolangIsGreat" +func ToPascalCase(str string) string { + return toCamelCase(str, true) +} + +func toCamelCase(str string, isBig bool) string { if len(str) == 0 { return "" } buf := &stringBuilder{} + var isFirstRuneUpper bool var r0, r1 rune var size int @@ -33,7 +53,14 @@ func ToCamelCase(str string) string { str = str[size:] if !isConnector(r0) { - r0 = unicode.ToUpper(r0) + isFirstRuneUpper = unicode.IsUpper(r0) + + if isBig { + r0 = unicode.ToUpper(r0) + } else { + r0 = unicode.ToLower(r0) + } + break } @@ -60,12 +87,25 @@ func ToCamelCase(str string) string { } if isConnector(r1) { + isFirstRuneUpper = unicode.IsUpper(r0) r0 = unicode.ToUpper(r0) } else { + if isFirstRuneUpper { + if unicode.IsUpper(r0) { + r0 = unicode.ToLower(r0) + } else { + isFirstRuneUpper = false + } + } + buf.WriteRune(r1) } } + if isFirstRuneUpper && !isBig { + r0 = unicode.ToLower(r0) + } + buf.WriteRune(r0) return buf.String() } diff --git a/vendor/github.com/jessevdk/go-flags/.travis.yml b/vendor/github.com/jessevdk/go-flags/.travis.yml deleted file mode 100644 index 2fc5e5f5b..000000000 --- a/vendor/github.com/jessevdk/go-flags/.travis.yml +++ /dev/null @@ -1,39 +0,0 @@ -language: go - -os: - - linux - - osx - -go: - - 1.16.x - -install: - # go-flags - - go build -v ./... - - # linting - - go get -v golang.org/x/lint/golint - - # code coverage - - go get golang.org/x/tools/cmd/cover - - go get github.com/onsi/ginkgo/ginkgo - - go get github.com/modocache/gover - - if [ "$TRAVIS_SECURE_ENV_VARS" = "true" ]; then go get github.com/mattn/goveralls; fi - -script: - # go-flags - - $(exit $(gofmt -l . | wc -l)) - - go test -v ./... - - # linting - - go tool vet -all=true -v=true . || true - - $(go env GOPATH | awk 'BEGIN{FS=":"} {print $1}')/bin/golint ./... - - # code coverage - - $(go env GOPATH | awk 'BEGIN{FS=":"} {print $1}')/bin/ginkgo -r -cover - - $(go env GOPATH | awk 'BEGIN{FS=":"} {print $1}')/bin/gover - - if [ "$TRAVIS_SECURE_ENV_VARS" = "true" ]; then $(go env GOPATH | awk 'BEGIN{FS=":"} {print $1}')/bin/goveralls -coverprofile=gover.coverprofile -service=travis-ci -repotoken $COVERALLS_TOKEN; fi - -env: - # coveralls.io - secure: "RCYbiB4P0RjQRIoUx/vG/AjP3mmYCbzOmr86DCww1Z88yNcy3hYr3Cq8rpPtYU5v0g7wTpu4adaKIcqRE9xknYGbqj3YWZiCoBP1/n4Z+9sHW3Dsd9D/GRGeHUus0laJUGARjWoCTvoEtOgTdGQDoX7mH+pUUY0FBltNYUdOiiU=" diff --git a/vendor/github.com/jessevdk/go-flags/README.md b/vendor/github.com/jessevdk/go-flags/README.md index f22650b20..759eeb0d4 100644 --- a/vendor/github.com/jessevdk/go-flags/README.md +++ b/vendor/github.com/jessevdk/go-flags/README.md @@ -1,7 +1,7 @@ go-flags: a go library for parsing command line arguments ========================================================= -[](https://godoc.org/github.com/jessevdk/go-flags) [](https://travis-ci.org/jessevdk/go-flags) [](https://coveralls.io/r/jessevdk/go-flags?branch=master) +[](https://godoc.org/github.com/jessevdk/go-flags) This library provides similar functionality to the builtin flag library of go, but provides much more functionality and nicer formatting. From the @@ -78,6 +78,9 @@ var opts struct { // Example of a map IntMap map[string]int `long:"intmap" description:"A map from string to int"` + + // Example of env variable + Thresholds []int `long:"thresholds" default:"1" default:"2" env:"THRESHOLD_VALUES" env-delim:","` } // Callback which will invoke callto:<argument> to call a number. diff --git a/vendor/github.com/jessevdk/go-flags/command.go b/vendor/github.com/jessevdk/go-flags/command.go index 879465d7a..ac4f1e392 100644 --- a/vendor/github.com/jessevdk/go-flags/command.go +++ b/vendor/github.com/jessevdk/go-flags/command.go @@ -30,6 +30,12 @@ type Command struct { // Whether positional arguments are required ArgsRequired bool + // Whether to pass all arguments after the first non option as remaining + // command line arguments. This is equivalent to strict POSIX processing. + // This is command-local version of PassAfterNonOption Parser flag. It + // cannot be turned off when PassAfterNonOption Parser flag is set. + PassAfterNonOption bool + commands []*Command hasBuiltinHelpGroup bool args []*Arg @@ -244,6 +250,7 @@ func (c *Command) scanSubcommandHandler(parentg *Group) scanHandler { longDescription := mtag.Get("long-description") subcommandsOptional := mtag.Get("subcommands-optional") aliases := mtag.GetMany("alias") + passAfterNonOption := mtag.Get("pass-after-non-option") subc, err := c.AddCommand(subcommand, shortDescription, longDescription, ptrval.Interface()) @@ -261,6 +268,10 @@ func (c *Command) scanSubcommandHandler(parentg *Group) scanHandler { subc.Aliases = aliases } + if len(passAfterNonOption) > 0 { + subc.PassAfterNonOption = true + } + return true, nil } diff --git a/vendor/github.com/jessevdk/go-flags/convert.go b/vendor/github.com/jessevdk/go-flags/convert.go index cda29b2f0..b27f698dc 100644 --- a/vendor/github.com/jessevdk/go-flags/convert.go +++ b/vendor/github.com/jessevdk/go-flags/convert.go @@ -53,7 +53,7 @@ func getBase(options multiTag, base int) (int, error) { func convertMarshal(val reflect.Value) (bool, string, error) { // Check first for the Marshaler interface - if val.Type().NumMethod() > 0 && val.CanInterface() { + if val.IsValid() && val.Type().NumMethod() > 0 && val.CanInterface() { if marshaler, ok := val.Interface().(Marshaler); ok { ret, err := marshaler.MarshalFlag() return true, ret, err @@ -68,6 +68,10 @@ func convertToString(val reflect.Value, options multiTag) (string, error) { return ret, err } + if !val.IsValid() { + return "", nil + } + tp := val.Type() // Support for time.Duration @@ -220,7 +224,7 @@ func convert(val string, retval reflect.Value, options multiTag) error { retval.SetBool(b) } case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - base, err := getBase(options, 10) + base, err := getBase(options, 0) if err != nil { return err @@ -234,7 +238,7 @@ func convert(val string, retval reflect.Value, options multiTag) error { retval.SetInt(parsed) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - base, err := getBase(options, 10) + base, err := getBase(options, 0) if err != nil { return err @@ -267,7 +271,12 @@ func convert(val string, retval reflect.Value, options multiTag) error { retval.Set(reflect.Append(retval, elemval)) case reflect.Map: - parts := strings.SplitN(val, ":", 2) + keyValueDelimiter := options.Get("key-value-delimiter") + if keyValueDelimiter == "" { + keyValueDelimiter = ":" + } + + parts := strings.SplitN(val, keyValueDelimiter, 2) key := parts[0] var value string diff --git a/vendor/github.com/jessevdk/go-flags/flags.go b/vendor/github.com/jessevdk/go-flags/flags.go index ac2157dd6..a6acf1be1 100644 --- a/vendor/github.com/jessevdk/go-flags/flags.go +++ b/vendor/github.com/jessevdk/go-flags/flags.go @@ -8,46 +8,45 @@ The flags package is similar in functionality to the go built-in flag package but provides more options and uses reflection to provide a convenient and succinct way of specifying command line options. - -Supported features +# Supported features The following features are supported in go-flags: - Options with short names (-v) - Options with long names (--verbose) - Options with and without arguments (bool v.s. other type) - Options with optional arguments and default values - Option default values from ENVIRONMENT_VARIABLES, including slice and map values - Multiple option groups each containing a set of options - Generate and print well-formatted help message - Passing remaining command line arguments after -- (optional) - Ignoring unknown command line options (optional) - Supports -I/usr/include -I=/usr/include -I /usr/include option argument specification - Supports multiple short options -aux - Supports all primitive go types (string, int{8..64}, uint{8..64}, float) - Supports same option multiple times (can store in slice or last option counts) - Supports maps - Supports function callbacks - Supports namespaces for (nested) option groups + Options with short names (-v) + Options with long names (--verbose) + Options with and without arguments (bool v.s. other type) + Options with optional arguments and default values + Option default values from ENVIRONMENT_VARIABLES, including slice and map values + Multiple option groups each containing a set of options + Generate and print well-formatted help message + Passing remaining command line arguments after -- (optional) + Ignoring unknown command line options (optional) + Supports -I/usr/include -I=/usr/include -I /usr/include option argument specification + Supports multiple short options -aux + Supports all primitive go types (string, int{8..64}, uint{8..64}, float) + Supports same option multiple times (can store in slice or last option counts) + Supports maps + Supports function callbacks + Supports namespaces for (nested) option groups Additional features specific to Windows: - Options with short names (/v) - Options with long names (/verbose) - Windows-style options with arguments use a colon as the delimiter - Modify generated help message with Windows-style / options - Windows style options can be disabled at build time using the "forceposix" - build tag + Options with short names (/v) + Options with long names (/verbose) + Windows-style options with arguments use a colon as the delimiter + Modify generated help message with Windows-style / options + Windows style options can be disabled at build time using the "forceposix" + build tag -Basic usage +# Basic usage The flags package uses structs, reflection and struct field tags to allow users to specify command line options. This results in very simple and concise specification of your application options. For example: - type Options struct { - Verbose []bool `short:"v" long:"verbose" description:"Show verbose debug information"` - } + type Options struct { + Verbose []bool `short:"v" long:"verbose" description:"Show verbose debug information"` + } This specifies one option with a short name -v and a long name --verbose. When either -v or --verbose is found on the command line, a 'true' value @@ -60,9 +59,9 @@ whenever the option is encountered, a value is appended to the slice. Map options from string to primitive type are also supported. On the command line, you specify the value for such an option as key:value. For example - type Options struct { - AuthorInfo string[string] `short:"a"` - } + type Options struct { + AuthorInfo string[string] `short:"a"` + } Then, the AuthorInfo map can be filled with something like -a name:Jesse -a "surname:van den Kieboom". @@ -71,96 +70,94 @@ Finally, for full control over the conversion between command line argument values and options, user defined types can choose to implement the Marshaler and Unmarshaler interfaces. - -Available field tags +# Available field tags The following is a list of tags for struct fields supported by go-flags: - short: the short name of the option (single character) - long: the long name of the option - required: if non empty, makes the option required to appear on the command - line. If a required option is not present, the parser will - return ErrRequired (optional) - description: the description of the option (optional) - long-description: the long description of the option. Currently only - displayed in generated man pages (optional) - no-flag: if non-empty, this field is ignored as an option (optional) - - optional: if non-empty, makes the argument of the option optional. When an - argument is optional it can only be specified using - --option=argument (optional) - optional-value: the value of an optional option when the option occurs - without an argument. This tag can be specified multiple - times in the case of maps or slices (optional) - default: the default value of an option. This tag can be specified - multiple times in the case of slices or maps (optional) - default-mask: when specified, this value will be displayed in the help - instead of the actual default value. This is useful - mostly for hiding otherwise sensitive information from - showing up in the help. If default-mask takes the special - value "-", then no default value will be shown at all - (optional) - env: the default value of the option is overridden from the - specified environment variable, if one has been defined. - (optional) - env-delim: the 'env' default value from environment is split into - multiple values with the given delimiter string, use with - slices and maps (optional) - value-name: the name of the argument value (to be shown in the help) - (optional) - choice: limits the values for an option to a set of values. - Repeat this tag once for each allowable value. - e.g. `long:"animal" choice:"cat" choice:"dog"` - hidden: if non-empty, the option is not visible in the help or man page. - - base: a base (radix) used to convert strings to integer values, the - default base is 10 (i.e. decimal) (optional) - - ini-name: the explicit ini option name (optional) - no-ini: if non-empty this field is ignored as an ini option - (optional) - - group: when specified on a struct field, makes the struct - field a separate group with the given name (optional) - namespace: when specified on a group struct field, the namespace - gets prepended to every option's long name and - subgroup's namespace of this group, separated by - the parser's namespace delimiter (optional) - env-namespace: when specified on a group struct field, the env-namespace - gets prepended to every option's env key and - subgroup's env-namespace of this group, separated by - the parser's env-namespace delimiter (optional) - command: when specified on a struct field, makes the struct - field a (sub)command with the given name (optional) - subcommands-optional: when specified on a command struct field, makes - any subcommands of that command optional (optional) - alias: when specified on a command struct field, adds the - specified name as an alias for the command. Can be - be specified multiple times to add more than one - alias (optional) - positional-args: when specified on a field with a struct type, - uses the fields of that struct to parse remaining - positional command line arguments into (in order - of the fields). If a field has a slice type, - then all remaining arguments will be added to it. - Positional arguments are optional by default, - unless the "required" tag is specified together - with the "positional-args" tag. The "required" tag - can also be set on the individual rest argument - fields, to require only the first N positional - arguments. If the "required" tag is set on the - rest arguments slice, then its value determines - the minimum amount of rest arguments that needs to - be provided (e.g. `required:"2"`) (optional) - positional-arg-name: used on a field in a positional argument struct; name - of the positional argument placeholder to be shown in - the help (optional) + short: the short name of the option (single character) + long: the long name of the option + required: if non empty, makes the option required to appear on the command + line. If a required option is not present, the parser will + return ErrRequired (optional) + description: the description of the option (optional) + long-description: the long description of the option. Currently only + displayed in generated man pages (optional) + no-flag: if non-empty, this field is ignored as an option (optional) + + optional: if non-empty, makes the argument of the option optional. When an + argument is optional it can only be specified using + --option=argument (optional) + optional-value: the value of an optional option when the option occurs + without an argument. This tag can be specified multiple + times in the case of maps or slices (optional) + default: the default value of an option. This tag can be specified + multiple times in the case of slices or maps (optional) + default-mask: when specified, this value will be displayed in the help + instead of the actual default value. This is useful + mostly for hiding otherwise sensitive information from + showing up in the help. If default-mask takes the special + value "-", then no default value will be shown at all + (optional) + env: the default value of the option is overridden from the + specified environment variable, if one has been defined. + (optional) + env-delim: the 'env' default value from environment is split into + multiple values with the given delimiter string, use with + slices and maps (optional) + value-name: the name of the argument value (to be shown in the help) + (optional) + choice: limits the values for an option to a set of values. + Repeat this tag once for each allowable value. + e.g. `long:"animal" choice:"cat" choice:"dog"` + hidden: if non-empty, the option is not visible in the help or man page. + + base: a base (radix) used to convert strings to integer values, the + default base is 10 (i.e. decimal) (optional) + + ini-name: the explicit ini option name (optional) + no-ini: if non-empty this field is ignored as an ini option + (optional) + + group: when specified on a struct field, makes the struct + field a separate group with the given name (optional) + namespace: when specified on a group struct field, the namespace + gets prepended to every option's long name and + subgroup's namespace of this group, separated by + the parser's namespace delimiter (optional) + env-namespace: when specified on a group struct field, the env-namespace + gets prepended to every option's env key and + subgroup's env-namespace of this group, separated by + the parser's env-namespace delimiter (optional) + command: when specified on a struct field, makes the struct + field a (sub)command with the given name (optional) + subcommands-optional: when specified on a command struct field, makes + any subcommands of that command optional (optional) + alias: when specified on a command struct field, adds the + specified name as an alias for the command. Can be + be specified multiple times to add more than one + alias (optional) + positional-args: when specified on a field with a struct type, + uses the fields of that struct to parse remaining + positional command line arguments into (in order + of the fields). If a field has a slice type, + then all remaining arguments will be added to it. + Positional arguments are optional by default, + unless the "required" tag is specified together + with the "positional-args" tag. The "required" tag + can also be set on the individual rest argument + fields, to require only the first N positional + arguments. If the "required" tag is set on the + rest arguments slice, then its value determines + the minimum amount of rest arguments that needs to + be provided (e.g. `required:"2"`) (optional) + positional-arg-name: used on a field in a positional argument struct; name + of the positional argument placeholder to be shown in + the help (optional) Either the `short:` tag or the `long:` must be specified to make the field eligible as an option. - -Option groups +# Option groups Option groups are a simple way to semantically separate your options. All options in a particular group are shown together in the help under the name @@ -169,14 +166,12 @@ precisely and emphasize the options affiliation to their group. There are currently three ways to specify option groups. - 1. Use NewNamedParser specifying the various option groups. - 2. Use AddGroup to add a group to an existing parser. - 3. Add a struct field to the top-level options annotated with the - group:"group-name" tag. + 1. Use NewNamedParser specifying the various option groups. + 2. Use AddGroup to add a group to an existing parser. + 3. Add a struct field to the top-level options annotated with the + group:"group-name" tag. - - -Commands +# Commands The flags package also has basic support for commands. Commands are often used in monolithic applications that support various commands or actions. @@ -186,9 +181,9 @@ application. There are currently two ways to specify a command. - 1. Use AddCommand on an existing parser. - 2. Add a struct field to your options struct annotated with the - command:"command-name" tag. + 1. Use AddCommand on an existing parser. + 2. Add a struct field to your options struct annotated with the + command:"command-name" tag. The most common, idiomatic way to implement commands is to define a global parser instance and implement each command in a separate file. These @@ -204,15 +199,14 @@ command has been specified on the command line, in addition to the options of all the parent commands. I.e. considering a -v flag on the parser and an add command, the following are equivalent: - ./app -v add - ./app add -v + ./app -v add + ./app add -v However, if the -v flag is defined on the add command, then the first of the two examples above would fail since the -v flag is not defined before the add command. - -Completion +# Completion go-flags has builtin support to provide bash completion of flags, commands and argument values. To use completion, the binary which uses go-flags @@ -226,7 +220,7 @@ by replacing the argument parsing routine with the completion routine which outputs completions for the passed arguments. The basic invocation to complete a set of arguments is therefore: - GO_FLAGS_COMPLETION=1 ./completion-example arg1 arg2 arg3 + GO_FLAGS_COMPLETION=1 ./completion-example arg1 arg2 arg3 where `completion-example` is the binary, `arg1` and `arg2` are the current arguments, and `arg3` (the last argument) is the argument @@ -237,20 +231,20 @@ are more than 1 completion items. To use this with bash completion, a simple file can be written which calls the binary which supports go-flags completion: - _completion_example() { - # All arguments except the first one - args=("${COMP_WORDS[@]:1:$COMP_CWORD}") + _completion_example() { + # All arguments except the first one + args=("${COMP_WORDS[@]:1:$COMP_CWORD}") - # Only split on newlines - local IFS=$'\n' + # Only split on newlines + local IFS=$'\n' - # Call completion (note that the first element of COMP_WORDS is - # the executable itself) - COMPREPLY=($(GO_FLAGS_COMPLETION=1 ${COMP_WORDS[0]} "${args[@]}")) - return 0 - } + # Call completion (note that the first element of COMP_WORDS is + # the executable itself) + COMPREPLY=($(GO_FLAGS_COMPLETION=1 ${COMP_WORDS[0]} "${args[@]}")) + return 0 + } - complete -F _completion_example completion-example + complete -F _completion_example completion-example Completion requires the parser option PassDoubleDash and is therefore enforced if the environment variable GO_FLAGS_COMPLETION is set. diff --git a/vendor/github.com/jessevdk/go-flags/help.go b/vendor/github.com/jessevdk/go-flags/help.go index 068fce152..8fd324443 100644 --- a/vendor/github.com/jessevdk/go-flags/help.go +++ b/vendor/github.com/jessevdk/go-flags/help.go @@ -72,15 +72,15 @@ func (p *Parser) getAlignmentInfo() alignmentInfo { var prevcmd *Command p.eachActiveGroup(func(c *Command, grp *Group) { - if !grp.showInHelp() { - return - } if c != prevcmd { for _, arg := range c.args { ret.updateLen(arg.Name, c != p.Command) } + prevcmd = c + } + if !grp.showInHelp() { + return } - for _, info := range grp.options { if !info.showInHelp() { continue @@ -334,7 +334,11 @@ func (p *Parser) WriteHelp(writer io.Writer) { } if !allcmd.ArgsRequired { - fmt.Fprintf(wr, "[%s]", name) + if arg.Required > 0 { + fmt.Fprintf(wr, "%s", name) + } else { + fmt.Fprintf(wr, "[%s]", name) + } } else { fmt.Fprintf(wr, "%s", name) } diff --git a/vendor/github.com/jessevdk/go-flags/ini.go b/vendor/github.com/jessevdk/go-flags/ini.go index 60b36c79c..565595e5f 100644 --- a/vendor/github.com/jessevdk/go-flags/ini.go +++ b/vendor/github.com/jessevdk/go-flags/ini.go @@ -113,18 +113,18 @@ func (i *IniParser) ParseFile(filename string) error { // // The format of the ini file is as follows: // -// [Option group name] -// option = value +// [Option group name] +// option = value // // Each section in the ini file represents an option group or command in the // flags parser. The default flags parser option group (i.e. when using // flags.Parse) is named 'Application Options'. The ini option name is matched // in the following order: // -// 1. Compared to the ini-name tag on the option struct field (if present) -// 2. Compared to the struct field name -// 3. Compared to the option long name (if present) -// 4. Compared to the option short name (if present) +// 1. Compared to the ini-name tag on the option struct field (if present) +// 2. Compared to the struct field name +// 3. Compared to the option long name (if present) +// 4. Compared to the option short name (if present) // // Sections for nested groups and commands can be addressed using a dot `.' // namespacing notation (i.e [subcommand.Options]). Group section names are @@ -584,7 +584,7 @@ func (i *IniParser) parse(ini *ini) error { if i.ParseAsDefaults { err = opt.setDefault(pval) } else { - err = opt.set(pval) + err = opt.Set(pval) } if err != nil { diff --git a/vendor/github.com/jessevdk/go-flags/option.go b/vendor/github.com/jessevdk/go-flags/option.go index f6d694181..257996a79 100644 --- a/vendor/github.com/jessevdk/go-flags/option.go +++ b/vendor/github.com/jessevdk/go-flags/option.go @@ -239,7 +239,7 @@ func (option *Option) IsSetDefault() bool { // Set the value of an option to the specified value. An error will be returned // if the specified value could not be converted to the corresponding option // value type. -func (option *Option) set(value *string) error { +func (option *Option) Set(value *string) error { kind := option.value.Type().Kind() if (kind == reflect.Map || kind == reflect.Slice) && option.clearReferenceBeforeSet { @@ -287,7 +287,7 @@ func (option *Option) setDefault(value *string) error { return nil } - if err := option.set(value); err != nil { + if err := option.Set(value); err != nil { return err } diff --git a/vendor/github.com/jessevdk/go-flags/optstyle_other.go b/vendor/github.com/jessevdk/go-flags/optstyle_other.go index 56dfdae12..f84b69746 100644 --- a/vendor/github.com/jessevdk/go-flags/optstyle_other.go +++ b/vendor/github.com/jessevdk/go-flags/optstyle_other.go @@ -1,3 +1,4 @@ +//go:build !windows || forceposix // +build !windows forceposix package flags diff --git a/vendor/github.com/jessevdk/go-flags/optstyle_windows.go b/vendor/github.com/jessevdk/go-flags/optstyle_windows.go index f3f28aeef..e80290420 100644 --- a/vendor/github.com/jessevdk/go-flags/optstyle_windows.go +++ b/vendor/github.com/jessevdk/go-flags/optstyle_windows.go @@ -1,3 +1,4 @@ +//go:build !forceposix // +build !forceposix package flags diff --git a/vendor/github.com/jessevdk/go-flags/parser.go b/vendor/github.com/jessevdk/go-flags/parser.go index 3fc3f7ba1..939dd7bf4 100644 --- a/vendor/github.com/jessevdk/go-flags/parser.go +++ b/vendor/github.com/jessevdk/go-flags/parser.go @@ -113,6 +113,10 @@ const ( // POSIX processing. PassAfterNonOption + // AllowBoolValues allows a user to assign true/false to a boolean value + // rather than raising an error stating it cannot have an argument. + AllowBoolValues + // Default is a convenient default set of options which should cover // most of the uses of the flags package. Default = HelpFlag | PrintErrors | PassDoubleDash @@ -252,7 +256,7 @@ func (p *Parser) ParseArgs(args []string) ([]string, error) { } if !argumentIsOption(arg) { - if (p.Options&PassAfterNonOption) != None && s.lookup.commands[arg] == nil { + if ((p.Options&PassAfterNonOption) != None || s.command.PassAfterNonOption) && s.lookup.commands[arg] == nil { // If PassAfterNonOption is set then all remaining arguments // are considered positional if err = s.addArgs(s.arg); err != nil { @@ -521,11 +525,10 @@ func (p *parseState) estimateCommand() error { func (p *Parser) parseOption(s *parseState, name string, option *Option, canarg bool, argument *string) (err error) { if !option.canArgument() { - if argument != nil { + if argument != nil && (p.Options&AllowBoolValues) == None { return newErrorf(ErrNoArgumentForBool, "bool flag `%s' cannot have an argument", option) } - - err = option.set(nil) + err = option.Set(argument) } else if argument != nil || (canarg && !s.eof()) { var arg string @@ -546,13 +549,13 @@ func (p *Parser) parseOption(s *parseState, name string, option *Option, canarg } if err == nil { - err = option.set(&arg) + err = option.Set(&arg) } } else if option.OptionalArgument { option.empty() for _, v := range option.OptionalValue { - err = option.set(&v) + err = option.Set(&v) if err != nil { break diff --git a/vendor/github.com/jessevdk/go-flags/termsize.go b/vendor/github.com/jessevdk/go-flags/termsize.go index 829e477ad..7bcf66fee 100644 --- a/vendor/github.com/jessevdk/go-flags/termsize.go +++ b/vendor/github.com/jessevdk/go-flags/termsize.go @@ -1,4 +1,5 @@ -// +build !windows,!plan9,!appengine,!wasm +//go:build !windows && !plan9 && !appengine && !wasm && !aix +// +build !windows,!plan9,!appengine,!wasm,!aix package flags diff --git a/vendor/github.com/jessevdk/go-flags/termsize_nosysioctl.go b/vendor/github.com/jessevdk/go-flags/termsize_nosysioctl.go index c1ff18673..d839220aa 100644 --- a/vendor/github.com/jessevdk/go-flags/termsize_nosysioctl.go +++ b/vendor/github.com/jessevdk/go-flags/termsize_nosysioctl.go @@ -1,4 +1,5 @@ -// +build plan9 appengine wasm +//go:build plan9 || appengine || wasm || aix +// +build plan9 appengine wasm aix package flags diff --git a/vendor/github.com/jessevdk/go-flags/termsize_windows.go b/vendor/github.com/jessevdk/go-flags/termsize_windows.go index 5c0fa6ba2..189a1b3fa 100644 --- a/vendor/github.com/jessevdk/go-flags/termsize_windows.go +++ b/vendor/github.com/jessevdk/go-flags/termsize_windows.go @@ -1,3 +1,4 @@ +//go:build windows // +build windows package flags diff --git a/vendor/github.com/mailru/easyjson/jlexer/bytestostr.go b/vendor/github.com/mailru/easyjson/jlexer/bytestostr.go index ff7b27c5b..e68108f86 100644 --- a/vendor/github.com/mailru/easyjson/jlexer/bytestostr.go +++ b/vendor/github.com/mailru/easyjson/jlexer/bytestostr.go @@ -8,7 +8,6 @@ package jlexer import ( - "reflect" "unsafe" ) @@ -18,7 +17,5 @@ import ( // chunk may be either blocked from being freed by GC because of a single string or the buffer.Data // may be garbage-collected even when the string exists. func bytesToStr(data []byte) string { - h := (*reflect.SliceHeader)(unsafe.Pointer(&data)) - shdr := reflect.StringHeader{Data: h.Data, Len: h.Len} - return *(*string)(unsafe.Pointer(&shdr)) + return *(*string)(unsafe.Pointer(&data)) } diff --git a/vendor/github.com/mailru/easyjson/jlexer/lexer.go b/vendor/github.com/mailru/easyjson/jlexer/lexer.go index b5f5e2613..a27705b12 100644 --- a/vendor/github.com/mailru/easyjson/jlexer/lexer.go +++ b/vendor/github.com/mailru/easyjson/jlexer/lexer.go @@ -19,21 +19,21 @@ import ( "github.com/josharian/intern" ) -// tokenKind determines type of a token. -type tokenKind byte +// TokenKind determines type of a token. +type TokenKind byte const ( - tokenUndef tokenKind = iota // No token. - tokenDelim // Delimiter: one of '{', '}', '[' or ']'. - tokenString // A string literal, e.g. "abc\u1234" - tokenNumber // Number literal, e.g. 1.5e5 - tokenBool // Boolean literal: true or false. - tokenNull // null keyword. + TokenUndef TokenKind = iota // No token. + TokenDelim // Delimiter: one of '{', '}', '[' or ']'. + TokenString // A string literal, e.g. "abc\u1234" + TokenNumber // Number literal, e.g. 1.5e5 + TokenBool // Boolean literal: true or false. + TokenNull // null keyword. ) // token describes a single token: type, position in the input and value. type token struct { - kind tokenKind // Type of a token. + kind TokenKind // Type of a token. boolValue bool // Value if a boolean literal token. byteValueCloned bool // true if byteValue was allocated and does not refer to original json body @@ -47,7 +47,7 @@ type Lexer struct { start int // Start of the current token. pos int // Current unscanned position in the input stream. - token token // Last scanned token, if token.kind != tokenUndef. + token token // Last scanned token, if token.kind != TokenUndef. firstElement bool // Whether current element is the first in array or an object. wantSep byte // A comma or a colon character, which need to occur before a token. @@ -59,7 +59,7 @@ type Lexer struct { // FetchToken scans the input for the next token. func (r *Lexer) FetchToken() { - r.token.kind = tokenUndef + r.token.kind = TokenUndef r.start = r.pos // Check if r.Data has r.pos element @@ -90,7 +90,7 @@ func (r *Lexer) FetchToken() { r.errSyntax() } - r.token.kind = tokenString + r.token.kind = TokenString r.fetchString() return @@ -99,7 +99,7 @@ func (r *Lexer) FetchToken() { r.errSyntax() } r.firstElement = true - r.token.kind = tokenDelim + r.token.kind = TokenDelim r.token.delimValue = r.Data[r.pos] r.pos++ return @@ -109,7 +109,7 @@ func (r *Lexer) FetchToken() { r.errSyntax() } r.wantSep = 0 - r.token.kind = tokenDelim + r.token.kind = TokenDelim r.token.delimValue = r.Data[r.pos] r.pos++ return @@ -118,7 +118,7 @@ func (r *Lexer) FetchToken() { if r.wantSep != 0 { r.errSyntax() } - r.token.kind = tokenNumber + r.token.kind = TokenNumber r.fetchNumber() return @@ -127,7 +127,7 @@ func (r *Lexer) FetchToken() { r.errSyntax() } - r.token.kind = tokenNull + r.token.kind = TokenNull r.fetchNull() return @@ -136,7 +136,7 @@ func (r *Lexer) FetchToken() { r.errSyntax() } - r.token.kind = tokenBool + r.token.kind = TokenBool r.token.boolValue = true r.fetchTrue() return @@ -146,7 +146,7 @@ func (r *Lexer) FetchToken() { r.errSyntax() } - r.token.kind = tokenBool + r.token.kind = TokenBool r.token.boolValue = false r.fetchFalse() return @@ -391,7 +391,7 @@ func (r *Lexer) fetchString() { // scanToken scans the next token if no token is currently available in the lexer. func (r *Lexer) scanToken() { - if r.token.kind != tokenUndef || r.fatalError != nil { + if r.token.kind != TokenUndef || r.fatalError != nil { return } @@ -400,7 +400,7 @@ func (r *Lexer) scanToken() { // consume resets the current token to allow scanning the next one. func (r *Lexer) consume() { - r.token.kind = tokenUndef + r.token.kind = TokenUndef r.token.byteValueCloned = false r.token.delimValue = 0 } @@ -443,10 +443,10 @@ func (r *Lexer) errInvalidToken(expected string) { switch expected { case "[": r.token.delimValue = ']' - r.token.kind = tokenDelim + r.token.kind = TokenDelim case "{": r.token.delimValue = '}' - r.token.kind = tokenDelim + r.token.kind = TokenDelim } r.addNonfatalError(&LexerError{ Reason: fmt.Sprintf("expected %s", expected), @@ -475,7 +475,7 @@ func (r *Lexer) GetPos() int { // Delim consumes a token and verifies that it is the given delimiter. func (r *Lexer) Delim(c byte) { - if r.token.kind == tokenUndef && r.Ok() { + if r.token.kind == TokenUndef && r.Ok() { r.FetchToken() } @@ -489,7 +489,7 @@ func (r *Lexer) Delim(c byte) { // IsDelim returns true if there was no scanning error and next token is the given delimiter. func (r *Lexer) IsDelim(c byte) bool { - if r.token.kind == tokenUndef && r.Ok() { + if r.token.kind == TokenUndef && r.Ok() { r.FetchToken() } return !r.Ok() || r.token.delimValue == c @@ -497,10 +497,10 @@ func (r *Lexer) IsDelim(c byte) bool { // Null verifies that the next token is null and consumes it. func (r *Lexer) Null() { - if r.token.kind == tokenUndef && r.Ok() { + if r.token.kind == TokenUndef && r.Ok() { r.FetchToken() } - if !r.Ok() || r.token.kind != tokenNull { + if !r.Ok() || r.token.kind != TokenNull { r.errInvalidToken("null") } r.consume() @@ -508,15 +508,15 @@ func (r *Lexer) Null() { // IsNull returns true if the next token is a null keyword. func (r *Lexer) IsNull() bool { - if r.token.kind == tokenUndef && r.Ok() { + if r.token.kind == TokenUndef && r.Ok() { r.FetchToken() } - return r.Ok() && r.token.kind == tokenNull + return r.Ok() && r.token.kind == TokenNull } // Skip skips a single token. func (r *Lexer) Skip() { - if r.token.kind == tokenUndef && r.Ok() { + if r.token.kind == TokenUndef && r.Ok() { r.FetchToken() } r.consume() @@ -621,10 +621,10 @@ func (r *Lexer) Consumed() { } func (r *Lexer) unsafeString(skipUnescape bool) (string, []byte) { - if r.token.kind == tokenUndef && r.Ok() { + if r.token.kind == TokenUndef && r.Ok() { r.FetchToken() } - if !r.Ok() || r.token.kind != tokenString { + if !r.Ok() || r.token.kind != TokenString { r.errInvalidToken("string") return "", nil } @@ -664,10 +664,10 @@ func (r *Lexer) UnsafeFieldName(skipUnescape bool) string { // String reads a string literal. func (r *Lexer) String() string { - if r.token.kind == tokenUndef && r.Ok() { + if r.token.kind == TokenUndef && r.Ok() { r.FetchToken() } - if !r.Ok() || r.token.kind != tokenString { + if !r.Ok() || r.token.kind != TokenString { r.errInvalidToken("string") return "" } @@ -687,10 +687,10 @@ func (r *Lexer) String() string { // StringIntern reads a string literal, and performs string interning on it. func (r *Lexer) StringIntern() string { - if r.token.kind == tokenUndef && r.Ok() { + if r.token.kind == TokenUndef && r.Ok() { r.FetchToken() } - if !r.Ok() || r.token.kind != tokenString { + if !r.Ok() || r.token.kind != TokenString { r.errInvalidToken("string") return "" } @@ -705,10 +705,10 @@ func (r *Lexer) StringIntern() string { // Bytes reads a string literal and base64 decodes it into a byte slice. func (r *Lexer) Bytes() []byte { - if r.token.kind == tokenUndef && r.Ok() { + if r.token.kind == TokenUndef && r.Ok() { r.FetchToken() } - if !r.Ok() || r.token.kind != tokenString { + if !r.Ok() || r.token.kind != TokenString { r.errInvalidToken("string") return nil } @@ -731,10 +731,10 @@ func (r *Lexer) Bytes() []byte { // Bool reads a true or false boolean keyword. func (r *Lexer) Bool() bool { - if r.token.kind == tokenUndef && r.Ok() { + if r.token.kind == TokenUndef && r.Ok() { r.FetchToken() } - if !r.Ok() || r.token.kind != tokenBool { + if !r.Ok() || r.token.kind != TokenBool { r.errInvalidToken("bool") return false } @@ -744,10 +744,10 @@ func (r *Lexer) Bool() bool { } func (r *Lexer) number() string { - if r.token.kind == tokenUndef && r.Ok() { + if r.token.kind == TokenUndef && r.Ok() { r.FetchToken() } - if !r.Ok() || r.token.kind != tokenNumber { + if !r.Ok() || r.token.kind != TokenNumber { r.errInvalidToken("number") return "" } @@ -1151,7 +1151,7 @@ func (r *Lexer) GetNonFatalErrors() []*LexerError { // JsonNumber fetches and json.Number from 'encoding/json' package. // Both int, float or string, contains them are valid values func (r *Lexer) JsonNumber() json.Number { - if r.token.kind == tokenUndef && r.Ok() { + if r.token.kind == TokenUndef && r.Ok() { r.FetchToken() } if !r.Ok() { @@ -1160,11 +1160,11 @@ func (r *Lexer) JsonNumber() json.Number { } switch r.token.kind { - case tokenString: + case TokenString: return json.Number(r.String()) - case tokenNumber: + case TokenNumber: return json.Number(r.Raw()) - case tokenNull: + case TokenNull: r.Null() return json.Number("") default: @@ -1175,7 +1175,7 @@ func (r *Lexer) JsonNumber() json.Number { // Interface fetches an interface{} analogous to the 'encoding/json' package. func (r *Lexer) Interface() interface{} { - if r.token.kind == tokenUndef && r.Ok() { + if r.token.kind == TokenUndef && r.Ok() { r.FetchToken() } @@ -1183,13 +1183,13 @@ func (r *Lexer) Interface() interface{} { return nil } switch r.token.kind { - case tokenString: + case TokenString: return r.String() - case tokenNumber: + case TokenNumber: return r.Float64() - case tokenBool: + case TokenBool: return r.Bool() - case tokenNull: + case TokenNull: r.Null() return nil } @@ -1242,3 +1242,16 @@ func (r *Lexer) WantColon() { r.wantSep = ':' r.firstElement = false } + +// CurrentToken returns current token kind if there were no errors and TokenUndef otherwise +func (r *Lexer) CurrentToken() TokenKind { + if r.token.kind == TokenUndef && r.Ok() { + r.FetchToken() + } + + if !r.Ok() { + return TokenUndef + } + + return r.token.kind +} diff --git a/vendor/github.com/mailru/easyjson/jwriter/writer.go b/vendor/github.com/mailru/easyjson/jwriter/writer.go index 2c5b20105..34b0ade46 100644 --- a/vendor/github.com/mailru/easyjson/jwriter/writer.go +++ b/vendor/github.com/mailru/easyjson/jwriter/writer.go @@ -67,6 +67,18 @@ func (w *Writer) RawString(s string) { w.Buffer.AppendString(s) } +// RawBytesString appends string from bytes to the buffer. +func (w *Writer) RawBytesString(data []byte, err error) { + switch { + case w.Error != nil: + return + case err != nil: + w.Error = err + default: + w.String(string(data)) + } +} + // Raw appends raw binary data to the buffer or sets the error if it is given. Useful for // calling with results of MarshalJSON-like functions. func (w *Writer) Raw(data []byte, err error) { diff --git a/vendor/github.com/rogpeppe/go-internal/fmtsort/sort.go b/vendor/github.com/rogpeppe/go-internal/fmtsort/sort.go index 7f5185417..6af8c7f7b 100644 --- a/vendor/github.com/rogpeppe/go-internal/fmtsort/sort.go +++ b/vendor/github.com/rogpeppe/go-internal/fmtsort/sort.go @@ -143,14 +143,14 @@ func compare(aVal, bVal reflect.Value) int { return 0 } case reflect.Struct: - for i := 0; i < aVal.NumField(); i++ { + for i := range aVal.NumField() { if c := compare(aVal.Field(i), bVal.Field(i)); c != 0 { return c } } return 0 case reflect.Array: - for i := 0; i < aVal.Len(); i++ { + for i := range aVal.Len() { if c := compare(aVal.Index(i), bVal.Index(i)); c != 0 { return c } diff --git a/vendor/github.com/shopspring/decimal/.travis.yml b/vendor/github.com/shopspring/decimal/.travis.yml deleted file mode 100644 index 6326d40f0..000000000 --- a/vendor/github.com/shopspring/decimal/.travis.yml +++ /dev/null @@ -1,19 +0,0 @@ -language: go - -arch: - - amd64 - - ppc64le - -go: - - 1.7.x - - 1.14.x - - 1.15.x - - 1.16.x - - 1.17.x - - tip - -install: - - go build . - -script: - - go test -v diff --git a/vendor/github.com/shopspring/decimal/CHANGELOG.md b/vendor/github.com/shopspring/decimal/CHANGELOG.md index aea61154b..432d0fd4e 100644 --- a/vendor/github.com/shopspring/decimal/CHANGELOG.md +++ b/vendor/github.com/shopspring/decimal/CHANGELOG.md @@ -1,3 +1,30 @@ +## Decimal v1.4.0 +#### BREAKING +- Drop support for Go version older than 1.10 [#361](https://github.com/shopspring/decimal/pull/361) + +#### FEATURES +- Add implementation of natural logarithm [#339](https://github.com/shopspring/decimal/pull/339) [#357](https://github.com/shopspring/decimal/pull/357) +- Add improved implementation of power operation [#358](https://github.com/shopspring/decimal/pull/358) +- Add Compare method which forwards calls to Cmp [#346](https://github.com/shopspring/decimal/pull/346) +- Add NewFromBigRat constructor [#288](https://github.com/shopspring/decimal/pull/288) +- Add NewFromUint64 constructor [#352](https://github.com/shopspring/decimal/pull/352) + +#### ENHANCEMENTS +- Migrate to Github Actions [#245](https://github.com/shopspring/decimal/pull/245) [#340](https://github.com/shopspring/decimal/pull/340) +- Fix examples for RoundDown, RoundFloor, RoundUp, and RoundCeil [#285](https://github.com/shopspring/decimal/pull/285) [#328](https://github.com/shopspring/decimal/pull/328) [#341](https://github.com/shopspring/decimal/pull/341) +- Use Godoc standard to mark deprecated Equals and StringScaled methods [#342](https://github.com/shopspring/decimal/pull/342) +- Removed unnecessary min function for RescalePair method [#265](https://github.com/shopspring/decimal/pull/265) +- Avoid reallocation of initial slice in MarshalBinary (GobEncode) [#355](https://github.com/shopspring/decimal/pull/355) +- Optimize NumDigits method [#301](https://github.com/shopspring/decimal/pull/301) [#356](https://github.com/shopspring/decimal/pull/356) +- Optimize BigInt method [#359](https://github.com/shopspring/decimal/pull/359) +- Support scanning uint64 [#131](https://github.com/shopspring/decimal/pull/131) [#364](https://github.com/shopspring/decimal/pull/364) +- Add docs section with alternative libraries [#363](https://github.com/shopspring/decimal/pull/363) + +#### BUGFIXES +- Fix incorrect calculation of decimal modulo [#258](https://github.com/shopspring/decimal/pull/258) [#317](https://github.com/shopspring/decimal/pull/317) +- Allocate new(big.Int) in Copy method to deeply clone it [#278](https://github.com/shopspring/decimal/pull/278) +- Fix overflow edge case in QuoRem method [#322](https://github.com/shopspring/decimal/pull/322) + ## Decimal v1.3.1 #### ENHANCEMENTS diff --git a/vendor/github.com/shopspring/decimal/README.md b/vendor/github.com/shopspring/decimal/README.md index 2e35df068..318c9df58 100644 --- a/vendor/github.com/shopspring/decimal/README.md +++ b/vendor/github.com/shopspring/decimal/README.md @@ -1,6 +1,8 @@ # decimal -[](https://app.travis-ci.com/shopspring/decimal) [](https://godoc.org/github.com/shopspring/decimal) [](https://goreportcard.com/report/github.com/shopspring/decimal) +[](https://github.com/shopspring/decimal/actions/workflows/ci.yml) +[](https://godoc.org/github.com/shopspring/decimal) +[](https://goreportcard.com/report/github.com/shopspring/decimal) Arbitrary-precision fixed-point decimal numbers in go. @@ -20,7 +22,12 @@ Run `go get github.com/shopspring/decimal` ## Requirements -Decimal library requires Go version `>=1.7` +Decimal library requires Go version `>=1.10` + +## Documentation + +http://godoc.org/github.com/shopspring/decimal + ## Usage @@ -57,14 +64,16 @@ func main() { } ``` -## Documentation - -http://godoc.org/github.com/shopspring/decimal +## Alternative libraries -## Production Usage +When working with decimal numbers, you might face problems this library is not perfectly suited for. +Fortunately, thanks to the wonderful community we have a dozen other libraries that you can choose from. +Explore other alternatives to find the one that best fits your needs :) -* [Spring](https://shopspring.com/), since August 14, 2014. -* If you are using this in production, please let us know! +* [cockroachdb/apd](https://github.com/cockroachdb/apd) - arbitrary precision, mutable and rich API similar to `big.Int`, more performant than this library +* [alpacahq/alpacadecimal](https://github.com/alpacahq/alpacadecimal) - high performance, low precision (12 digits), fully compatible API with this library +* [govalues/decimal](https://github.com/govalues/decimal) - high performance, zero-allocation, low precision (19 digits) +* [greatcloak/decimal](https://github.com/greatcloak/decimal) - fork focusing on billing and e-commerce web application related use cases, includes out-of-the-box BSON marshaling support ## FAQ diff --git a/vendor/github.com/shopspring/decimal/const.go b/vendor/github.com/shopspring/decimal/const.go new file mode 100644 index 000000000..e5d6fa87e --- /dev/null +++ b/vendor/github.com/shopspring/decimal/const.go @@ -0,0 +1,63 @@ +package decimal + +import ( + "strings" +) + +const ( + strLn10 = "2.302585092994045684017991454684364207601101488628772976033327900967572609677352480235997205089598298341967784042286248633409525465082806756666287369098781689482907208325554680843799894826233198528393505308965377732628846163366222287698219886746543667474404243274365155048934314939391479619404400222105101714174800368808401264708068556774321622835522011480466371565912137345074785694768346361679210180644507064800027750268491674655058685693567342067058113642922455440575892572420824131469568901675894025677631135691929203337658714166023010570308963457207544037084746994016826928280848118428931484852494864487192780967627127577539702766860595249671667418348570442250719796500471495105049221477656763693866297697952211071826454973477266242570942932258279850258550978526538320760672631716430950599508780752371033310119785754733154142180842754386359177811705430982748238504564801909561029929182431823752535770975053956518769751037497088869218020518933950723853920514463419726528728696511086257149219884997874887377134568620916705849807828059751193854445009978131146915934666241071846692310107598438319191292230792503747298650929009880391941702654416816335727555703151596113564846546190897042819763365836983716328982174407366009162177850541779276367731145041782137660111010731042397832521894898817597921798666394319523936855916447118246753245630912528778330963604262982153040874560927760726641354787576616262926568298704957954913954918049209069438580790032763017941503117866862092408537949861264933479354871737451675809537088281067452440105892444976479686075120275724181874989395971643105518848195288330746699317814634930000321200327765654130472621883970596794457943468343218395304414844803701305753674262153675579814770458031413637793236291560128185336498466942261465206459942072917119370602444929358037007718981097362533224548366988505528285966192805098447175198503666680874970496982273220244823343097169111136813588418696549323714996941979687803008850408979618598756579894836445212043698216415292987811742973332588607915912510967187510929248475023930572665446276200923068791518135803477701295593646298412366497023355174586195564772461857717369368404676577047874319780573853271810933883496338813069945569399346101090745616033312247949360455361849123333063704751724871276379140924398331810164737823379692265637682071706935846394531616949411701841938119405416449466111274712819705817783293841742231409930022911502362192186723337268385688273533371925103412930705632544426611429765388301822384091026198582888433587455960453004548370789052578473166283701953392231047527564998119228742789713715713228319641003422124210082180679525276689858180956119208391760721080919923461516952599099473782780648128058792731993893453415320185969711021407542282796298237068941764740642225757212455392526179373652434440560595336591539160312524480149313234572453879524389036839236450507881731359711238145323701508413491122324390927681724749607955799151363982881058285740538000653371655553014196332241918087621018204919492651483892" +) + +var ( + ln10 = newConstApproximation(strLn10) +) + +type constApproximation struct { + exact Decimal + approximations []Decimal +} + +func newConstApproximation(value string) constApproximation { + parts := strings.Split(value, ".") + coeff, fractional := parts[0], parts[1] + + coeffLen := len(coeff) + maxPrecision := len(fractional) + + var approximations []Decimal + for p := 1; p < maxPrecision; p *= 2 { + r := RequireFromString(value[:coeffLen+p]) + approximations = append(approximations, r) + } + + return constApproximation{ + RequireFromString(value), + approximations, + } +} + +// Returns the smallest approximation available that's at least as precise +// as the passed precision (places after decimal point), i.e. Floor[ log2(precision) ] + 1 +func (c constApproximation) withPrecision(precision int32) Decimal { + i := 0 + + if precision >= 1 { + i++ + } + + for precision >= 16 { + precision /= 16 + i += 4 + } + + for precision >= 2 { + precision /= 2 + i++ + } + + if i >= len(c.approximations) { + return c.exact + } + + return c.approximations[i] +} diff --git a/vendor/github.com/shopspring/decimal/decimal.go b/vendor/github.com/shopspring/decimal/decimal.go index 84405ec1c..a37a2301e 100644 --- a/vendor/github.com/shopspring/decimal/decimal.go +++ b/vendor/github.com/shopspring/decimal/decimal.go @@ -4,14 +4,14 @@ // // The best way to create a new Decimal is to use decimal.NewFromString, ex: // -// n, err := decimal.NewFromString("-123.4567") -// n.String() // output: "-123.4567" +// n, err := decimal.NewFromString("-123.4567") +// n.String() // output: "-123.4567" // // To use Decimal as part of a struct: // -// type Struct struct { -// Number Decimal -// } +// type StructName struct { +// Number Decimal +// } // // Note: This can "only" represent numbers with a maximum of 2^31 digits after the decimal point. package decimal @@ -32,18 +32,31 @@ import ( // // Example: // -// d1 := decimal.NewFromFloat(2).Div(decimal.NewFromFloat(3)) -// d1.String() // output: "0.6666666666666667" -// d2 := decimal.NewFromFloat(2).Div(decimal.NewFromFloat(30000)) -// d2.String() // output: "0.0000666666666667" -// d3 := decimal.NewFromFloat(20000).Div(decimal.NewFromFloat(3)) -// d3.String() // output: "6666.6666666666666667" -// decimal.DivisionPrecision = 3 -// d4 := decimal.NewFromFloat(2).Div(decimal.NewFromFloat(3)) -// d4.String() // output: "0.667" -// +// d1 := decimal.NewFromFloat(2).Div(decimal.NewFromFloat(3)) +// d1.String() // output: "0.6666666666666667" +// d2 := decimal.NewFromFloat(2).Div(decimal.NewFromFloat(30000)) +// d2.String() // output: "0.0000666666666667" +// d3 := decimal.NewFromFloat(20000).Div(decimal.NewFromFloat(3)) +// d3.String() // output: "6666.6666666666666667" +// decimal.DivisionPrecision = 3 +// d4 := decimal.NewFromFloat(2).Div(decimal.NewFromFloat(3)) +// d4.String() // output: "0.667" var DivisionPrecision = 16 +// PowPrecisionNegativeExponent specifies the maximum precision of the result (digits after decimal point) +// when calculating decimal power. Only used for cases where the exponent is a negative number. +// This constant applies to Pow, PowInt32 and PowBigInt methods, PowWithPrecision method is not constrained by it. +// +// Example: +// +// d1, err := decimal.NewFromFloat(15.2).PowInt32(-2) +// d1.String() // output: "0.0043282548476454" +// +// decimal.PowPrecisionNegativeExponent = 24 +// d2, err := decimal.NewFromFloat(15.2).PowInt32(-2) +// d2.String() // output: "0.004328254847645429362881" +var PowPrecisionNegativeExponent = 16 + // MarshalJSONWithoutQuotes should be set to true if you want the decimal to // be JSON marshaled as a number, instead of as a string. // WARNING: this is dangerous for decimals with many digits, since many JSON @@ -91,12 +104,12 @@ func New(value int64, exp int32) Decimal { } } -// NewFromInt converts a int64 to Decimal. +// NewFromInt converts an int64 to Decimal. // // Example: // -// NewFromInt(123).String() // output: "123" -// NewFromInt(-10).String() // output: "-10" +// NewFromInt(123).String() // output: "123" +// NewFromInt(-10).String() // output: "-10" func NewFromInt(value int64) Decimal { return Decimal{ value: big.NewInt(value), @@ -104,12 +117,12 @@ func NewFromInt(value int64) Decimal { } } -// NewFromInt32 converts a int32 to Decimal. +// NewFromInt32 converts an int32 to Decimal. // // Example: // -// NewFromInt(123).String() // output: "123" -// NewFromInt(-10).String() // output: "-10" +// NewFromInt(123).String() // output: "123" +// NewFromInt(-10).String() // output: "-10" func NewFromInt32(value int32) Decimal { return Decimal{ value: big.NewInt(int64(value)), @@ -117,6 +130,18 @@ func NewFromInt32(value int32) Decimal { } } +// NewFromUint64 converts an uint64 to Decimal. +// +// Example: +// +// NewFromUint64(123).String() // output: "123" +func NewFromUint64(value uint64) Decimal { + return Decimal{ + value: new(big.Int).SetUint64(value), + exp: 0, + } +} + // NewFromBigInt returns a new Decimal from a big.Int, value * 10 ^ exp func NewFromBigInt(value *big.Int, exp int32) Decimal { return Decimal{ @@ -125,15 +150,33 @@ func NewFromBigInt(value *big.Int, exp int32) Decimal { } } +// NewFromBigRat returns a new Decimal from a big.Rat. The numerator and +// denominator are divided and rounded to the given precision. +// +// Example: +// +// d1 := NewFromBigRat(big.NewRat(0, 1), 0) // output: "0" +// d2 := NewFromBigRat(big.NewRat(4, 5), 1) // output: "0.8" +// d3 := NewFromBigRat(big.NewRat(1000, 3), 3) // output: "333.333" +// d4 := NewFromBigRat(big.NewRat(2, 7), 4) // output: "0.2857" +func NewFromBigRat(value *big.Rat, precision int32) Decimal { + return Decimal{ + value: new(big.Int).Set(value.Num()), + exp: 0, + }.DivRound(Decimal{ + value: new(big.Int).Set(value.Denom()), + exp: 0, + }, precision) +} + // NewFromString returns a new Decimal from a string representation. // Trailing zeroes are not trimmed. // // Example: // -// d, err := NewFromString("-123.45") -// d2, err := NewFromString(".0001") -// d3, err := NewFromString("1.47000") -// +// d, err := NewFromString("-123.45") +// d2, err := NewFromString(".0001") +// d3, err := NewFromString("1.47000") func NewFromString(value string) (Decimal, error) { originalInput := value var intString string @@ -211,15 +254,14 @@ func NewFromString(value string) (Decimal, error) { // // Example: // -// r := regexp.MustCompile("[$,]") -// d1, err := NewFromFormattedString("$5,125.99", r) +// r := regexp.MustCompile("[$,]") +// d1, err := NewFromFormattedString("$5,125.99", r) // -// r2 := regexp.MustCompile("[_]") -// d2, err := NewFromFormattedString("1_000_000", r2) -// -// r3 := regexp.MustCompile("[USD\\s]") -// d3, err := NewFromFormattedString("5000 USD", r3) +// r2 := regexp.MustCompile("[_]") +// d2, err := NewFromFormattedString("1_000_000", r2) // +// r3 := regexp.MustCompile("[USD\\s]") +// d3, err := NewFromFormattedString("5000 USD", r3) func NewFromFormattedString(value string, replRegexp *regexp.Regexp) (Decimal, error) { parsedValue := replRegexp.ReplaceAllString(value, "") d, err := NewFromString(parsedValue) @@ -230,13 +272,12 @@ func NewFromFormattedString(value string, replRegexp *regexp.Regexp) (Decimal, e } // RequireFromString returns a new Decimal from a string representation -// or panics if NewFromString would have returned an error. +// or panics if NewFromString had returned an error. // // Example: // -// d := RequireFromString("-123.45") -// d2 := RequireFromString(".0001") -// +// d := RequireFromString("-123.45") +// d2 := RequireFromString(".0001") func RequireFromString(value string) Decimal { dec, err := NewFromString(value) if err != nil { @@ -332,8 +373,7 @@ func newFromFloat(val float64, bits uint64, flt *floatInfo) Decimal { // // Example: // -// NewFromFloatWithExponent(123.456, -2).String() // output: "123.46" -// +// NewFromFloatWithExponent(123.456, -2).String() // output: "123.46" func NewFromFloatWithExponent(value float64, exp int32) Decimal { if math.IsNaN(value) || math.IsInf(value, 0) { panic(fmt.Sprintf("Cannot create a Decimal from %v", value)) @@ -418,7 +458,7 @@ func NewFromFloatWithExponent(value float64, exp int32) Decimal { func (d Decimal) Copy() Decimal { d.ensureInitialized() return Decimal{ - value: &(*d.value), + value: new(big.Int).Set(d.value), exp: d.exp, } } @@ -430,7 +470,7 @@ func (d Decimal) Copy() Decimal { // // Example: // -// d := New(12345, -4) +// d := New(12345, -4) // d2 := d.rescale(-1) // d3 := d2.rescale(-4) // println(d1) @@ -442,7 +482,6 @@ func (d Decimal) Copy() Decimal { // 1.2345 // 1.2 // 1.2000 -// func (d Decimal) rescale(exp int32) Decimal { d.ensureInitialized() @@ -552,11 +591,13 @@ func (d Decimal) Div(d2 Decimal) Decimal { return d.DivRound(d2, int32(DivisionPrecision)) } -// QuoRem does divsion with remainder +// QuoRem does division with remainder // d.QuoRem(d2,precision) returns quotient q and remainder r such that -// d = d2 * q + r, q an integer multiple of 10^(-precision) -// 0 <= r < abs(d2) * 10 ^(-precision) if d>=0 -// 0 >= r > -abs(d2) * 10 ^(-precision) if d<0 +// +// d = d2 * q + r, q an integer multiple of 10^(-precision) +// 0 <= r < abs(d2) * 10 ^(-precision) if d>=0 +// 0 >= r > -abs(d2) * 10 ^(-precision) if d<0 +// // Note that precision<0 is allowed as input. func (d Decimal) QuoRem(d2 Decimal, precision int32) (Decimal, Decimal) { d.ensureInitialized() @@ -565,7 +606,7 @@ func (d Decimal) QuoRem(d2 Decimal, precision int32) (Decimal, Decimal) { panic("decimal division by 0") } scale := -precision - e := int64(d.exp - d2.exp - scale) + e := int64(d.exp) - int64(d2.exp) - int64(scale) if e > math.MaxInt32 || e < math.MinInt32 { panic("overflow in decimal QuoRem") } @@ -599,8 +640,10 @@ func (d Decimal) QuoRem(d2 Decimal, precision int32) (Decimal, Decimal) { // DivRound divides and rounds to a given precision // i.e. to an integer multiple of 10^(-precision) -// for a positive quotient digit 5 is rounded up, away from 0 -// if the quotient is negative then digit 5 is rounded down, away from 0 +// +// for a positive quotient digit 5 is rounded up, away from 0 +// if the quotient is negative then digit 5 is rounded down, away from 0 +// // Note that precision<0 is allowed as input. func (d Decimal) DivRound(d2 Decimal, precision int32) Decimal { // QuoRem already checks initialization @@ -628,24 +671,278 @@ func (d Decimal) DivRound(d2 Decimal, precision int32) Decimal { // Mod returns d % d2. func (d Decimal) Mod(d2 Decimal) Decimal { - quo := d.Div(d2).Truncate(0) - return d.Sub(d2.Mul(quo)) + _, r := d.QuoRem(d2, 0) + return r } -// Pow returns d to the power d2 +// Pow returns d to the power of d2. +// When exponent is negative the returned decimal will have maximum precision of PowPrecisionNegativeExponent places after decimal point. +// +// Pow returns 0 (zero-value of Decimal) instead of error for power operation edge cases, to handle those edge cases use PowWithPrecision +// Edge cases not handled by Pow: +// - 0 ** 0 => undefined value +// - 0 ** y, where y < 0 => infinity +// - x ** y, where x < 0 and y is non-integer decimal => imaginary value +// +// Example: +// +// d1 := decimal.NewFromFloat(4.0) +// d2 := decimal.NewFromFloat(4.0) +// res1 := d1.Pow(d2) +// res1.String() // output: "256" +// +// d3 := decimal.NewFromFloat(5.0) +// d4 := decimal.NewFromFloat(5.73) +// res2 := d3.Pow(d4) +// res2.String() // output: "10118.08037125" func (d Decimal) Pow(d2 Decimal) Decimal { - var temp Decimal - if d2.IntPart() == 0 { - return NewFromFloat(1) + baseSign := d.Sign() + expSign := d2.Sign() + + if baseSign == 0 { + if expSign == 0 { + return Decimal{} + } + if expSign == 1 { + return Decimal{zeroInt, 0} + } + if expSign == -1 { + return Decimal{} + } + } + + if expSign == 0 { + return Decimal{oneInt, 0} + } + + // TODO: optimize extraction of fractional part + one := Decimal{oneInt, 0} + expIntPart, expFracPart := d2.QuoRem(one, 0) + + if baseSign == -1 && !expFracPart.IsZero() { + return Decimal{} + } + + intPartPow, _ := d.PowBigInt(expIntPart.value) + + // if exponent is an integer we don't need to calculate d1**frac(d2) + if expFracPart.value.Sign() == 0 { + return intPartPow + } + + // TODO: optimize NumDigits for more performant precision adjustment + digitsBase := d.NumDigits() + digitsExponent := d2.NumDigits() + + precision := digitsBase + + if digitsExponent > precision { + precision += digitsExponent + } + + precision += 6 + + // Calculate x ** frac(y), where + // x ** frac(y) = exp(ln(x ** frac(y)) = exp(ln(x) * frac(y)) + fracPartPow, err := d.Abs().Ln(-d.exp + int32(precision)) + if err != nil { + return Decimal{} + } + + fracPartPow = fracPartPow.Mul(expFracPart) + + fracPartPow, err = fracPartPow.ExpTaylor(-d.exp + int32(precision)) + if err != nil { + return Decimal{} + } + + // Join integer and fractional part, + // base ** (expBase + expFrac) = base ** expBase * base ** expFrac + res := intPartPow.Mul(fracPartPow) + + return res +} + +// PowWithPrecision returns d to the power of d2. +// Precision parameter specifies minimum precision of the result (digits after decimal point). +// Returned decimal is not rounded to 'precision' places after decimal point. +// +// PowWithPrecision returns error when: +// - 0 ** 0 => undefined value +// - 0 ** y, where y < 0 => infinity +// - x ** y, where x < 0 and y is non-integer decimal => imaginary value +// +// Example: +// +// d1 := decimal.NewFromFloat(4.0) +// d2 := decimal.NewFromFloat(4.0) +// res1, err := d1.PowWithPrecision(d2, 2) +// res1.String() // output: "256" +// +// d3 := decimal.NewFromFloat(5.0) +// d4 := decimal.NewFromFloat(5.73) +// res2, err := d3.PowWithPrecision(d4, 5) +// res2.String() // output: "10118.080371595015625" +// +// d5 := decimal.NewFromFloat(-3.0) +// d6 := decimal.NewFromFloat(-6.0) +// res3, err := d5.PowWithPrecision(d6, 10) +// res3.String() // output: "0.0013717421" +func (d Decimal) PowWithPrecision(d2 Decimal, precision int32) (Decimal, error) { + baseSign := d.Sign() + expSign := d2.Sign() + + if baseSign == 0 { + if expSign == 0 { + return Decimal{}, fmt.Errorf("cannot represent undefined value of 0**0") + } + if expSign == 1 { + return Decimal{zeroInt, 0}, nil + } + if expSign == -1 { + return Decimal{}, fmt.Errorf("cannot represent infinity value of 0 ** y, where y < 0") + } + } + + if expSign == 0 { + return Decimal{oneInt, 0}, nil + } + + // TODO: optimize extraction of fractional part + one := Decimal{oneInt, 0} + expIntPart, expFracPart := d2.QuoRem(one, 0) + + if baseSign == -1 && !expFracPart.IsZero() { + return Decimal{}, fmt.Errorf("cannot represent imaginary value of x ** y, where x < 0 and y is non-integer decimal") + } + + intPartPow, _ := d.powBigIntWithPrecision(expIntPart.value, precision) + + // if exponent is an integer we don't need to calculate d1**frac(d2) + if expFracPart.value.Sign() == 0 { + return intPartPow, nil + } + + // TODO: optimize NumDigits for more performant precision adjustment + digitsBase := d.NumDigits() + digitsExponent := d2.NumDigits() + + if int32(digitsBase) > precision { + precision = int32(digitsBase) + } + if int32(digitsExponent) > precision { + precision += int32(digitsExponent) + } + // increase precision by 10 to compensate for errors in further calculations + precision += 10 + + // Calculate x ** frac(y), where + // x ** frac(y) = exp(ln(x ** frac(y)) = exp(ln(x) * frac(y)) + fracPartPow, err := d.Abs().Ln(precision) + if err != nil { + return Decimal{}, err + } + + fracPartPow = fracPartPow.Mul(expFracPart) + + fracPartPow, err = fracPartPow.ExpTaylor(precision) + if err != nil { + return Decimal{}, err + } + + // Join integer and fractional part, + // base ** (expBase + expFrac) = base ** expBase * base ** expFrac + res := intPartPow.Mul(fracPartPow) + + return res, nil +} + +// PowInt32 returns d to the power of exp, where exp is int32. +// Only returns error when d and exp is 0, thus result is undefined. +// +// When exponent is negative the returned decimal will have maximum precision of PowPrecisionNegativeExponent places after decimal point. +// +// Example: +// +// d1, err := decimal.NewFromFloat(4.0).PowInt32(4) +// d1.String() // output: "256" +// +// d2, err := decimal.NewFromFloat(3.13).PowInt32(5) +// d2.String() // output: "300.4150512793" +func (d Decimal) PowInt32(exp int32) (Decimal, error) { + if d.IsZero() && exp == 0 { + return Decimal{}, fmt.Errorf("cannot represent undefined value of 0**0") + } + + isExpNeg := exp < 0 + exp = abs(exp) + + n, result := d, New(1, 0) + + for exp > 0 { + if exp%2 == 1 { + result = result.Mul(n) + } + exp /= 2 + + if exp > 0 { + n = n.Mul(n) + } + } + + if isExpNeg { + return New(1, 0).DivRound(result, int32(PowPrecisionNegativeExponent)), nil + } + + return result, nil +} + +// PowBigInt returns d to the power of exp, where exp is big.Int. +// Only returns error when d and exp is 0, thus result is undefined. +// +// When exponent is negative the returned decimal will have maximum precision of PowPrecisionNegativeExponent places after decimal point. +// +// Example: +// +// d1, err := decimal.NewFromFloat(3.0).PowBigInt(big.NewInt(3)) +// d1.String() // output: "27" +// +// d2, err := decimal.NewFromFloat(629.25).PowBigInt(big.NewInt(5)) +// d2.String() // output: "98654323103449.5673828125" +func (d Decimal) PowBigInt(exp *big.Int) (Decimal, error) { + return d.powBigIntWithPrecision(exp, int32(PowPrecisionNegativeExponent)) +} + +func (d Decimal) powBigIntWithPrecision(exp *big.Int, precision int32) (Decimal, error) { + if d.IsZero() && exp.Sign() == 0 { + return Decimal{}, fmt.Errorf("cannot represent undefined value of 0**0") } - temp = d.Pow(d2.Div(NewFromFloat(2))) - if d2.IntPart()%2 == 0 { - return temp.Mul(temp) + + tmpExp := new(big.Int).Set(exp) + isExpNeg := exp.Sign() < 0 + + if isExpNeg { + tmpExp.Abs(tmpExp) + } + + n, result := d, New(1, 0) + + for tmpExp.Sign() > 0 { + if tmpExp.Bit(0) == 1 { + result = result.Mul(n) + } + tmpExp.Rsh(tmpExp, 1) + + if tmpExp.Sign() > 0 { + n = n.Mul(n) + } } - if d2.IntPart() > 0 { - return temp.Mul(temp).Mul(d) + + if isExpNeg { + return New(1, 0).DivRound(result, precision), nil } - return temp.Mul(temp).Div(d) + + return result, nil } // ExpHullAbrham calculates the natural exponent of decimal (e to the power of d) using Hull-Abraham algorithm. @@ -655,9 +952,8 @@ func (d Decimal) Pow(d2 Decimal) Decimal { // // Example: // -// NewFromFloat(26.1).ExpHullAbrham(2).String() // output: "220000000000" -// NewFromFloat(26.1).ExpHullAbrham(20).String() // output: "216314672147.05767284" -// +// NewFromFloat(26.1).ExpHullAbrham(2).String() // output: "220000000000" +// NewFromFloat(26.1).ExpHullAbrham(20).String() // output: "216314672147.05767284" func (d Decimal) ExpHullAbrham(overallPrecision uint32) (Decimal, error) { // Algorithm based on Variable precision exponential function. // ACM Transactions on Mathematical Software by T. E. Hull & A. Abrham. @@ -747,15 +1043,14 @@ func (d Decimal) ExpHullAbrham(overallPrecision uint32) (Decimal, error) { // // Example: // -// d, err := NewFromFloat(26.1).ExpTaylor(2).String() -// d.String() // output: "216314672147.06" -// -// NewFromFloat(26.1).ExpTaylor(20).String() -// d.String() // output: "216314672147.05767284062928674083" +// d, err := NewFromFloat(26.1).ExpTaylor(2).String() +// d.String() // output: "216314672147.06" // -// NewFromFloat(26.1).ExpTaylor(-10).String() -// d.String() // output: "220000000000" +// NewFromFloat(26.1).ExpTaylor(20).String() +// d.String() // output: "216314672147.05767284062928674083" // +// NewFromFloat(26.1).ExpTaylor(-10).String() +// d.String() // output: "220000000000" func (d Decimal) ExpTaylor(precision int32) (Decimal, error) { // Note(mwoss): Implementation can be optimized by exclusively using big.Int API only if d.IsZero() { @@ -812,14 +1107,162 @@ func (d Decimal) ExpTaylor(precision int32) (Decimal, error) { return result, nil } +// Ln calculates natural logarithm of d. +// Precision argument specifies how precise the result must be (number of digits after decimal point). +// Negative precision is allowed. +// +// Example: +// +// d1, err := NewFromFloat(13.3).Ln(2) +// d1.String() // output: "2.59" +// +// d2, err := NewFromFloat(579.161).Ln(10) +// d2.String() // output: "6.3615805046" +func (d Decimal) Ln(precision int32) (Decimal, error) { + // Algorithm based on The Use of Iteration Methods for Approximating the Natural Logarithm, + // James F. Epperson, The American Mathematical Monthly, Vol. 96, No. 9, November 1989, pp. 831-835. + if d.IsNegative() { + return Decimal{}, fmt.Errorf("cannot calculate natural logarithm for negative decimals") + } + + if d.IsZero() { + return Decimal{}, fmt.Errorf("cannot represent natural logarithm of 0, result: -infinity") + } + + calcPrecision := precision + 2 + z := d.Copy() + + var comp1, comp3, comp2, comp4, reduceAdjust Decimal + comp1 = z.Sub(Decimal{oneInt, 0}) + comp3 = Decimal{oneInt, -1} + + // for decimal in range [0.9, 1.1] where ln(d) is close to 0 + usePowerSeries := false + + if comp1.Abs().Cmp(comp3) <= 0 { + usePowerSeries = true + } else { + // reduce input decimal to range [0.1, 1) + expDelta := int32(z.NumDigits()) + z.exp + z.exp -= expDelta + + // Input decimal was reduced by factor of 10^expDelta, thus we will need to add + // ln(10^expDelta) = expDelta * ln(10) + // to the result to compensate that + ln10 := ln10.withPrecision(calcPrecision) + reduceAdjust = NewFromInt32(expDelta) + reduceAdjust = reduceAdjust.Mul(ln10) + + comp1 = z.Sub(Decimal{oneInt, 0}) + + if comp1.Abs().Cmp(comp3) <= 0 { + usePowerSeries = true + } else { + // initial estimate using floats + zFloat := z.InexactFloat64() + comp1 = NewFromFloat(math.Log(zFloat)) + } + } + + epsilon := Decimal{oneInt, -calcPrecision} + + if usePowerSeries { + // Power Series - https://en.wikipedia.org/wiki/Logarithm#Power_series + // Calculating n-th term of formula: ln(z+1) = 2 sum [ 1 / (2n+1) * (z / (z+2))^(2n+1) ] + // until the difference between current and next term is smaller than epsilon. + // Coverage quite fast for decimals close to 1.0 + + // z + 2 + comp2 = comp1.Add(Decimal{twoInt, 0}) + // z / (z + 2) + comp3 = comp1.DivRound(comp2, calcPrecision) + // 2 * (z / (z + 2)) + comp1 = comp3.Add(comp3) + comp2 = comp1.Copy() + + for n := 1; ; n++ { + // 2 * (z / (z+2))^(2n+1) + comp2 = comp2.Mul(comp3).Mul(comp3) + + // 1 / (2n+1) * 2 * (z / (z+2))^(2n+1) + comp4 = NewFromInt(int64(2*n + 1)) + comp4 = comp2.DivRound(comp4, calcPrecision) + + // comp1 = 2 sum [ 1 / (2n+1) * (z / (z+2))^(2n+1) ] + comp1 = comp1.Add(comp4) + + if comp4.Abs().Cmp(epsilon) <= 0 { + break + } + } + } else { + // Halley's Iteration. + // Calculating n-th term of formula: a_(n+1) = a_n - 2 * (exp(a_n) - z) / (exp(a_n) + z), + // until the difference between current and next term is smaller than epsilon + var prevStep Decimal + maxIters := calcPrecision*2 + 10 + + for i := int32(0); i < maxIters; i++ { + // exp(a_n) + comp3, _ = comp1.ExpTaylor(calcPrecision) + // exp(a_n) - z + comp2 = comp3.Sub(z) + // 2 * (exp(a_n) - z) + comp2 = comp2.Add(comp2) + // exp(a_n) + z + comp4 = comp3.Add(z) + // 2 * (exp(a_n) - z) / (exp(a_n) + z) + comp3 = comp2.DivRound(comp4, calcPrecision) + // comp1 = a_(n+1) = a_n - 2 * (exp(a_n) - z) / (exp(a_n) + z) + comp1 = comp1.Sub(comp3) + + if prevStep.Add(comp3).IsZero() { + // If iteration steps oscillate we should return early and prevent an infinity loop + // NOTE(mwoss): This should be quite a rare case, returning error is not necessary + break + } + + if comp3.Abs().Cmp(epsilon) <= 0 { + break + } + + prevStep = comp3 + } + } + + comp1 = comp1.Add(reduceAdjust) + + return comp1.Round(precision), nil +} + // NumDigits returns the number of digits of the decimal coefficient (d.Value) -// Note: Current implementation is extremely slow for large decimals and/or decimals with large fractional part func (d Decimal) NumDigits() int { - // Note(mwoss): It can be optimized, unnecessary cast of big.Int to string - if d.IsNegative() { - return len(d.value.String()) - 1 + if d.value == nil { + return 1 + } + + if d.value.IsInt64() { + i64 := d.value.Int64() + // restrict fast path to integers with exact conversion to float64 + if i64 <= (1<<53) && i64 >= -(1<<53) { + if i64 == 0 { + return 1 + } + return int(math.Log10(math.Abs(float64(i64)))) + 1 + } + } + + estimatedNumDigits := int(float64(d.value.BitLen()) / math.Log2(10)) + + // estimatedNumDigits (lg10) may be off by 1, need to verify + digitsBigInt := big.NewInt(int64(estimatedNumDigits)) + errorCorrectionUnit := digitsBigInt.Exp(tenInt, digitsBigInt, nil) + + if d.value.CmpAbs(errorCorrectionUnit) >= 0 { + return estimatedNumDigits + 1 } - return len(d.value.String()) + + return estimatedNumDigits } // IsInteger returns true when decimal can be represented as an integer value, otherwise, it returns false. @@ -851,10 +1294,9 @@ func abs(n int32) int32 { // Cmp compares the numbers represented by d and d2 and returns: // -// -1 if d < d2 -// 0 if d == d2 -// +1 if d > d2 -// +// -1 if d < d2 +// 0 if d == d2 +// +1 if d > d2 func (d Decimal) Cmp(d2 Decimal) int { d.ensureInitialized() d2.ensureInitialized() @@ -868,12 +1310,21 @@ func (d Decimal) Cmp(d2 Decimal) int { return rd.value.Cmp(rd2.value) } +// Compare compares the numbers represented by d and d2 and returns: +// +// -1 if d < d2 +// 0 if d == d2 +// +1 if d > d2 +func (d Decimal) Compare(d2 Decimal) int { + return d.Cmp(d2) +} + // Equal returns whether the numbers represented by d and d2 are equal. func (d Decimal) Equal(d2 Decimal) bool { return d.Cmp(d2) == 0 } -// Equals is deprecated, please use Equal method instead +// Deprecated: Equals is deprecated, please use Equal method instead. func (d Decimal) Equals(d2 Decimal) bool { return d.Equal(d2) } @@ -905,7 +1356,6 @@ func (d Decimal) LessThanOrEqual(d2 Decimal) bool { // -1 if d < 0 // 0 if d == 0 // +1 if d > 0 -// func (d Decimal) Sign() int { if d.value == nil { return 0 @@ -968,9 +1418,7 @@ func (d Decimal) IntPart() int64 { // BigInt returns integer component of the decimal as a BigInt. func (d Decimal) BigInt() *big.Int { scaledD := d.rescale(0) - i := &big.Int{} - i.SetString(scaledD.String(), 10) - return i + return scaledD.value } // BigFloat returns decimal as BigFloat. @@ -1014,13 +1462,12 @@ func (d Decimal) InexactFloat64() float64 { // // Example: // -// d := New(-12345, -3) -// println(d.String()) +// d := New(-12345, -3) +// println(d.String()) // // Output: // -// -12.345 -// +// -12.345 func (d Decimal) String() string { return d.string(true) } @@ -1030,14 +1477,13 @@ func (d Decimal) String() string { // // Example: // -// NewFromFloat(0).StringFixed(2) // output: "0.00" -// NewFromFloat(0).StringFixed(0) // output: "0" -// NewFromFloat(5.45).StringFixed(0) // output: "5" -// NewFromFloat(5.45).StringFixed(1) // output: "5.5" -// NewFromFloat(5.45).StringFixed(2) // output: "5.45" -// NewFromFloat(5.45).StringFixed(3) // output: "5.450" -// NewFromFloat(545).StringFixed(-1) // output: "550" -// +// NewFromFloat(0).StringFixed(2) // output: "0.00" +// NewFromFloat(0).StringFixed(0) // output: "0" +// NewFromFloat(5.45).StringFixed(0) // output: "5" +// NewFromFloat(5.45).StringFixed(1) // output: "5.5" +// NewFromFloat(5.45).StringFixed(2) // output: "5.45" +// NewFromFloat(5.45).StringFixed(3) // output: "5.450" +// NewFromFloat(545).StringFixed(-1) // output: "550" func (d Decimal) StringFixed(places int32) string { rounded := d.Round(places) return rounded.string(false) @@ -1048,14 +1494,13 @@ func (d Decimal) StringFixed(places int32) string { // // Example: // -// NewFromFloat(0).StringFixedBank(2) // output: "0.00" -// NewFromFloat(0).StringFixedBank(0) // output: "0" -// NewFromFloat(5.45).StringFixedBank(0) // output: "5" -// NewFromFloat(5.45).StringFixedBank(1) // output: "5.4" -// NewFromFloat(5.45).StringFixedBank(2) // output: "5.45" -// NewFromFloat(5.45).StringFixedBank(3) // output: "5.450" -// NewFromFloat(545).StringFixedBank(-1) // output: "540" -// +// NewFromFloat(0).StringFixedBank(2) // output: "0.00" +// NewFromFloat(0).StringFixedBank(0) // output: "0" +// NewFromFloat(5.45).StringFixedBank(0) // output: "5" +// NewFromFloat(5.45).StringFixedBank(1) // output: "5.4" +// NewFromFloat(5.45).StringFixedBank(2) // output: "5.45" +// NewFromFloat(5.45).StringFixedBank(3) // output: "5.450" +// NewFromFloat(545).StringFixedBank(-1) // output: "540" func (d Decimal) StringFixedBank(places int32) string { rounded := d.RoundBank(places) return rounded.string(false) @@ -1073,9 +1518,8 @@ func (d Decimal) StringFixedCash(interval uint8) string { // // Example: // -// NewFromFloat(5.45).Round(1).String() // output: "5.5" -// NewFromFloat(545).Round(-1).String() // output: "550" -// +// NewFromFloat(5.45).Round(1).String() // output: "5.5" +// NewFromFloat(545).Round(-1).String() // output: "550" func (d Decimal) Round(places int32) Decimal { if d.exp == -places { return d @@ -1104,11 +1548,10 @@ func (d Decimal) Round(places int32) Decimal { // // Example: // -// NewFromFloat(545).RoundCeil(-2).String() // output: "600" -// NewFromFloat(500).RoundCeil(-2).String() // output: "500" -// NewFromFloat(1.1001).RoundCeil(2).String() // output: "1.11" -// NewFromFloat(-1.454).RoundCeil(1).String() // output: "-1.5" -// +// NewFromFloat(545).RoundCeil(-2).String() // output: "600" +// NewFromFloat(500).RoundCeil(-2).String() // output: "500" +// NewFromFloat(1.1001).RoundCeil(2).String() // output: "1.11" +// NewFromFloat(-1.454).RoundCeil(1).String() // output: "-1.4" func (d Decimal) RoundCeil(places int32) Decimal { if d.exp >= -places { return d @@ -1130,11 +1573,10 @@ func (d Decimal) RoundCeil(places int32) Decimal { // // Example: // -// NewFromFloat(545).RoundFloor(-2).String() // output: "500" -// NewFromFloat(-500).RoundFloor(-2).String() // output: "-500" -// NewFromFloat(1.1001).RoundFloor(2).String() // output: "1.1" -// NewFromFloat(-1.454).RoundFloor(1).String() // output: "-1.4" -// +// NewFromFloat(545).RoundFloor(-2).String() // output: "500" +// NewFromFloat(-500).RoundFloor(-2).String() // output: "-500" +// NewFromFloat(1.1001).RoundFloor(2).String() // output: "1.1" +// NewFromFloat(-1.454).RoundFloor(1).String() // output: "-1.5" func (d Decimal) RoundFloor(places int32) Decimal { if d.exp >= -places { return d @@ -1156,11 +1598,10 @@ func (d Decimal) RoundFloor(places int32) Decimal { // // Example: // -// NewFromFloat(545).RoundUp(-2).String() // output: "600" -// NewFromFloat(500).RoundUp(-2).String() // output: "500" -// NewFromFloat(1.1001).RoundUp(2).String() // output: "1.11" -// NewFromFloat(-1.454).RoundUp(1).String() // output: "-1.4" -// +// NewFromFloat(545).RoundUp(-2).String() // output: "600" +// NewFromFloat(500).RoundUp(-2).String() // output: "500" +// NewFromFloat(1.1001).RoundUp(2).String() // output: "1.11" +// NewFromFloat(-1.454).RoundUp(1).String() // output: "-1.5" func (d Decimal) RoundUp(places int32) Decimal { if d.exp >= -places { return d @@ -1184,11 +1625,10 @@ func (d Decimal) RoundUp(places int32) Decimal { // // Example: // -// NewFromFloat(545).RoundDown(-2).String() // output: "500" -// NewFromFloat(-500).RoundDown(-2).String() // output: "-500" -// NewFromFloat(1.1001).RoundDown(2).String() // output: "1.1" -// NewFromFloat(-1.454).RoundDown(1).String() // output: "-1.5" -// +// NewFromFloat(545).RoundDown(-2).String() // output: "500" +// NewFromFloat(-500).RoundDown(-2).String() // output: "-500" +// NewFromFloat(1.1001).RoundDown(2).String() // output: "1.1" +// NewFromFloat(-1.454).RoundDown(1).String() // output: "-1.4" func (d Decimal) RoundDown(places int32) Decimal { if d.exp >= -places { return d @@ -1209,13 +1649,12 @@ func (d Decimal) RoundDown(places int32) Decimal { // // Examples: // -// NewFromFloat(5.45).RoundBank(1).String() // output: "5.4" -// NewFromFloat(545).RoundBank(-1).String() // output: "540" -// NewFromFloat(5.46).RoundBank(1).String() // output: "5.5" -// NewFromFloat(546).RoundBank(-1).String() // output: "550" -// NewFromFloat(5.55).RoundBank(1).String() // output: "5.6" -// NewFromFloat(555).RoundBank(-1).String() // output: "560" -// +// NewFromFloat(5.45).RoundBank(1).String() // output: "5.4" +// NewFromFloat(545).RoundBank(-1).String() // output: "540" +// NewFromFloat(5.46).RoundBank(1).String() // output: "5.5" +// NewFromFloat(546).RoundBank(-1).String() // output: "550" +// NewFromFloat(5.55).RoundBank(1).String() // output: "5.6" +// NewFromFloat(555).RoundBank(-1).String() // output: "560" func (d Decimal) RoundBank(places int32) Decimal { round := d.Round(places) @@ -1237,11 +1676,13 @@ func (d Decimal) RoundBank(places int32) Decimal { // interval. The amount payable for a cash transaction is rounded to the nearest // multiple of the minimum currency unit available. The following intervals are // available: 5, 10, 25, 50 and 100; any other number throws a panic. -// 5: 5 cent rounding 3.43 => 3.45 -// 10: 10 cent rounding 3.45 => 3.50 (5 gets rounded up) -// 25: 25 cent rounding 3.41 => 3.50 -// 50: 50 cent rounding 3.75 => 4.00 -// 100: 100 cent rounding 3.50 => 4.00 +// +// 5: 5 cent rounding 3.43 => 3.45 +// 10: 10 cent rounding 3.45 => 3.50 (5 gets rounded up) +// 25: 25 cent rounding 3.41 => 3.50 +// 50: 50 cent rounding 3.75 => 4.00 +// 100: 100 cent rounding 3.50 => 4.00 +// // For more details: https://en.wikipedia.org/wiki/Cash_rounding func (d Decimal) RoundCash(interval uint8) Decimal { var iVal *big.Int @@ -1310,8 +1751,7 @@ func (d Decimal) Ceil() Decimal { // // Example: // -// decimal.NewFromString("123.456").Truncate(2).String() // "123.45" -// +// decimal.NewFromString("123.456").Truncate(2).String() // "123.45" func (d Decimal) Truncate(precision int32) Decimal { d.ensureInitialized() if precision >= 0 && -precision > d.exp { @@ -1373,19 +1813,18 @@ func (d *Decimal) UnmarshalBinary(data []byte) error { // MarshalBinary implements the encoding.BinaryMarshaler interface. func (d Decimal) MarshalBinary() (data []byte, err error) { - // Write the exponent first since it's a fixed size - v1 := make([]byte, 4) - binary.BigEndian.PutUint32(v1, uint32(d.exp)) - - // Add the value - var v2 []byte - if v2, err = d.value.GobEncode(); err != nil { - return + // exp is written first, but encode value first to know output size + var valueData []byte + if valueData, err = d.value.GobEncode(); err != nil { + return nil, err } + // Write the exponent in front, since it's a fixed size + expData := make([]byte, 4, len(valueData)+4) + binary.BigEndian.PutUint32(expData, uint32(d.exp)) + // Return the byte array - data = append(v1, v2...) - return + return append(expData, valueData...), nil } // Scan implements the sql.Scanner interface for database deserialization. @@ -1408,6 +1847,11 @@ func (d *Decimal) Scan(value interface{}) error { *d = New(v, 0) return nil + case uint64: + // while clickhouse may send 0 in db as uint64 + *d = NewFromUint64(v) + return nil + default: // default is trying to interpret value stored as string str, err := unquoteIfQuoted(v) @@ -1455,7 +1899,8 @@ func (d *Decimal) GobDecode(data []byte) error { } // StringScaled first scales the decimal then calls .String() on it. -// NOTE: buggy, unintuitive, and DEPRECATED! Use StringFixed instead. +// +// Deprecated: buggy and unintuitive. Use StringFixed instead. func (d Decimal) StringScaled(exp int32) string { return d.rescale(exp).String() } @@ -1515,7 +1960,7 @@ func (d *Decimal) ensureInitialized() { // // To call this function with an array, you must do: // -// Min(arr[0], arr[1:]...) +// Min(arr[0], arr[1:]...) // // This makes it harder to accidentally call Min with 0 arguments. func Min(first Decimal, rest ...Decimal) Decimal { @@ -1532,7 +1977,7 @@ func Min(first Decimal, rest ...Decimal) Decimal { // // To call this function with an array, you must do: // -// Max(arr[0], arr[1:]...) +// Max(arr[0], arr[1:]...) // // This makes it harder to accidentally call Max with 0 arguments. func Max(first Decimal, rest ...Decimal) Decimal { @@ -1567,22 +2012,13 @@ func RescalePair(d1 Decimal, d2 Decimal) (Decimal, Decimal) { d1.ensureInitialized() d2.ensureInitialized() - if d1.exp == d2.exp { - return d1, d2 + if d1.exp < d2.exp { + return d1, d2.rescale(d1.exp) + } else if d1.exp > d2.exp { + return d1.rescale(d2.exp), d2 } - baseScale := min(d1.exp, d2.exp) - if baseScale != d1.exp { - return d1.rescale(baseScale), d2 - } - return d1, d2.rescale(baseScale) -} - -func min(x, y int32) int32 { - if x >= y { - return y - } - return x + return d1, d2 } func unquoteIfQuoted(value interface{}) (string, error) { @@ -1594,8 +2030,7 @@ func unquoteIfQuoted(value interface{}) (string, error) { case []byte: bytes = v default: - return "", fmt.Errorf("could not convert value '%+v' to byte array of type '%T'", - value, value) + return "", fmt.Errorf("could not convert value '%+v' to byte array of type '%T'", value, value) } // If the amount is quoted, strip the quotes diff --git a/vendor/github.com/toqueteos/webbrowser/.travis.yml b/vendor/github.com/toqueteos/webbrowser/.travis.yml deleted file mode 100644 index b55b114ab..000000000 --- a/vendor/github.com/toqueteos/webbrowser/.travis.yml +++ /dev/null @@ -1,9 +0,0 @@ -language: go - -go: - - 1.2 - - 1.12 - - tip - -script: - - go build ./... diff --git a/vendor/github.com/toqueteos/webbrowser/CONTRIBUTING.md b/vendor/github.com/toqueteos/webbrowser/CONTRIBUTING.md index b9f7bf82a..b701a3a62 100644 --- a/vendor/github.com/toqueteos/webbrowser/CONTRIBUTING.md +++ b/vendor/github.com/toqueteos/webbrowser/CONTRIBUTING.md @@ -7,5 +7,4 @@ Any changes are welcomed! ## Looking for contact info? -- Twitter: [@toqueteos](https://twitter.com/toqueteos) - Mail: `toqueteos AT gmail DOT com` diff --git a/vendor/github.com/toqueteos/webbrowser/LICENSE.md b/vendor/github.com/toqueteos/webbrowser/LICENSE.md index 0d67949ef..e679e09fd 100644 --- a/vendor/github.com/toqueteos/webbrowser/LICENSE.md +++ b/vendor/github.com/toqueteos/webbrowser/LICENSE.md @@ -1,5 +1,5 @@ The MIT License (MIT) -Copyright (c) 2013-19 by Carlos Cobo and contributors. +Copyright (c) 2012-23 by Carlos Cobo and contributors. 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 diff --git a/vendor/github.com/toqueteos/webbrowser/README.md b/vendor/github.com/toqueteos/webbrowser/README.md index 2ce091afb..ed9f4b207 100644 --- a/vendor/github.com/toqueteos/webbrowser/README.md +++ b/vendor/github.com/toqueteos/webbrowser/README.md @@ -1,4 +1,4 @@ -# webbrowser [](https://travis-ci.org/toqueteos/webbrowser) [](http://godoc.org/github.com/toqueteos/webbrowser) [](https://sourcegraph.com/github.com/toqueteos/webbrowser?badge)
+# webbrowser [](https://github.com/toqueteos/webbrowser/actions) [](https://pkg.go.dev/github.com/toqueteos/webbrowser)
webbrowser provides a simple API for opening web pages on your default browser.
@@ -14,6 +14,10 @@ As simple as: go get -u github.com/toqueteos/webbrowser
```
+It is Go modules compatible!
+
+_(`go.mod` was explicitly added in version `v1.2.0`)_
+
## Usage
```go
diff --git a/vendor/github.com/toqueteos/webbrowser/webbrowser.go b/vendor/github.com/toqueteos/webbrowser/webbrowser.go index f4f19b6b3..5a0a4aa7a 100644 --- a/vendor/github.com/toqueteos/webbrowser/webbrowser.go +++ b/vendor/github.com/toqueteos/webbrowser/webbrowser.go @@ -30,9 +30,11 @@ type Browser interface { } // Open tries to open a URL in your default browser ensuring you have a display -// set up and not running this from SSH. NOTE: This may cause your program to -// hang until the browser process is closed in some OSes, see -// https://github.com/toqueteos/webbrowser/issues/4. +// set up and not running this from SSH. +// NOTE: This may cause your program to hang until the browser process is closed in +// some OSes, see https://github.com/toqueteos/webbrowser/issues/4. +// SECURITY(windows): Do not use a file:// URLs pointing to an executable, this +// can execute programs, see https://github.com/toqueteos/webbrowser/issues/10 func Open(s string) (err error) { if len(Candidates) == 0 { return ErrNoCandidates diff --git a/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/extjson_writer.go b/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/extjson_writer.go index 57781ff9f..86a293570 100644 --- a/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/extjson_writer.go +++ b/vendor/go.mongodb.org/mongo-driver/bson/bsonrw/extjson_writer.go @@ -468,12 +468,13 @@ func (ejvw *extJSONValueWriter) WriteRegex(pattern string, options string) error return err } + options = sortStringAlphebeticAscending(options) var buf bytes.Buffer buf.WriteString(`{"$regularExpression":{"pattern":`) writeStringWithEscapes(pattern, &buf, ejvw.escapeHTML) - buf.WriteString(`,"options":"`) - buf.WriteString(sortStringAlphebeticAscending(options)) - buf.WriteString(`"}},`) + buf.WriteString(`,"options":`) + writeStringWithEscapes(options, &buf, ejvw.escapeHTML) + buf.WriteString(`}},`) ejvw.buf = append(ejvw.buf, buf.Bytes()...) diff --git a/vendor/modernc.org/sqlite/CONTRIBUTORS b/vendor/modernc.org/sqlite/CONTRIBUTORS index 625b7dcd2..8c09cfcea 100644 --- a/vendor/modernc.org/sqlite/CONTRIBUTORS +++ b/vendor/modernc.org/sqlite/CONTRIBUTORS @@ -38,5 +38,6 @@ Sean McGivern <sean@mcgivern.me.uk> Steffen Butzer <steffen(dot)butzer@outlook.com> Toni Spets <toni.spets@beeper.com> W. Michael Petullo <mike@flyn.org> +Walter Wanderley <walterwanderley@gmail.com> Yaacov Akiba Slama <ya@slamail.org> Prathyush PV <prathyush.pv@temporal.io> diff --git a/vendor/modernc.org/sqlite/convert.go b/vendor/modernc.org/sqlite/convert.go new file mode 100644 index 000000000..1b19dc60c --- /dev/null +++ b/vendor/modernc.org/sqlite/convert.go @@ -0,0 +1,299 @@ +// Extracted from Go database/sql source code + +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Type conversions for Scan. + +package sqlite + +import ( + "database/sql" + "database/sql/driver" + "errors" + "fmt" + "reflect" + "strconv" + "time" +) + +var errNilPtr = errors.New("destination pointer is nil") // embedded in descriptive error + +// convertAssign copies to dest the value in src, converting it if possible. +// An error is returned if the copy would result in loss of information. +// dest should be a pointer type. +func convertAssign(dest, src interface{}) error { + // Common cases, without reflect. + switch s := src.(type) { + case string: + switch d := dest.(type) { + case *string: + if d == nil { + return errNilPtr + } + *d = s + return nil + case *[]byte: + if d == nil { + return errNilPtr + } + *d = []byte(s) + return nil + case *sql.RawBytes: + if d == nil { + return errNilPtr + } + *d = append((*d)[:0], s...) + return nil + } + case []byte: + switch d := dest.(type) { + case *string: + if d == nil { + return errNilPtr + } + *d = string(s) + return nil + case *interface{}: + if d == nil { + return errNilPtr + } + *d = cloneBytes(s) + return nil + case *[]byte: + if d == nil { + return errNilPtr + } + *d = cloneBytes(s) + return nil + case *sql.RawBytes: + if d == nil { + return errNilPtr + } + *d = s + return nil + } + case time.Time: + switch d := dest.(type) { + case *time.Time: + *d = s + return nil + case *string: + *d = s.Format(time.RFC3339Nano) + return nil + case *[]byte: + if d == nil { + return errNilPtr + } + *d = []byte(s.Format(time.RFC3339Nano)) + return nil + case *sql.RawBytes: + if d == nil { + return errNilPtr + } + *d = s.AppendFormat((*d)[:0], time.RFC3339Nano) + return nil + } + case nil: + switch d := dest.(type) { + case *interface{}: + if d == nil { + return errNilPtr + } + *d = nil + return nil + case *[]byte: + if d == nil { + return errNilPtr + } + *d = nil + return nil + case *sql.RawBytes: + if d == nil { + return errNilPtr + } + *d = nil + return nil + } + } + + var sv reflect.Value + + switch d := dest.(type) { + case *string: + sv = reflect.ValueOf(src) + switch sv.Kind() { + case reflect.Bool, + reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, + reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, + reflect.Float32, reflect.Float64: + *d = asString(src) + return nil + } + case *[]byte: + sv = reflect.ValueOf(src) + if b, ok := asBytes(nil, sv); ok { + *d = b + return nil + } + case *sql.RawBytes: + sv = reflect.ValueOf(src) + if b, ok := asBytes([]byte(*d)[:0], sv); ok { + *d = sql.RawBytes(b) + return nil + } + case *bool: + bv, err := driver.Bool.ConvertValue(src) + if err == nil { + *d = bv.(bool) + } + return err + case *interface{}: + *d = src + return nil + } + + if scanner, ok := dest.(sql.Scanner); ok { + return scanner.Scan(src) + } + + dpv := reflect.ValueOf(dest) + if dpv.Kind() != reflect.Ptr { + return errors.New("destination not a pointer") + } + if dpv.IsNil() { + return errNilPtr + } + + if !sv.IsValid() { + sv = reflect.ValueOf(src) + } + + dv := reflect.Indirect(dpv) + if sv.IsValid() && sv.Type().AssignableTo(dv.Type()) { + switch b := src.(type) { + case []byte: + dv.Set(reflect.ValueOf(cloneBytes(b))) + default: + dv.Set(sv) + } + return nil + } + + if dv.Kind() == sv.Kind() && sv.Type().ConvertibleTo(dv.Type()) { + dv.Set(sv.Convert(dv.Type())) + return nil + } + + // The following conversions use a string value as an intermediate representation + // to convert between various numeric types. + // + // This also allows scanning into user defined types such as "type Int int64". + // For symmetry, also check for string destination types. + switch dv.Kind() { + case reflect.Ptr: + if src == nil { + dv.Set(reflect.Zero(dv.Type())) + return nil + } + dv.Set(reflect.New(dv.Type().Elem())) + return convertAssign(dv.Interface(), src) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + s := asString(src) + i64, err := strconv.ParseInt(s, 10, dv.Type().Bits()) + if err != nil { + err = strconvErr(err) + return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err) + } + dv.SetInt(i64) + return nil + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + s := asString(src) + u64, err := strconv.ParseUint(s, 10, dv.Type().Bits()) + if err != nil { + err = strconvErr(err) + return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err) + } + dv.SetUint(u64) + return nil + case reflect.Float32, reflect.Float64: + s := asString(src) + f64, err := strconv.ParseFloat(s, dv.Type().Bits()) + if err != nil { + err = strconvErr(err) + return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err) + } + dv.SetFloat(f64) + return nil + case reflect.String: + switch v := src.(type) { + case string: + dv.SetString(v) + return nil + case []byte: + dv.SetString(string(v)) + return nil + } + } + + return fmt.Errorf("unsupported Scan, storing driver.Value type %T into type %T", src, dest) +} + +func strconvErr(err error) error { + if ne, ok := err.(*strconv.NumError); ok { + return ne.Err + } + return err +} + +func cloneBytes(b []byte) []byte { + if b == nil { + return nil + } + c := make([]byte, len(b)) + copy(c, b) + return c +} + +func asString(src interface{}) string { + switch v := src.(type) { + case string: + return v + case []byte: + return string(v) + } + rv := reflect.ValueOf(src) + switch rv.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return strconv.FormatInt(rv.Int(), 10) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return strconv.FormatUint(rv.Uint(), 10) + case reflect.Float64: + return strconv.FormatFloat(rv.Float(), 'g', -1, 64) + case reflect.Float32: + return strconv.FormatFloat(rv.Float(), 'g', -1, 32) + case reflect.Bool: + return strconv.FormatBool(rv.Bool()) + } + return fmt.Sprintf("%v", src) +} + +func asBytes(buf []byte, rv reflect.Value) (b []byte, ok bool) { + switch rv.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return strconv.AppendInt(buf, rv.Int(), 10), true + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return strconv.AppendUint(buf, rv.Uint(), 10), true + case reflect.Float32: + return strconv.AppendFloat(buf, rv.Float(), 'g', -1, 32), true + case reflect.Float64: + return strconv.AppendFloat(buf, rv.Float(), 'g', -1, 64), true + case reflect.Bool: + return strconv.AppendBool(buf, rv.Bool()), true + case reflect.String: + s := rv.String() + return append(buf, s...), true + } + return +} diff --git a/vendor/modernc.org/sqlite/pre_update_hook.go b/vendor/modernc.org/sqlite/pre_update_hook.go new file mode 100644 index 000000000..9a00fe5ac --- /dev/null +++ b/vendor/modernc.org/sqlite/pre_update_hook.go @@ -0,0 +1,227 @@ +package sqlite + +import ( + "errors" + "fmt" + "sync" + "unsafe" + + "modernc.org/libc" + "modernc.org/libc/sys/types" + sqlite3 "modernc.org/sqlite/lib" +) + +var ( + xPreUpdateHandlers = struct { + mu sync.RWMutex + m map[uintptr]func(SQLitePreUpdateData) + }{ + m: make(map[uintptr]func(SQLitePreUpdateData)), + } + xCommitHandlers = struct { + mu sync.RWMutex + m map[uintptr]CommitHookFn + }{ + m: make(map[uintptr]CommitHookFn), + } + xRollbackHandlers = struct { + mu sync.RWMutex + m map[uintptr]RollbackHookFn + }{ + m: make(map[uintptr]RollbackHookFn), + } +) + +type PreUpdateHookFn func(SQLitePreUpdateData) + +func (c *conn) RegisterPreUpdateHook(callback PreUpdateHookFn) { + + if callback == nil { + xPreUpdateHandlers.mu.Lock() + delete(xPreUpdateHandlers.m, c.db) + xPreUpdateHandlers.mu.Unlock() + sqlite3.Xsqlite3_preupdate_hook(c.tls, c.db, uintptr(unsafe.Pointer(nil)), uintptr(unsafe.Pointer(nil))) + return + } + xPreUpdateHandlers.mu.Lock() + xPreUpdateHandlers.m[c.db] = callback + xPreUpdateHandlers.mu.Unlock() + + sqlite3.Xsqlite3_preupdate_hook(c.tls, c.db, cFuncPointer(preUpdateHookTrampoline), c.db) +} + +type CommitHookFn func() int32 + +func (c *conn) RegisterCommitHook(callback CommitHookFn) { + if callback == nil { + xCommitHandlers.mu.Lock() + delete(xCommitHandlers.m, c.db) + xCommitHandlers.mu.Unlock() + sqlite3.Xsqlite3_commit_hook(c.tls, c.db, uintptr(unsafe.Pointer(nil)), uintptr(unsafe.Pointer(nil))) + return + } + xCommitHandlers.mu.Lock() + xCommitHandlers.m[c.db] = callback + xCommitHandlers.mu.Unlock() + sqlite3.Xsqlite3_commit_hook(c.tls, c.db, cFuncPointer(commitHookTrampoline), c.db) +} + +type RollbackHookFn func() + +func (c *conn) RegisterRollbackHook(callback RollbackHookFn) { + if callback == nil { + xRollbackHandlers.mu.Lock() + delete(xRollbackHandlers.m, c.db) + xRollbackHandlers.mu.Unlock() + sqlite3.Xsqlite3_rollback_hook(c.tls, c.db, uintptr(unsafe.Pointer(nil)), uintptr(unsafe.Pointer(nil))) + return + } + xRollbackHandlers.mu.Lock() + xRollbackHandlers.m[c.db] = callback + xRollbackHandlers.mu.Unlock() + sqlite3.Xsqlite3_rollback_hook(c.tls, c.db, cFuncPointer(rollbackHookTrampoline), c.db) +} + +type SQLitePreUpdateData struct { + tls *libc.TLS + pCsr uintptr + Op int32 + DatabaseName string + TableName string + OldRowID int64 + NewRowID int64 +} + +// Depth returns the source path of the write, see sqlite3_preupdate_depth() +func (d *SQLitePreUpdateData) Depth() int { + return int(sqlite3.Xsqlite3_preupdate_depth(d.tls, d.pCsr)) +} + +// Count returns the number of columns in the row +func (d *SQLitePreUpdateData) Count() int { + return int(sqlite3.Xsqlite3_preupdate_count(d.tls, d.pCsr)) +} + +func (d *SQLitePreUpdateData) row(dest []any, new bool) error { + count := d.Count() + ppValue, err := mallocValue(d.tls) + if err != nil { + return err + } + defer libc.Xfree(d.tls, ppValue) + + for i := 0; i < count && i < len(dest); i++ { + val, err := d.value(ppValue, i, new) + if err != nil { + return err + } + err = convertAssign(&dest[i], val) + if err != nil { + return err + } + } + return nil +} + +// Old populates dest with the row data to be replaced. This works similar to +// database/sql's Rows.Scan() +func (d *SQLitePreUpdateData) Old(dest ...any) error { + if d.Op == sqlite3.SQLITE_INSERT { + return errors.New("there is no old row for INSERT operations") + } + return d.row(dest, false) +} + +// New populates dest with the replacement row data. This works similar to +// database/sql's Rows.Scan() +func (d *SQLitePreUpdateData) New(dest ...any) error { + if d.Op == sqlite3.SQLITE_DELETE { + return errors.New("there is no new row for DELETE operations") + } + return d.row(dest, true) +} + +const ptrValSize = types.Size_t(unsafe.Sizeof(&sqlite3.Sqlite3_value{})) + +func mallocValue(tls *libc.TLS) (uintptr, error) { + p := libc.Xmalloc(tls, ptrValSize) + if p == 0 { + return 0, fmt.Errorf("out of memory") + } + return p, nil +} + +func (d *SQLitePreUpdateData) value(ppValue uintptr, i int, new bool) (any, error) { + var src any + if new { + sqlite3.Xsqlite3_preupdate_new(d.tls, d.pCsr, int32(i), ppValue) + } else { + sqlite3.Xsqlite3_preupdate_old(d.tls, d.pCsr, int32(i), ppValue) + } + ptrValue := *(*uintptr)(unsafe.Pointer(ppValue)) + switch sqlite3.Xsqlite3_value_type(d.tls, ptrValue) { + case sqlite3.SQLITE_INTEGER: + src = int64(sqlite3.Xsqlite3_value_int64(d.tls, ptrValue)) + case sqlite3.SQLITE_FLOAT: + src = float64(sqlite3.Xsqlite3_value_double(d.tls, ptrValue)) + case sqlite3.SQLITE_BLOB: + size := sqlite3.Xsqlite3_value_bytes(d.tls, ptrValue) + blobPtr := sqlite3.Xsqlite3_value_blob(d.tls, ptrValue) + + var v []byte + if size != 0 { + v = make([]byte, size) + copy(v, (*libc.RawMem)(unsafe.Pointer(blobPtr))[:size:size]) + } + src = v + case sqlite3.SQLITE_TEXT: + src = libc.GoString(sqlite3.Xsqlite3_value_text(d.tls, ptrValue)) + case sqlite3.SQLITE_NULL: + src = nil + } + return src, nil +} + +func preUpdateHookTrampoline(tls *libc.TLS, handle uintptr, pCsr uintptr, op int32, zDb uintptr, pTab uintptr, iKey1 int64, iReg int32, iBlobWrite int32) { + xPreUpdateHandlers.mu.RLock() + xPreUpdateHandler := xPreUpdateHandlers.m[handle] + xPreUpdateHandlers.mu.RUnlock() + + if xPreUpdateHandler == nil { + return + } + data := SQLitePreUpdateData{ + tls: tls, + pCsr: pCsr, + Op: op, + DatabaseName: libc.GoString(zDb), + TableName: libc.GoString(pTab), + OldRowID: iKey1, + NewRowID: int64(iReg), + } + xPreUpdateHandler(data) +} + +func commitHookTrampoline(tls *libc.TLS, handle uintptr, pCsr uintptr) int32 { + xCommitHandlers.mu.RLock() + xCommitHandler := xCommitHandlers.m[handle] + xCommitHandlers.mu.RUnlock() + + if xCommitHandler == nil { + return 0 + } + + return xCommitHandler() +} + +func rollbackHookTrampoline(tls *libc.TLS, handle uintptr, pCsr uintptr) { + xRollbackHandlers.mu.RLock() + xRollbackHandler := xRollbackHandlers.m[handle] + xRollbackHandlers.mu.RUnlock() + + if xRollbackHandler == nil { + return + } + + xRollbackHandler() +} diff --git a/vendor/modernc.org/sqlite/sqlite.go b/vendor/modernc.org/sqlite/sqlite.go index a0b6ca4eb..c48b70292 100644 --- a/vendor/modernc.org/sqlite/sqlite.go +++ b/vendor/modernc.org/sqlite/sqlite.go @@ -1914,6 +1914,12 @@ type ExecQuerierContext interface { driver.QueryerContext } +type HookRegisterer interface { + RegisterPreUpdateHook(PreUpdateHookFn) + RegisterCommitHook(CommitHookFn) + RegisterRollbackHook(RollbackHookFn) +} + // Commit releases all resources associated with the Backup object but does not // close the destination database connection. // diff --git a/vendor/modules.txt b/vendor/modules.txt index ccf3a0b8e..c3c98820a 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -299,20 +299,23 @@ codeberg.org/gruf/go-structr # codeberg.org/gruf/go-xunsafe v0.0.0-20250809104800-512a9df57d73 ## explicit; go 1.24.5 codeberg.org/gruf/go-xunsafe +# dario.cat/mergo v1.0.2 +## explicit; go 1.13 +dario.cat/mergo # github.com/DmitriyVTitov/size v1.5.0 ## explicit; go 1.14 github.com/DmitriyVTitov/size -# github.com/KimMachineGun/automemlimit v0.7.4 +# github.com/KimMachineGun/automemlimit v0.7.5 ## explicit; go 1.22.0 github.com/KimMachineGun/automemlimit/memlimit # github.com/Masterminds/goutils v1.1.1 ## explicit github.com/Masterminds/goutils -# github.com/Masterminds/semver/v3 v3.2.1 -## explicit; go 1.18 +# github.com/Masterminds/semver/v3 v3.4.0 +## explicit; go 1.21 github.com/Masterminds/semver/v3 -# github.com/Masterminds/sprig/v3 v3.2.3 -## explicit; go 1.13 +# github.com/Masterminds/sprig/v3 v3.3.0 +## explicit; go 1.21 github.com/Masterminds/sprig/v3 # github.com/SherClockHolmes/webpush-go v1.4.0 ## explicit; go 1.13 @@ -484,13 +487,13 @@ github.com/go-openapi/analysis/internal/flatten/operations github.com/go-openapi/analysis/internal/flatten/replace github.com/go-openapi/analysis/internal/flatten/schutils github.com/go-openapi/analysis/internal/flatten/sortref -# github.com/go-openapi/errors v0.22.0 +# github.com/go-openapi/errors v0.22.2 ## explicit; go 1.20 github.com/go-openapi/errors -# github.com/go-openapi/inflect v0.21.0 +# github.com/go-openapi/inflect v0.21.3 ## explicit; go 1.20 github.com/go-openapi/inflect -# github.com/go-openapi/jsonpointer v0.21.0 +# github.com/go-openapi/jsonpointer v0.21.2 ## explicit; go 1.20 github.com/go-openapi/jsonpointer # github.com/go-openapi/jsonreference v0.21.0 @@ -516,7 +519,7 @@ github.com/go-openapi/spec # github.com/go-openapi/strfmt v0.23.0 ## explicit; go 1.20 github.com/go-openapi/strfmt -# github.com/go-openapi/swag v0.23.0 +# github.com/go-openapi/swag v0.23.1 ## explicit; go 1.20 github.com/go-openapi/swag # github.com/go-openapi/validate v0.24.0 @@ -535,8 +538,8 @@ github.com/go-playground/universal-translator # github.com/go-playground/validator/v10 v10.28.0 ## explicit; go 1.24.0 github.com/go-playground/validator/v10 -# github.com/go-swagger/go-swagger v0.33.1 => codeberg.org/superseriousbusiness/go-swagger v0.32.3-gts-go1.23-fix -## explicit; go 1.21 +# github.com/go-swagger/go-swagger v0.33.1 +## explicit; go 1.24.0 github.com/go-swagger/go-swagger/cmd/swagger github.com/go-swagger/go-swagger/cmd/swagger/commands github.com/go-swagger/go-swagger/cmd/swagger/commands/diff @@ -611,12 +614,9 @@ github.com/grafana/regexp github.com/grpc-ecosystem/grpc-gateway/v2/internal/httprule github.com/grpc-ecosystem/grpc-gateway/v2/runtime github.com/grpc-ecosystem/grpc-gateway/v2/utilities -# github.com/huandu/xstrings v1.4.0 +# github.com/huandu/xstrings v1.5.0 ## explicit; go 1.12 github.com/huandu/xstrings -# github.com/imdario/mergo v0.3.16 -## explicit; go 1.13 -github.com/imdario/mergo # github.com/inconshreveable/mousetrap v1.1.0 ## explicit; go 1.18 github.com/inconshreveable/mousetrap @@ -644,8 +644,8 @@ github.com/jackc/pgx/v5/stdlib ## explicit; go 1.19 github.com/jackc/puddle/v2 github.com/jackc/puddle/v2/internal/genstack -# github.com/jessevdk/go-flags v1.5.0 -## explicit; go 1.15 +# github.com/jessevdk/go-flags v1.6.1 +## explicit; go 1.20 github.com/jessevdk/go-flags # github.com/jinzhu/inflection v1.0.0 ## explicit @@ -677,8 +677,8 @@ github.com/kr/text ## explicit; go 1.18 github.com/leodido/go-urn github.com/leodido/go-urn/scim/schema -# github.com/mailru/easyjson v0.7.7 -## explicit; go 1.12 +# github.com/mailru/easyjson v0.9.0 +## explicit; go 1.20 github.com/mailru/easyjson/buffer github.com/mailru/easyjson/jlexer github.com/mailru/easyjson/jwriter @@ -815,8 +815,8 @@ github.com/remyoudompheng/bigfft # github.com/rivo/uniseg v0.4.7 ## explicit; go 1.18 github.com/rivo/uniseg -# github.com/rogpeppe/go-internal v1.13.2-0.20241226121412-a5dc8ff20d0a -## explicit; go 1.22.0 +# github.com/rogpeppe/go-internal v1.14.1 +## explicit; go 1.23 github.com/rogpeppe/go-internal/fmtsort # github.com/rs/xid v1.6.0 ## explicit; go 1.16 @@ -824,8 +824,8 @@ github.com/rs/xid # github.com/sagikazarmark/locafero v0.11.0 ## explicit; go 1.23.0 github.com/sagikazarmark/locafero -# github.com/shopspring/decimal v1.3.1 -## explicit; go 1.13 +# github.com/shopspring/decimal v1.4.0 +## explicit; go 1.10 github.com/shopspring/decimal # github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 ## explicit; go 1.20 @@ -864,11 +864,11 @@ github.com/stretchr/testify/suite # github.com/subosito/gotenv v1.6.0 ## explicit; go 1.18 github.com/subosito/gotenv -# github.com/tdewolff/minify/v2 v2.24.4 +# github.com/tdewolff/minify/v2 v2.24.5 ## explicit; go 1.17 github.com/tdewolff/minify/v2 github.com/tdewolff/minify/v2/html -# github.com/tdewolff/parse/v2 v2.8.4 +# github.com/tdewolff/parse/v2 v2.8.5-0.20251020133559-0efcf90bef1a ## explicit; go 1.11 github.com/tdewolff/parse/v2 github.com/tdewolff/parse/v2/buffer @@ -923,7 +923,7 @@ github.com/tmthrgd/go-hex # github.com/tomnomnom/linkheader v0.0.0-20250811210735-e5fe3b51442e ## explicit; go 1.13 github.com/tomnomnom/linkheader -# github.com/toqueteos/webbrowser v1.2.0 +# github.com/toqueteos/webbrowser v1.2.1 ## explicit; go 1.12 github.com/toqueteos/webbrowser # github.com/twitchyliquid64/golang-asm v0.15.1 @@ -1002,7 +1002,7 @@ github.com/yuin/goldmark/renderer github.com/yuin/goldmark/renderer/html github.com/yuin/goldmark/text github.com/yuin/goldmark/util -# go.mongodb.org/mongo-driver v1.17.3 +# go.mongodb.org/mongo-driver v1.17.4 ## explicit; go 1.18 go.mongodb.org/mongo-driver/bson go.mongodb.org/mongo-driver/bson/bsoncodec @@ -1435,12 +1435,11 @@ modernc.org/mathutil # modernc.org/memory v1.11.0 ## explicit; go 1.23.0 modernc.org/memory -# modernc.org/sqlite v1.39.1 => gitlab.com/NyaaaWhatsUpDoc/sqlite v1.39.1-concurrency-workaround +# modernc.org/sqlite v1.40.0 => gitlab.com/NyaaaWhatsUpDoc/sqlite v1.40.0-concurrency-workaround ## explicit; go 1.24.0 modernc.org/sqlite modernc.org/sqlite/lib # mvdan.cc/xurls/v2 v2.6.0 ## explicit; go 1.22.0 mvdan.cc/xurls/v2 -# github.com/go-swagger/go-swagger => codeberg.org/superseriousbusiness/go-swagger v0.32.3-gts-go1.23-fix -# modernc.org/sqlite => gitlab.com/NyaaaWhatsUpDoc/sqlite v1.39.1-concurrency-workaround +# modernc.org/sqlite => gitlab.com/NyaaaWhatsUpDoc/sqlite v1.40.0-concurrency-workaround |
