diff --git a/go.mod b/go.mod
index aa7568fb7..b7ceadbdc 100644
--- a/go.mod
+++ b/go.mod
@@ -12,7 +12,7 @@ require (
github.com/json-iterator/go v1.1.12
github.com/mariomac/guara v0.0.0-20220523124851-5fc279816f1f
github.com/minio/minio-go/v7 v7.0.63
- github.com/mitchellh/mapstructure v1.4.3
+ github.com/mitchellh/mapstructure v1.5.0
github.com/netobserv/gopipes v0.3.0
github.com/netobserv/loki-client-go v0.0.0-20220927092034-f37122a54500
github.com/netobserv/netobserv-ebpf-agent v0.3.3-0.20230922095057-f87021a84111
@@ -24,7 +24,7 @@ require (
github.com/sirupsen/logrus v1.9.3
github.com/spf13/cobra v1.7.0
github.com/spf13/pflag v1.0.5
- github.com/spf13/viper v1.10.1
+ github.com/spf13/viper v1.16.0
github.com/stretchr/testify v1.8.4
github.com/vladimirvivien/gexe v0.2.0
github.com/vmware/go-ipfix v0.5.13
@@ -65,7 +65,7 @@ require (
github.com/klauspost/compress v1.16.7 // indirect
github.com/klauspost/cpuid/v2 v2.2.5 // indirect
github.com/libp2p/go-reuseport v0.3.0 // indirect
- github.com/magiconair/properties v1.8.5 // indirect
+ github.com/magiconair/properties v1.8.7 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/mdlayher/ethernet v0.0.0-20220221185849-529eae5b6118 // indirect
@@ -76,7 +76,7 @@ require (
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect
- github.com/pelletier/go-toml v1.9.4 // indirect
+ github.com/pelletier/go-toml/v2 v2.0.8 // indirect
github.com/pierrec/lz4/v4 v4.1.17 // indirect
github.com/pion/dtls/v2 v2.2.4 // indirect
github.com/pion/logging v0.2.2 // indirect
@@ -87,11 +87,11 @@ require (
github.com/prometheus/procfs v0.10.1 // indirect
github.com/prometheus/prometheus v1.8.2-0.20201028100903-3245b3267b24 // indirect
github.com/rs/xid v1.5.0 // indirect
- github.com/spf13/afero v1.6.0 // indirect
- github.com/spf13/cast v1.4.1 // indirect
+ github.com/spf13/afero v1.9.5 // indirect
+ github.com/spf13/cast v1.5.1 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/stretchr/objx v0.5.0 // indirect
- github.com/subosito/gotenv v1.2.0 // indirect
+ github.com/subosito/gotenv v1.4.2 // indirect
github.com/xdg/scram v1.0.5 // indirect
github.com/xdg/stringprep v1.0.3 // indirect
go.uber.org/atomic v1.9.0 // indirect
diff --git a/go.sum b/go.sum
index 1565e93bf..1890081d8 100644
--- a/go.sum
+++ b/go.sum
@@ -4,6 +4,7 @@ cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSR
cloud.google.com/go v0.43.0/go.mod h1:BOSR3VbTLkk6FDC/TcffxP4NF/FFBGA5ku+jvKOP7pg=
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
+cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
@@ -15,6 +16,9 @@ cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKV
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
+cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
+cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
+cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
@@ -34,6 +38,7 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
+cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
collectd.org v0.3.0/go.mod h1:A/8DzQBkF6abtvrT2j/AU/4tiBgJWYyh0y/oB/4MlWE=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/Azure/azure-sdk-for-go v46.4.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
@@ -97,7 +102,6 @@ github.com/armon/go-metrics v0.3.3/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
-github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
@@ -135,6 +139,8 @@ github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp
github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
+github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
+github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
github.com/containerd/containerd v1.3.4/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
@@ -185,9 +191,10 @@ github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4s
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
+github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
+github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
-github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww=
github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
@@ -198,6 +205,7 @@ github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHqu
github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
github.com/frankban/quicktest v1.10.2/go.mod h1:K+q6oSqb0W0Ininfk863uOk1lMy69l/P6txr3mVT54s=
+github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
@@ -339,7 +347,6 @@ github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4er
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
-github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
@@ -371,7 +378,6 @@ github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
-github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
github.com/google/flatbuffers v1.11.0/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I=
github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U=
@@ -398,6 +404,7 @@ 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/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
+github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
@@ -406,6 +413,9 @@ github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hf
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20201007051231-1066cbb265c7/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@@ -416,6 +426,7 @@ github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg=
+github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
github.com/gophercloud/gophercloud v0.13.0/go.mod h1:VX0Ibx85B60B5XOrZr6kaNwrmPUzcmMpwxvQ1WQIIWM=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
@@ -475,6 +486,7 @@ github.com/hetznercloud/hcloud-go v1.22.0/go.mod h1:xng8lbDUg+xM1dgc0yGHX5EeqbwI
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
+github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/imdario/mergo v0.3.15 h1:M8XP7IuFNsqUx6VPK2P9OSmsYsI/YFaGil0uD21V3dM=
github.com/imdario/mergo v0.3.15/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
@@ -560,8 +572,8 @@ github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-b
github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
-github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls=
-github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
+github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
+github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
@@ -616,8 +628,8 @@ github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0Qu
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.2.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
-github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs=
-github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
+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/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8=
github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
github.com/moby/term v0.0.0-20201216013528-df9cb8a40635/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc=
@@ -694,8 +706,8 @@ github.com/paulbellamy/ratecounter v0.2.0/go.mod h1:Hfx1hDpSGoqxkVVpBi/IlYD7kChl
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo=
-github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM=
-github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
+github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ=
+github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=
github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/peterh/liner v1.0.1-0.20180619022028-8c1271fcf47f/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc=
@@ -723,7 +735,7 @@ github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
-github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
+github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
github.com/pkg/term v0.0.0-20180730021639-bffc007b7fd5/go.mod h1:eCbImbZ95eXtAUIbLAuAVnBnwf83mjf6QIVH8SHYwqQ=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
@@ -818,11 +830,11 @@ github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJ
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
-github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY=
-github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
+github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM=
+github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
-github.com/spf13/cast v1.4.1 h1:s0hze+J0196ZfEMTs80N7UlFt0BDuQ7Q+JDnHiMWKdA=
-github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
+github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA=
+github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48=
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI=
github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
@@ -836,8 +848,8 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
-github.com/spf13/viper v1.10.1 h1:nuJZuYpG7gTj/XqiUwg8bA0cp1+M2mC3J4g5luUYBKk=
-github.com/spf13/viper v1.10.1/go.mod h1:IGlFPqhNAPKRxohIzWpI5QEy4kuI7tcl5WvR+8qy1rU=
+github.com/spf13/viper v1.16.0 h1:rGGH0XDZhdUOryiDWjmIvUSWpbNqisK8Wk0Vyefw8hc=
+github.com/spf13/viper v1.16.0/go.mod h1:yg78JgCJcbrQOvV9YLXgkLaZqUidkY9K+Dd1FofRzQg=
github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
@@ -857,10 +869,12 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
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=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
+github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
-github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
+github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8=
+github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
@@ -906,7 +920,7 @@ go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
-go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
+go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
@@ -917,7 +931,7 @@ go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A
go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
-go.uber.org/multierr v1.7.0 h1:zaiO/rmgFjbmCXdSYJWQcdvOCsthmdaHfr3Gm2Kx4Ec=
+go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
@@ -934,7 +948,6 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191202143827-86a70503ff7e/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
@@ -943,8 +956,10 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
+golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk=
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
@@ -974,6 +989,7 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
@@ -982,6 +998,8 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -1025,6 +1043,9 @@ golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81R
golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210224082022-3d97a244fca7/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
@@ -1041,6 +1062,9 @@ golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4Iltr
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
+golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.10.0 h1:zHCpF2Khkwy4mMB4bv0U37YtJdTGW8jI0glAApi0Kh8=
golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI=
@@ -1119,9 +1143,13 @@ golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201008064518-c1f3e3309c71/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -1231,7 +1259,13 @@ golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
golang.org/x/tools v0.0.0-20201020161133-226fd2f889ca/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
+golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -1263,6 +1297,9 @@ google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0M
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
google.golang.org/api v0.32.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
+google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
+google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
+google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
@@ -1306,6 +1343,12 @@ google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6D
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 h1:bVf09lpb+OJbByTj913DRJioFFAjf/ZGxEz7MajTp2U=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
@@ -1327,6 +1370,9 @@ google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
+google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
+google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
+google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.58.1 h1:OL+Vz23DTtrrldqHK49FUOPHyY75rvFqJfXC84NYW58=
google.golang.org/grpc v1.58.1/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
@@ -1412,7 +1458,6 @@ k8s.io/client-go v0.28.2 h1:DNoYI1vGq0slMBN/SWKMZMw0Rq+0EQW6/AK4v9+3VeY=
k8s.io/client-go v0.28.2/go.mod h1:sMkApowspLuc7omj1FOSUxSoqjr+d5Q0Yc0LOFnYFJY=
k8s.io/component-base v0.21.0/go.mod h1:qvtjz6X0USWXbgmbfXR+Agik4RZ3jv2Bgr5QnZzdPYw=
k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
-k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
diff --git a/vendor/github.com/magiconair/properties/.travis.yml b/vendor/github.com/magiconair/properties/.travis.yml
deleted file mode 100644
index baf9031df..000000000
--- a/vendor/github.com/magiconair/properties/.travis.yml
+++ /dev/null
@@ -1,17 +0,0 @@
-language: go
-go:
- - 1.3.x
- - 1.4.x
- - 1.5.x
- - 1.6.x
- - 1.7.x
- - 1.8.x
- - 1.9.x
- - "1.10.x"
- - "1.11.x"
- - "1.12.x"
- - "1.13.x"
- - "1.14.x"
- - "1.15.x"
- - "1.16.x"
- - tip
diff --git a/vendor/github.com/magiconair/properties/CHANGELOG.md b/vendor/github.com/magiconair/properties/CHANGELOG.md
index ff8d02535..842e8e24f 100644
--- a/vendor/github.com/magiconair/properties/CHANGELOG.md
+++ b/vendor/github.com/magiconair/properties/CHANGELOG.md
@@ -1,5 +1,50 @@
## Changelog
+### [1.8.7](https://github.com/magiconair/properties/tree/v1.8.7) - 08 Dec 2022
+
+ * [PR #65](https://github.com/magiconair/properties/pull/65): Speedup Merge
+
+ Thanks to [@AdityaVallabh](https://github.com/AdityaVallabh) for the patch.
+
+ * [PR #66](https://github.com/magiconair/properties/pull/66): use github actions
+
+### [1.8.6](https://github.com/magiconair/properties/tree/v1.8.6) - 23 Feb 2022
+
+ * [PR #57](https://github.com/magiconair/properties/pull/57):Fix "unreachable code" lint error
+
+ Thanks to [@ellie](https://github.com/ellie) for the patch.
+
+ * [PR #63](https://github.com/magiconair/properties/pull/63): Make TestMustGetParsedDuration backwards compatible
+
+ This patch ensures that the `TestMustGetParsedDuration` still works with `go1.3` to make the
+ author happy until it affects real users.
+
+ Thanks to [@maage](https://github.com/maage) for the patch.
+
+### [1.8.5](https://github.com/magiconair/properties/tree/v1.8.5) - 24 Mar 2021
+
+ * [PR #55](https://github.com/magiconair/properties/pull/55): Fix: Encoding Bug in Comments
+
+ When reading comments \ are loaded correctly, but when writing they are then
+ replaced by \\. This leads to wrong comments when writing and reading multiple times.
+
+ Thanks to [@doxsch](https://github.com/doxsch) for the patch.
+
+### [1.8.4](https://github.com/magiconair/properties/tree/v1.8.4) - 23 Sep 2020
+
+ * [PR #50](https://github.com/magiconair/properties/pull/50): enhance error message for circular references
+
+ Thanks to [@sriv](https://github.com/sriv) for the patch.
+
+### [1.8.3](https://github.com/magiconair/properties/tree/v1.8.3) - 14 Sep 2020
+
+ * [PR #49](https://github.com/magiconair/properties/pull/49): Include the key in error message causing the circular reference
+
+ The change is include the key in the error message which is causing the circular
+ reference when parsing/loading the properties files.
+
+ Thanks to [@haroon-sheikh](https://github.com/haroon-sheikh) for the patch.
+
### [1.8.2](https://github.com/magiconair/properties/tree/v1.8.2) - 25 Aug 2020
* [PR #36](https://github.com/magiconair/properties/pull/36): Escape backslash on write
diff --git a/vendor/github.com/magiconair/properties/decode.go b/vendor/github.com/magiconair/properties/decode.go
index 3ebf8049c..8e6aa441d 100644
--- a/vendor/github.com/magiconair/properties/decode.go
+++ b/vendor/github.com/magiconair/properties/decode.go
@@ -1,4 +1,4 @@
-// Copyright 2018 Frank Schroeder. All rights reserved.
+// Copyright 2013-2022 Frank Schroeder. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -48,49 +48,49 @@ import (
//
// Examples:
//
-// // Field is ignored.
-// Field int `properties:"-"`
+// // Field is ignored.
+// Field int `properties:"-"`
//
-// // Field is assigned value of 'Field'.
-// Field int
+// // Field is assigned value of 'Field'.
+// Field int
//
-// // Field is assigned value of 'myName'.
-// Field int `properties:"myName"`
+// // Field is assigned value of 'myName'.
+// Field int `properties:"myName"`
//
-// // Field is assigned value of key 'myName' and has a default
-// // value 15 if the key does not exist.
-// Field int `properties:"myName,default=15"`
+// // Field is assigned value of key 'myName' and has a default
+// // value 15 if the key does not exist.
+// Field int `properties:"myName,default=15"`
//
-// // Field is assigned value of key 'Field' and has a default
-// // value 15 if the key does not exist.
-// Field int `properties:",default=15"`
+// // Field is assigned value of key 'Field' and has a default
+// // value 15 if the key does not exist.
+// Field int `properties:",default=15"`
//
-// // Field is assigned value of key 'date' and the date
-// // is in format 2006-01-02
-// Field time.Time `properties:"date,layout=2006-01-02"`
+// // Field is assigned value of key 'date' and the date
+// // is in format 2006-01-02
+// Field time.Time `properties:"date,layout=2006-01-02"`
//
-// // Field is assigned the non-empty and whitespace trimmed
-// // values of key 'Field' split by commas.
-// Field []string
+// // Field is assigned the non-empty and whitespace trimmed
+// // values of key 'Field' split by commas.
+// Field []string
//
-// // Field is assigned the non-empty and whitespace trimmed
-// // values of key 'Field' split by commas and has a default
-// // value ["a", "b", "c"] if the key does not exist.
-// Field []string `properties:",default=a;b;c"`
+// // Field is assigned the non-empty and whitespace trimmed
+// // values of key 'Field' split by commas and has a default
+// // value ["a", "b", "c"] if the key does not exist.
+// Field []string `properties:",default=a;b;c"`
//
-// // Field is decoded recursively with "Field." as key prefix.
-// Field SomeStruct
+// // Field is decoded recursively with "Field." as key prefix.
+// Field SomeStruct
//
-// // Field is decoded recursively with "myName." as key prefix.
-// Field SomeStruct `properties:"myName"`
+// // Field is decoded recursively with "myName." as key prefix.
+// Field SomeStruct `properties:"myName"`
//
-// // Field is decoded recursively with "Field." as key prefix
-// // and the next dotted element of the key as map key.
-// Field map[string]string
+// // Field is decoded recursively with "Field." as key prefix
+// // and the next dotted element of the key as map key.
+// Field map[string]string
//
-// // Field is decoded recursively with "myName." as key prefix
-// // and the next dotted element of the key as map key.
-// Field map[string]string `properties:"myName"`
+// // Field is decoded recursively with "myName." as key prefix
+// // and the next dotted element of the key as map key.
+// Field map[string]string `properties:"myName"`
func (p *Properties) Decode(x interface{}) error {
t, v := reflect.TypeOf(x), reflect.ValueOf(x)
if t.Kind() != reflect.Ptr || v.Elem().Type().Kind() != reflect.Struct {
diff --git a/vendor/github.com/magiconair/properties/doc.go b/vendor/github.com/magiconair/properties/doc.go
index f8822da2b..7c7979315 100644
--- a/vendor/github.com/magiconair/properties/doc.go
+++ b/vendor/github.com/magiconair/properties/doc.go
@@ -1,4 +1,4 @@
-// Copyright 2018 Frank Schroeder. All rights reserved.
+// Copyright 2013-2022 Frank Schroeder. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -13,7 +13,7 @@
//
// To load a single properties file use MustLoadFile():
//
-// p := properties.MustLoadFile(filename, properties.UTF8)
+// p := properties.MustLoadFile(filename, properties.UTF8)
//
// To load multiple properties files use MustLoadFiles()
// which loads the files in the given order and merges the
@@ -23,25 +23,25 @@
// Filenames can contain environment variables which are expanded
// before loading.
//
-// f1 := "/etc/myapp/myapp.conf"
-// f2 := "/home/${USER}/myapp.conf"
-// p := MustLoadFiles([]string{f1, f2}, properties.UTF8, true)
+// f1 := "/etc/myapp/myapp.conf"
+// f2 := "/home/${USER}/myapp.conf"
+// p := MustLoadFiles([]string{f1, f2}, properties.UTF8, true)
//
// All of the different key/value delimiters ' ', ':' and '=' are
// supported as well as the comment characters '!' and '#' and
// multi-line values.
//
-// ! this is a comment
-// # and so is this
+// ! this is a comment
+// # and so is this
//
-// # the following expressions are equal
-// key value
-// key=value
-// key:value
-// key = value
-// key : value
-// key = val\
-// ue
+// # the following expressions are equal
+// key value
+// key=value
+// key:value
+// key = value
+// key : value
+// key = val\
+// ue
//
// Properties stores all comments preceding a key and provides
// GetComments() and SetComments() methods to retrieve and
@@ -55,62 +55,62 @@
// and malformed expressions are not allowed and cause an
// error. Expansion of environment variables is supported.
//
-// # standard property
-// key = value
+// # standard property
+// key = value
//
-// # property expansion: key2 = value
-// key2 = ${key}
+// # property expansion: key2 = value
+// key2 = ${key}
//
-// # recursive expansion: key3 = value
-// key3 = ${key2}
+// # recursive expansion: key3 = value
+// key3 = ${key2}
//
-// # circular reference (error)
-// key = ${key}
+// # circular reference (error)
+// key = ${key}
//
-// # malformed expression (error)
-// key = ${ke
+// # malformed expression (error)
+// key = ${ke
//
-// # refers to the users' home dir
-// home = ${HOME}
+// # refers to the users' home dir
+// home = ${HOME}
//
-// # local key takes precedence over env var: u = foo
-// USER = foo
-// u = ${USER}
+// # local key takes precedence over env var: u = foo
+// USER = foo
+// u = ${USER}
//
// The default property expansion format is ${key} but can be
// changed by setting different pre- and postfix values on the
// Properties object.
//
-// p := properties.NewProperties()
-// p.Prefix = "#["
-// p.Postfix = "]#"
+// p := properties.NewProperties()
+// p.Prefix = "#["
+// p.Postfix = "]#"
//
// Properties provides convenience functions for getting typed
// values with default values if the key does not exist or the
// type conversion failed.
//
-// # Returns true if the value is either "1", "on", "yes" or "true"
-// # Returns false for every other value and the default value if
-// # the key does not exist.
-// v = p.GetBool("key", false)
+// # Returns true if the value is either "1", "on", "yes" or "true"
+// # Returns false for every other value and the default value if
+// # the key does not exist.
+// v = p.GetBool("key", false)
//
-// # Returns the value if the key exists and the format conversion
-// # was successful. Otherwise, the default value is returned.
-// v = p.GetInt64("key", 999)
-// v = p.GetUint64("key", 999)
-// v = p.GetFloat64("key", 123.0)
-// v = p.GetString("key", "def")
-// v = p.GetDuration("key", 999)
+// # Returns the value if the key exists and the format conversion
+// # was successful. Otherwise, the default value is returned.
+// v = p.GetInt64("key", 999)
+// v = p.GetUint64("key", 999)
+// v = p.GetFloat64("key", 123.0)
+// v = p.GetString("key", "def")
+// v = p.GetDuration("key", 999)
//
// As an alternative properties may be applied with the standard
// library's flag implementation at any time.
//
-// # Standard configuration
-// v = flag.Int("key", 999, "help message")
-// flag.Parse()
+// # Standard configuration
+// v = flag.Int("key", 999, "help message")
+// flag.Parse()
//
-// # Merge p into the flag set
-// p.MustFlag(flag.CommandLine)
+// # Merge p into the flag set
+// p.MustFlag(flag.CommandLine)
//
// Properties provides several MustXXX() convenience functions
// which will terminate the app if an error occurs. The behavior
@@ -119,30 +119,30 @@
// of logging the error set a different ErrorHandler before
// you use the Properties package.
//
-// properties.ErrorHandler = properties.PanicHandler
+// properties.ErrorHandler = properties.PanicHandler
//
-// # Will panic instead of logging an error
-// p := properties.MustLoadFile("config.properties")
+// # Will panic instead of logging an error
+// p := properties.MustLoadFile("config.properties")
//
// You can also provide your own ErrorHandler function. The only requirement
// is that the error handler function must exit after handling the error.
//
-// properties.ErrorHandler = func(err error) {
-// fmt.Println(err)
-// os.Exit(1)
-// }
+// properties.ErrorHandler = func(err error) {
+// fmt.Println(err)
+// os.Exit(1)
+// }
//
-// # Will write to stdout and then exit
-// p := properties.MustLoadFile("config.properties")
+// # Will write to stdout and then exit
+// p := properties.MustLoadFile("config.properties")
//
// Properties can also be loaded into a struct via the `Decode`
// method, e.g.
//
-// type S struct {
-// A string `properties:"a,default=foo"`
-// D time.Duration `properties:"timeout,default=5s"`
-// E time.Time `properties:"expires,layout=2006-01-02,default=2015-01-01"`
-// }
+// type S struct {
+// A string `properties:"a,default=foo"`
+// D time.Duration `properties:"timeout,default=5s"`
+// E time.Time `properties:"expires,layout=2006-01-02,default=2015-01-01"`
+// }
//
// See `Decode()` method for the full documentation.
//
@@ -152,5 +152,4 @@
// http://en.wikipedia.org/wiki/.properties
//
// http://docs.oracle.com/javase/7/docs/api/java/util/Properties.html#load%28java.io.Reader%29
-//
package properties
diff --git a/vendor/github.com/magiconair/properties/integrate.go b/vendor/github.com/magiconair/properties/integrate.go
index 74d38dc67..35d0ae97b 100644
--- a/vendor/github.com/magiconair/properties/integrate.go
+++ b/vendor/github.com/magiconair/properties/integrate.go
@@ -1,4 +1,4 @@
-// Copyright 2018 Frank Schroeder. All rights reserved.
+// Copyright 2013-2022 Frank Schroeder. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -10,8 +10,9 @@ import "flag"
// the respective key for flag.Flag.Name.
//
// It's use is recommended with command line arguments as in:
-// flag.Parse()
-// p.MustFlag(flag.CommandLine)
+//
+// flag.Parse()
+// p.MustFlag(flag.CommandLine)
func (p *Properties) MustFlag(dst *flag.FlagSet) {
m := make(map[string]*flag.Flag)
dst.VisitAll(func(f *flag.Flag) {
diff --git a/vendor/github.com/magiconair/properties/lex.go b/vendor/github.com/magiconair/properties/lex.go
index 367166d58..3d15a1f6e 100644
--- a/vendor/github.com/magiconair/properties/lex.go
+++ b/vendor/github.com/magiconair/properties/lex.go
@@ -1,4 +1,4 @@
-// Copyright 2018 Frank Schroeder. All rights reserved.
+// Copyright 2013-2022 Frank Schroeder. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//
@@ -128,18 +128,6 @@ func (l *lexer) acceptRun(valid string) {
l.backup()
}
-// acceptRunUntil consumes a run of runes up to a terminator.
-func (l *lexer) acceptRunUntil(term rune) {
- for term != l.next() {
- }
- l.backup()
-}
-
-// hasText returns true if the current parsed text is not empty.
-func (l *lexer) isNotEmpty() bool {
- return l.pos > l.start
-}
-
// lineNumber reports which line we're on, based on the position of
// the previous item returned by nextItem. Doing it this way
// means we don't have to worry about peek double counting.
diff --git a/vendor/github.com/magiconair/properties/load.go b/vendor/github.com/magiconair/properties/load.go
index c83c2dadd..635368dc8 100644
--- a/vendor/github.com/magiconair/properties/load.go
+++ b/vendor/github.com/magiconair/properties/load.go
@@ -1,4 +1,4 @@
-// Copyright 2018 Frank Schroeder. All rights reserved.
+// Copyright 2013-2022 Frank Schroeder. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
diff --git a/vendor/github.com/magiconair/properties/parser.go b/vendor/github.com/magiconair/properties/parser.go
index cdc4a8034..fccfd39f6 100644
--- a/vendor/github.com/magiconair/properties/parser.go
+++ b/vendor/github.com/magiconair/properties/parser.go
@@ -1,4 +1,4 @@
-// Copyright 2018 Frank Schroeder. All rights reserved.
+// Copyright 2013-2022 Frank Schroeder. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -59,14 +59,6 @@ func (p *parser) errorf(format string, args ...interface{}) {
panic(fmt.Errorf(format, args...))
}
-func (p *parser) expect(expected itemType) (token item) {
- token = p.lex.nextItem()
- if token.typ != expected {
- p.unexpected(token)
- }
- return token
-}
-
func (p *parser) expectOneOf(expected ...itemType) (token item) {
token = p.lex.nextItem()
for _, v := range expected {
@@ -91,5 +83,4 @@ func (p *parser) recover(errp *error) {
}
*errp = e.(error)
}
- return
}
diff --git a/vendor/github.com/magiconair/properties/properties.go b/vendor/github.com/magiconair/properties/properties.go
index 1529e7223..fb2f7b404 100644
--- a/vendor/github.com/magiconair/properties/properties.go
+++ b/vendor/github.com/magiconair/properties/properties.go
@@ -1,4 +1,4 @@
-// Copyright 2018 Frank Schroeder. All rights reserved.
+// Copyright 2013-2022 Frank Schroeder. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -700,22 +700,17 @@ func (p *Properties) Delete(key string) {
// Merge merges properties, comments and keys from other *Properties into p
func (p *Properties) Merge(other *Properties) {
+ for _, k := range other.k {
+ if _, ok := p.m[k]; !ok {
+ p.k = append(p.k, k)
+ }
+ }
for k, v := range other.m {
p.m[k] = v
}
for k, v := range other.c {
p.c[k] = v
}
-
-outer:
- for _, otherKey := range other.k {
- for _, key := range p.k {
- if otherKey == key {
- continue outer
- }
- }
- p.k = append(p.k, otherKey)
- }
}
// ----------------------------------------------------------------------------
@@ -786,7 +781,6 @@ func expand(s string, keys []string, prefix, postfix string, values map[string]s
}
s = s[:start] + new_val + s[end+1:]
}
- return s, nil
}
// encode encodes a UTF-8 string to ISO-8859-1 and escapes some characters.
diff --git a/vendor/github.com/magiconair/properties/rangecheck.go b/vendor/github.com/magiconair/properties/rangecheck.go
index b013a2e5e..dbd60b36e 100644
--- a/vendor/github.com/magiconair/properties/rangecheck.go
+++ b/vendor/github.com/magiconair/properties/rangecheck.go
@@ -1,4 +1,4 @@
-// Copyright 2018 Frank Schroeder. All rights reserved.
+// Copyright 2013-2022 Frank Schroeder. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
diff --git a/vendor/github.com/mitchellh/mapstructure/CHANGELOG.md b/vendor/github.com/mitchellh/mapstructure/CHANGELOG.md
index 38a099162..c75823490 100644
--- a/vendor/github.com/mitchellh/mapstructure/CHANGELOG.md
+++ b/vendor/github.com/mitchellh/mapstructure/CHANGELOG.md
@@ -1,3 +1,16 @@
+## 1.5.0
+
+* New option `IgnoreUntaggedFields` to ignore decoding to any fields
+ without `mapstructure` (or the configured tag name) set [GH-277]
+* New option `ErrorUnset` which makes it an error if any fields
+ in a target struct are not set by the decoding process. [GH-225]
+* New function `OrComposeDecodeHookFunc` to help compose decode hooks. [GH-240]
+* Decoding to slice from array no longer crashes [GH-265]
+* Decode nested struct pointers to map [GH-271]
+* Fix issue where `,squash` was ignored if `Squash` option was set. [GH-280]
+* Fix issue where fields with `,omitempty` would sometimes decode
+ into a map with an empty string key [GH-281]
+
## 1.4.3
* Fix cases where `json.Number` didn't decode properly [GH-261]
diff --git a/vendor/github.com/mitchellh/mapstructure/decode_hooks.go b/vendor/github.com/mitchellh/mapstructure/decode_hooks.go
index 4d4bbc733..3a754ca72 100644
--- a/vendor/github.com/mitchellh/mapstructure/decode_hooks.go
+++ b/vendor/github.com/mitchellh/mapstructure/decode_hooks.go
@@ -77,6 +77,28 @@ func ComposeDecodeHookFunc(fs ...DecodeHookFunc) DecodeHookFunc {
}
}
+// OrComposeDecodeHookFunc executes all input hook functions until one of them returns no error. In that case its value is returned.
+// If all hooks return an error, OrComposeDecodeHookFunc returns an error concatenating all error messages.
+func OrComposeDecodeHookFunc(ff ...DecodeHookFunc) DecodeHookFunc {
+ return func(a, b reflect.Value) (interface{}, error) {
+ var allErrs string
+ var out interface{}
+ var err error
+
+ for _, f := range ff {
+ out, err = DecodeHookExec(f, a, b)
+ if err != nil {
+ allErrs += err.Error() + "\n"
+ continue
+ }
+
+ return out, nil
+ }
+
+ return nil, errors.New(allErrs)
+ }
+}
+
// StringToSliceHookFunc returns a DecodeHookFunc that converts
// string to []string by splitting on the given sep.
func StringToSliceHookFunc(sep string) DecodeHookFunc {
diff --git a/vendor/github.com/mitchellh/mapstructure/mapstructure.go b/vendor/github.com/mitchellh/mapstructure/mapstructure.go
index 6b81b0067..1efb22ac3 100644
--- a/vendor/github.com/mitchellh/mapstructure/mapstructure.go
+++ b/vendor/github.com/mitchellh/mapstructure/mapstructure.go
@@ -122,7 +122,7 @@
// field value is zero and a numeric type, the field is empty, and it won't
// be encoded into the destination type.
//
-// type Source {
+// type Source struct {
// Age int `mapstructure:",omitempty"`
// }
//
@@ -215,6 +215,12 @@ type DecoderConfig struct {
// (extra keys).
ErrorUnused bool
+ // If ErrorUnset is true, then it is an error for there to exist
+ // fields in the result that were not set in the decoding process
+ // (extra fields). This only applies to decoding to a struct. This
+ // will affect all nested structs as well.
+ ErrorUnset bool
+
// ZeroFields, if set to true, will zero fields before writing them.
// For example, a map will be emptied before decoded values are put in
// it. If this is false, a map will be merged.
@@ -259,6 +265,10 @@ type DecoderConfig struct {
// defaults to "mapstructure"
TagName string
+ // IgnoreUntaggedFields ignores all struct fields without explicit
+ // TagName, comparable to `mapstructure:"-"` as default behaviour.
+ IgnoreUntaggedFields bool
+
// MatchName is the function used to match the map key to the struct
// field name or tag. Defaults to `strings.EqualFold`. This can be used
// to implement case-sensitive tag values, support snake casing, etc.
@@ -284,6 +294,11 @@ type Metadata struct {
// Unused is a slice of keys that were found in the raw value but
// weren't decoded since there was no matching field in the result interface
Unused []string
+
+ // Unset is a slice of field names that were found in the result interface
+ // but weren't set in the decoding process since there was no matching value
+ // in the input
+ Unset []string
}
// Decode takes an input structure and uses reflection to translate it to
@@ -375,6 +390,10 @@ func NewDecoder(config *DecoderConfig) (*Decoder, error) {
if config.Metadata.Unused == nil {
config.Metadata.Unused = make([]string, 0)
}
+
+ if config.Metadata.Unset == nil {
+ config.Metadata.Unset = make([]string, 0)
+ }
}
if config.TagName == "" {
@@ -906,9 +925,15 @@ func (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val re
tagValue := f.Tag.Get(d.config.TagName)
keyName := f.Name
+ if tagValue == "" && d.config.IgnoreUntaggedFields {
+ continue
+ }
+
// If Squash is set in the config, we squash the field down.
squash := d.config.Squash && v.Kind() == reflect.Struct && f.Anonymous
+ v = dereferencePtrToStructIfNeeded(v, d.config.TagName)
+
// Determine the name of the key in the map
if index := strings.Index(tagValue, ","); index != -1 {
if tagValue[:index] == "-" {
@@ -920,7 +945,7 @@ func (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val re
}
// If "squash" is specified in the tag, we squash the field down.
- squash = !squash && strings.Index(tagValue[index+1:], "squash") != -1
+ squash = squash || strings.Index(tagValue[index+1:], "squash") != -1
if squash {
// When squashing, the embedded type can be a pointer to a struct.
if v.Kind() == reflect.Ptr && v.Elem().Kind() == reflect.Struct {
@@ -932,7 +957,9 @@ func (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val re
return fmt.Errorf("cannot squash non-struct type '%s'", v.Type())
}
}
- keyName = tagValue[:index]
+ if keyNameTagValue := tagValue[:index]; keyNameTagValue != "" {
+ keyName = keyNameTagValue
+ }
} else if len(tagValue) > 0 {
if tagValue == "-" {
continue
@@ -1088,7 +1115,7 @@ func (d *Decoder) decodeSlice(name string, data interface{}, val reflect.Value)
}
// If the input value is nil, then don't allocate since empty != nil
- if dataVal.IsNil() {
+ if dataValKind != reflect.Array && dataVal.IsNil() {
return nil
}
@@ -1250,6 +1277,7 @@ func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) e
dataValKeysUnused[dataValKey.Interface()] = struct{}{}
}
+ targetValKeysUnused := make(map[interface{}]struct{})
errors := make([]string, 0)
// This slice will keep track of all the structs we'll be decoding.
@@ -1354,7 +1382,8 @@ func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) e
if !rawMapVal.IsValid() {
// There was no matching key in the map for the value in
- // the struct. Just ignore.
+ // the struct. Remember it for potential errors and metadata.
+ targetValKeysUnused[fieldName] = struct{}{}
continue
}
}
@@ -1414,6 +1443,17 @@ func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) e
errors = appendErrors(errors, err)
}
+ if d.config.ErrorUnset && len(targetValKeysUnused) > 0 {
+ keys := make([]string, 0, len(targetValKeysUnused))
+ for rawKey := range targetValKeysUnused {
+ keys = append(keys, rawKey.(string))
+ }
+ sort.Strings(keys)
+
+ err := fmt.Errorf("'%s' has unset fields: %s", name, strings.Join(keys, ", "))
+ errors = appendErrors(errors, err)
+ }
+
if len(errors) > 0 {
return &Error{errors}
}
@@ -1428,6 +1468,14 @@ func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) e
d.config.Metadata.Unused = append(d.config.Metadata.Unused, key)
}
+ for rawKey := range targetValKeysUnused {
+ key := rawKey.(string)
+ if name != "" {
+ key = name + "." + key
+ }
+
+ d.config.Metadata.Unset = append(d.config.Metadata.Unset, key)
+ }
}
return nil
@@ -1465,3 +1513,28 @@ func getKind(val reflect.Value) reflect.Kind {
return kind
}
}
+
+func isStructTypeConvertibleToMap(typ reflect.Type, checkMapstructureTags bool, tagName string) bool {
+ for i := 0; i < typ.NumField(); i++ {
+ f := typ.Field(i)
+ if f.PkgPath == "" && !checkMapstructureTags { // check for unexported fields
+ return true
+ }
+ if checkMapstructureTags && f.Tag.Get(tagName) != "" { // check for mapstructure tags inside
+ return true
+ }
+ }
+ return false
+}
+
+func dereferencePtrToStructIfNeeded(v reflect.Value, tagName string) reflect.Value {
+ if v.Kind() != reflect.Ptr || v.Elem().Kind() != reflect.Struct {
+ return v
+ }
+ deref := v.Elem()
+ derefT := deref.Type()
+ if isStructTypeConvertibleToMap(derefT, true, tagName) {
+ return deref
+ }
+ return v
+}
diff --git a/vendor/github.com/pelletier/go-toml/CONTRIBUTING.md b/vendor/github.com/pelletier/go-toml/CONTRIBUTING.md
deleted file mode 100644
index 98b9893d3..000000000
--- a/vendor/github.com/pelletier/go-toml/CONTRIBUTING.md
+++ /dev/null
@@ -1,132 +0,0 @@
-## Contributing
-
-Thank you for your interest in go-toml! We appreciate you considering
-contributing to go-toml!
-
-The main goal is the project is to provide an easy-to-use TOML
-implementation for Go that gets the job done and gets out of your way –
-dealing with TOML is probably not the central piece of your project.
-
-As the single maintainer of go-toml, time is scarce. All help, big or
-small, is more than welcomed!
-
-### Ask questions
-
-Any question you may have, somebody else might have it too. Always feel
-free to ask them on the [issues tracker][issues-tracker]. We will try to
-answer them as clearly and quickly as possible, time permitting.
-
-Asking questions also helps us identify areas where the documentation needs
-improvement, or new features that weren't envisioned before. Sometimes, a
-seemingly innocent question leads to the fix of a bug. Don't hesitate and
-ask away!
-
-### Improve the documentation
-
-The best way to share your knowledge and experience with go-toml is to
-improve the documentation. Fix a typo, clarify an interface, add an
-example, anything goes!
-
-The documentation is present in the [README][readme] and thorough the
-source code. On release, it gets updated on [pkg.go.dev][pkg.go.dev]. To make a
-change to the documentation, create a pull request with your proposed
-changes. For simple changes like that, the easiest way to go is probably
-the "Fork this project and edit the file" button on Github, displayed at
-the top right of the file. Unless it's a trivial change (for example a
-typo), provide a little bit of context in your pull request description or
-commit message.
-
-### Report a bug
-
-Found a bug! Sorry to hear that :(. Help us and other track them down and
-fix by reporting it. [File a new bug report][bug-report] on the [issues
-tracker][issues-tracker]. The template should provide enough guidance on
-what to include. When in doubt: add more details! By reducing ambiguity and
-providing more information, it decreases back and forth and saves everyone
-time.
-
-### Code changes
-
-Want to contribute a patch? Very happy to hear that!
-
-First, some high-level rules:
-
-* A short proposal with some POC code is better than a lengthy piece of
- text with no code. Code speaks louder than words.
-* No backward-incompatible patch will be accepted unless discussed.
- Sometimes it's hard, and Go's lack of versioning by default does not
- help, but we try not to break people's programs unless we absolutely have
- to.
-* If you are writing a new feature or extending an existing one, make sure
- to write some documentation.
-* Bug fixes need to be accompanied with regression tests.
-* New code needs to be tested.
-* Your commit messages need to explain why the change is needed, even if
- already included in the PR description.
-
-It does sound like a lot, but those best practices are here to save time
-overall and continuously improve the quality of the project, which is
-something everyone benefits from.
-
-#### Get started
-
-The fairly standard code contribution process looks like that:
-
-1. [Fork the project][fork].
-2. Make your changes, commit on any branch you like.
-3. [Open up a pull request][pull-request]
-4. Review, potential ask for changes.
-5. Merge. You're in!
-
-Feel free to ask for help! You can create draft pull requests to gather
-some early feedback!
-
-#### Run the tests
-
-You can run tests for go-toml using Go's test tool: `go test ./...`.
-When creating a pull requests, all tests will be ran on Linux on a few Go
-versions (Travis CI), and on Windows using the latest Go version
-(AppVeyor).
-
-#### Style
-
-Try to look around and follow the same format and structure as the rest of
-the code. We enforce using `go fmt` on the whole code base.
-
----
-
-### Maintainers-only
-
-#### Merge pull request
-
-Checklist:
-
-* Passing CI.
-* Does not introduce backward-incompatible changes (unless discussed).
-* Has relevant doc changes.
-* Has relevant unit tests.
-
-1. Merge using "squash and merge".
-2. Make sure to edit the commit message to keep all the useful information
- nice and clean.
-3. Make sure the commit title is clear and contains the PR number (#123).
-
-#### New release
-
-1. Go to [releases][releases]. Click on "X commits to master since this
- release".
-2. Make note of all the changes. Look for backward incompatible changes,
- new features, and bug fixes.
-3. Pick the new version using the above and semver.
-4. Create a [new release][new-release].
-5. Follow the same format as [1.1.0][release-110].
-
-[issues-tracker]: https://github.com/pelletier/go-toml/issues
-[bug-report]: https://github.com/pelletier/go-toml/issues/new?template=bug_report.md
-[pkg.go.dev]: https://pkg.go.dev/github.com/pelletier/go-toml
-[readme]: ./README.md
-[fork]: https://help.github.com/articles/fork-a-repo
-[pull-request]: https://help.github.com/en/articles/creating-a-pull-request
-[releases]: https://github.com/pelletier/go-toml/releases
-[new-release]: https://github.com/pelletier/go-toml/releases/new
-[release-110]: https://github.com/pelletier/go-toml/releases/tag/v1.1.0
diff --git a/vendor/github.com/pelletier/go-toml/Dockerfile b/vendor/github.com/pelletier/go-toml/Dockerfile
deleted file mode 100644
index fffdb0166..000000000
--- a/vendor/github.com/pelletier/go-toml/Dockerfile
+++ /dev/null
@@ -1,11 +0,0 @@
-FROM golang:1.12-alpine3.9 as builder
-WORKDIR /go/src/github.com/pelletier/go-toml
-COPY . .
-ENV CGO_ENABLED=0
-ENV GOOS=linux
-RUN go install ./...
-
-FROM scratch
-COPY --from=builder /go/bin/tomll /usr/bin/tomll
-COPY --from=builder /go/bin/tomljson /usr/bin/tomljson
-COPY --from=builder /go/bin/jsontoml /usr/bin/jsontoml
diff --git a/vendor/github.com/pelletier/go-toml/LICENSE b/vendor/github.com/pelletier/go-toml/LICENSE
deleted file mode 100644
index f414553c2..000000000
--- a/vendor/github.com/pelletier/go-toml/LICENSE
+++ /dev/null
@@ -1,247 +0,0 @@
-The bulk of github.com/pelletier/go-toml is distributed under the MIT license
-(see below), with the exception of localtime.go and localtime.test.go.
-Those two files have been copied over from Google's civil library at revision
-ed46f5086358513cf8c25f8e3f022cb838a49d66, and are distributed under the Apache
-2.0 license (see below).
-
-
-github.com/pelletier/go-toml:
-
-
-The MIT License (MIT)
-
-Copyright (c) 2013 - 2021 Thomas Pelletier, Eric Anderton
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
-
-localtime.go, localtime_test.go:
-
-Originals:
- https://raw.githubusercontent.com/googleapis/google-cloud-go/ed46f5086358513cf8c25f8e3f022cb838a49d66/civil/civil.go
- https://raw.githubusercontent.com/googleapis/google-cloud-go/ed46f5086358513cf8c25f8e3f022cb838a49d66/civil/civil_test.go
-Changes:
- * Renamed files from civil* to localtime*.
- * Package changed from civil to toml.
- * 'Local' prefix added to all structs.
-License:
- https://raw.githubusercontent.com/googleapis/google-cloud-go/ed46f5086358513cf8c25f8e3f022cb838a49d66/LICENSE
-
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright [yyyy] [name of copyright owner]
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
diff --git a/vendor/github.com/pelletier/go-toml/Makefile b/vendor/github.com/pelletier/go-toml/Makefile
deleted file mode 100644
index 9e4503aea..000000000
--- a/vendor/github.com/pelletier/go-toml/Makefile
+++ /dev/null
@@ -1,29 +0,0 @@
-export CGO_ENABLED=0
-go := go
-go.goos ?= $(shell echo `go version`|cut -f4 -d ' '|cut -d '/' -f1)
-go.goarch ?= $(shell echo `go version`|cut -f4 -d ' '|cut -d '/' -f2)
-
-out.tools := tomll tomljson jsontoml
-out.dist := $(out.tools:=_$(go.goos)_$(go.goarch).tar.xz)
-sources := $(wildcard **/*.go)
-
-
-.PHONY:
-tools: $(out.tools)
-
-$(out.tools): $(sources)
- GOOS=$(go.goos) GOARCH=$(go.goarch) $(go) build ./cmd/$@
-
-.PHONY:
-dist: $(out.dist)
-
-$(out.dist):%_$(go.goos)_$(go.goarch).tar.xz: %
- if [ "$(go.goos)" = "windows" ]; then \
- tar -cJf $@ $^.exe; \
- else \
- tar -cJf $@ $^; \
- fi
-
-.PHONY:
-clean:
- rm -rf $(out.tools) $(out.dist)
diff --git a/vendor/github.com/pelletier/go-toml/PULL_REQUEST_TEMPLATE.md b/vendor/github.com/pelletier/go-toml/PULL_REQUEST_TEMPLATE.md
deleted file mode 100644
index 041cdc4a2..000000000
--- a/vendor/github.com/pelletier/go-toml/PULL_REQUEST_TEMPLATE.md
+++ /dev/null
@@ -1,5 +0,0 @@
-**Issue:** add link to pelletier/go-toml issue here
-
-Explanation of what this pull request does.
-
-More detailed description of the decisions being made and the reasons why (if the patch is non-trivial).
diff --git a/vendor/github.com/pelletier/go-toml/README.md b/vendor/github.com/pelletier/go-toml/README.md
deleted file mode 100644
index 6c061712b..000000000
--- a/vendor/github.com/pelletier/go-toml/README.md
+++ /dev/null
@@ -1,176 +0,0 @@
-# go-toml
-
-Go library for the [TOML](https://toml.io/) format.
-
-This library supports TOML version
-[v1.0.0-rc.3](https://toml.io/en/v1.0.0-rc.3)
-
-[![Go Reference](https://pkg.go.dev/badge/github.com/pelletier/go-toml.svg)](https://pkg.go.dev/github.com/pelletier/go-toml)
-[![license](https://img.shields.io/github/license/pelletier/go-toml.svg)](https://github.com/pelletier/go-toml/blob/master/LICENSE)
-[![Build Status](https://dev.azure.com/pelletierthomas/go-toml-ci/_apis/build/status/pelletier.go-toml?branchName=master)](https://dev.azure.com/pelletierthomas/go-toml-ci/_build/latest?definitionId=1&branchName=master)
-[![codecov](https://codecov.io/gh/pelletier/go-toml/branch/master/graph/badge.svg)](https://codecov.io/gh/pelletier/go-toml)
-[![Go Report Card](https://goreportcard.com/badge/github.com/pelletier/go-toml)](https://goreportcard.com/report/github.com/pelletier/go-toml)
-[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fpelletier%2Fgo-toml.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fpelletier%2Fgo-toml?ref=badge_shield)
-
-
-## Development status
-
-**ℹ️ Consider go-toml v2!**
-
-The next version of go-toml is in [active development][v2-dev], and
-[nearing completion][v2-map].
-
-Though technically in beta, v2 is already more tested, [fixes bugs][v1-bugs],
-and [much faster][v2-bench]. If you only need reading and writing TOML documents
-(majority of cases), those features are implemented and the API unlikely to
-change.
-
-The remaining features (Document structure editing and tooling) will be added
-shortly. While pull-requests are welcome on v1, no active development is
-expected on it. When v2.0.0 is released, v1 will be deprecated.
-
-👉 [go-toml v2][v2]
-
-[v2]: https://github.com/pelletier/go-toml/tree/v2
-[v2-map]: https://github.com/pelletier/go-toml/discussions/506
-[v2-dev]: https://github.com/pelletier/go-toml/tree/v2
-[v1-bugs]: https://github.com/pelletier/go-toml/issues?q=is%3Aissue+is%3Aopen+label%3Av2-fixed
-[v2-bench]: https://github.com/pelletier/go-toml/tree/v2#benchmarks
-
-## Features
-
-Go-toml provides the following features for using data parsed from TOML documents:
-
-* Load TOML documents from files and string data
-* Easily navigate TOML structure using Tree
-* Marshaling and unmarshaling to and from data structures
-* Line & column position data for all parsed elements
-* [Query support similar to JSON-Path](query/)
-* Syntax errors contain line and column numbers
-
-## Import
-
-```go
-import "github.com/pelletier/go-toml"
-```
-
-## Usage example
-
-Read a TOML document:
-
-```go
-config, _ := toml.Load(`
-[postgres]
-user = "pelletier"
-password = "mypassword"`)
-// retrieve data directly
-user := config.Get("postgres.user").(string)
-
-// or using an intermediate object
-postgresConfig := config.Get("postgres").(*toml.Tree)
-password := postgresConfig.Get("password").(string)
-```
-
-Or use Unmarshal:
-
-```go
-type Postgres struct {
- User string
- Password string
-}
-type Config struct {
- Postgres Postgres
-}
-
-doc := []byte(`
-[Postgres]
-User = "pelletier"
-Password = "mypassword"`)
-
-config := Config{}
-toml.Unmarshal(doc, &config)
-fmt.Println("user=", config.Postgres.User)
-```
-
-Or use a query:
-
-```go
-// use a query to gather elements without walking the tree
-q, _ := query.Compile("$..[user,password]")
-results := q.Execute(config)
-for ii, item := range results.Values() {
- fmt.Printf("Query result %d: %v\n", ii, item)
-}
-```
-
-## Documentation
-
-The documentation and additional examples are available at
-[pkg.go.dev](https://pkg.go.dev/github.com/pelletier/go-toml).
-
-## Tools
-
-Go-toml provides three handy command line tools:
-
-* `tomll`: Reads TOML files and lints them.
-
- ```
- go install github.com/pelletier/go-toml/cmd/tomll
- tomll --help
- ```
-* `tomljson`: Reads a TOML file and outputs its JSON representation.
-
- ```
- go install github.com/pelletier/go-toml/cmd/tomljson
- tomljson --help
- ```
-
- * `jsontoml`: Reads a JSON file and outputs a TOML representation.
-
- ```
- go install github.com/pelletier/go-toml/cmd/jsontoml
- jsontoml --help
- ```
-
-### Docker image
-
-Those tools are also available as a Docker image from
-[dockerhub](https://hub.docker.com/r/pelletier/go-toml). For example, to
-use `tomljson`:
-
-```
-docker run -v $PWD:/workdir pelletier/go-toml tomljson /workdir/example.toml
-```
-
-Only master (`latest`) and tagged versions are published to dockerhub. You
-can build your own image as usual:
-
-```
-docker build -t go-toml .
-```
-
-## Contribute
-
-Feel free to report bugs and patches using GitHub's pull requests system on
-[pelletier/go-toml](https://github.com/pelletier/go-toml). Any feedback would be
-much appreciated!
-
-### Run tests
-
-`go test ./...`
-
-### Fuzzing
-
-The script `./fuzz.sh` is available to
-run [go-fuzz](https://github.com/dvyukov/go-fuzz) on go-toml.
-
-## Versioning
-
-Go-toml follows [Semantic Versioning](http://semver.org/). The supported version
-of [TOML](https://github.com/toml-lang/toml) is indicated at the beginning of
-this document. The last two major versions of Go are supported
-(see [Go Release Policy](https://golang.org/doc/devel/release.html#policy)).
-
-## License
-
-The MIT License (MIT) + Apache 2.0. Read [LICENSE](LICENSE).
diff --git a/vendor/github.com/pelletier/go-toml/azure-pipelines.yml b/vendor/github.com/pelletier/go-toml/azure-pipelines.yml
deleted file mode 100644
index 4af198b4d..000000000
--- a/vendor/github.com/pelletier/go-toml/azure-pipelines.yml
+++ /dev/null
@@ -1,188 +0,0 @@
-trigger:
-- master
-
-stages:
-- stage: run_checks
- displayName: "Check"
- dependsOn: []
- jobs:
- - job: fmt
- displayName: "fmt"
- pool:
- vmImage: ubuntu-latest
- steps:
- - task: GoTool@0
- displayName: "Install Go 1.16"
- inputs:
- version: "1.16"
- - task: Go@0
- displayName: "go fmt ./..."
- inputs:
- command: 'custom'
- customCommand: 'fmt'
- arguments: './...'
- - job: coverage
- displayName: "coverage"
- pool:
- vmImage: ubuntu-latest
- steps:
- - task: GoTool@0
- displayName: "Install Go 1.16"
- inputs:
- version: "1.16"
- - task: Go@0
- displayName: "Generate coverage"
- inputs:
- command: 'test'
- arguments: "-race -coverprofile=coverage.txt -covermode=atomic"
- - task: Bash@3
- inputs:
- targetType: 'inline'
- script: 'bash <(curl -s https://codecov.io/bash) -t ${CODECOV_TOKEN}'
- env:
- CODECOV_TOKEN: $(CODECOV_TOKEN)
- - job: benchmark
- displayName: "benchmark"
- pool:
- vmImage: ubuntu-latest
- steps:
- - task: GoTool@0
- displayName: "Install Go 1.16"
- inputs:
- version: "1.16"
- - script: echo "##vso[task.setvariable variable=PATH]${PATH}:/home/vsts/go/bin/"
- - task: Bash@3
- inputs:
- filePath: './benchmark.sh'
- arguments: "master $(Build.Repository.Uri)"
-
- - job: go_unit_tests
- displayName: "unit tests"
- strategy:
- matrix:
- linux 1.16:
- goVersion: '1.16'
- imageName: 'ubuntu-latest'
- mac 1.16:
- goVersion: '1.16'
- imageName: 'macOS-latest'
- windows 1.16:
- goVersion: '1.16'
- imageName: 'windows-latest'
- linux 1.15:
- goVersion: '1.15'
- imageName: 'ubuntu-latest'
- mac 1.15:
- goVersion: '1.15'
- imageName: 'macOS-latest'
- windows 1.15:
- goVersion: '1.15'
- imageName: 'windows-latest'
- pool:
- vmImage: $(imageName)
- steps:
- - task: GoTool@0
- displayName: "Install Go $(goVersion)"
- inputs:
- version: $(goVersion)
- - task: Go@0
- displayName: "go test ./..."
- inputs:
- command: 'test'
- arguments: './...'
-- stage: build_binaries
- displayName: "Build binaries"
- dependsOn: run_checks
- jobs:
- - job: build_binary
- displayName: "Build binary"
- strategy:
- matrix:
- linux_amd64:
- GOOS: linux
- GOARCH: amd64
- darwin_amd64:
- GOOS: darwin
- GOARCH: amd64
- windows_amd64:
- GOOS: windows
- GOARCH: amd64
- pool:
- vmImage: ubuntu-latest
- steps:
- - task: GoTool@0
- displayName: "Install Go"
- inputs:
- version: 1.16
- - task: Bash@3
- inputs:
- targetType: inline
- script: "make dist"
- env:
- go.goos: $(GOOS)
- go.goarch: $(GOARCH)
- - task: CopyFiles@2
- inputs:
- sourceFolder: '$(Build.SourcesDirectory)'
- contents: '*.tar.xz'
- TargetFolder: '$(Build.ArtifactStagingDirectory)'
- - task: PublishBuildArtifacts@1
- inputs:
- pathtoPublish: '$(Build.ArtifactStagingDirectory)'
- artifactName: binaries
-- stage: build_binaries_manifest
- displayName: "Build binaries manifest"
- dependsOn: build_binaries
- jobs:
- - job: build_manifest
- displayName: "Build binaries manifest"
- steps:
- - task: DownloadBuildArtifacts@0
- inputs:
- buildType: 'current'
- downloadType: 'single'
- artifactName: 'binaries'
- downloadPath: '$(Build.SourcesDirectory)'
- - task: Bash@3
- inputs:
- targetType: inline
- script: "cd binaries && sha256sum --binary *.tar.xz | tee $(Build.ArtifactStagingDirectory)/sha256sums.txt"
- - task: PublishBuildArtifacts@1
- inputs:
- pathtoPublish: '$(Build.ArtifactStagingDirectory)'
- artifactName: manifest
-
-- stage: build_docker_image
- displayName: "Build Docker image"
- dependsOn: run_checks
- jobs:
- - job: build
- displayName: "Build"
- pool:
- vmImage: ubuntu-latest
- steps:
- - task: Docker@2
- inputs:
- command: 'build'
- Dockerfile: 'Dockerfile'
- buildContext: '.'
- addPipelineData: false
-
-- stage: publish_docker_image
- displayName: "Publish Docker image"
- dependsOn: build_docker_image
- condition: and(succeeded(), eq(variables['Build.SourceBranchName'], 'master'))
- jobs:
- - job: publish
- displayName: "Publish"
- pool:
- vmImage: ubuntu-latest
- steps:
- - task: Docker@2
- inputs:
- containerRegistry: 'DockerHub'
- repository: 'pelletier/go-toml'
- command: 'buildAndPush'
- Dockerfile: 'Dockerfile'
- buildContext: '.'
- tags: 'latest'
diff --git a/vendor/github.com/pelletier/go-toml/benchmark.sh b/vendor/github.com/pelletier/go-toml/benchmark.sh
deleted file mode 100644
index a69d3040f..000000000
--- a/vendor/github.com/pelletier/go-toml/benchmark.sh
+++ /dev/null
@@ -1,35 +0,0 @@
-#!/bin/bash
-
-set -ex
-
-reference_ref=${1:-master}
-reference_git=${2:-.}
-
-if ! `hash benchstat 2>/dev/null`; then
- echo "Installing benchstat"
- go get golang.org/x/perf/cmd/benchstat
-fi
-
-tempdir=`mktemp -d /tmp/go-toml-benchmark-XXXXXX`
-ref_tempdir="${tempdir}/ref"
-ref_benchmark="${ref_tempdir}/benchmark-`echo -n ${reference_ref}|tr -s '/' '-'`.txt"
-local_benchmark="`pwd`/benchmark-local.txt"
-
-echo "=== ${reference_ref} (${ref_tempdir})"
-git clone ${reference_git} ${ref_tempdir} >/dev/null 2>/dev/null
-pushd ${ref_tempdir} >/dev/null
-git checkout ${reference_ref} >/dev/null 2>/dev/null
-go test -bench=. -benchmem | tee ${ref_benchmark}
-cd benchmark
-go test -bench=. -benchmem | tee -a ${ref_benchmark}
-popd >/dev/null
-
-echo ""
-echo "=== local"
-go test -bench=. -benchmem | tee ${local_benchmark}
-cd benchmark
-go test -bench=. -benchmem | tee -a ${local_benchmark}
-
-echo ""
-echo "=== diff"
-benchstat -delta-test=none ${ref_benchmark} ${local_benchmark}
diff --git a/vendor/github.com/pelletier/go-toml/doc.go b/vendor/github.com/pelletier/go-toml/doc.go
deleted file mode 100644
index a1406a32b..000000000
--- a/vendor/github.com/pelletier/go-toml/doc.go
+++ /dev/null
@@ -1,23 +0,0 @@
-// Package toml is a TOML parser and manipulation library.
-//
-// This version supports the specification as described in
-// https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.5.0.md
-//
-// Marshaling
-//
-// Go-toml can marshal and unmarshal TOML documents from and to data
-// structures.
-//
-// TOML document as a tree
-//
-// Go-toml can operate on a TOML document as a tree. Use one of the Load*
-// functions to parse TOML data and obtain a Tree instance, then one of its
-// methods to manipulate the tree.
-//
-// JSONPath-like queries
-//
-// The package github.com/pelletier/go-toml/query implements a system
-// similar to JSONPath to quickly retrieve elements of a TOML document using a
-// single expression. See the package documentation for more information.
-//
-package toml
diff --git a/vendor/github.com/pelletier/go-toml/example-crlf.toml b/vendor/github.com/pelletier/go-toml/example-crlf.toml
deleted file mode 100644
index 780d9c68f..000000000
--- a/vendor/github.com/pelletier/go-toml/example-crlf.toml
+++ /dev/null
@@ -1,30 +0,0 @@
-# This is a TOML document. Boom.
-
-title = "TOML Example"
-
-[owner]
-name = "Tom Preston-Werner"
-organization = "GitHub"
-bio = "GitHub Cofounder & CEO\nLikes tater tots and beer."
-dob = 1979-05-27T07:32:00Z # First class dates? Why not?
-
-[database]
-server = "192.168.1.1"
-ports = [ 8001, 8001, 8002 ]
-connection_max = 5000
-enabled = true
-
-[servers]
-
- # You can indent as you please. Tabs or spaces. TOML don't care.
- [servers.alpha]
- ip = "10.0.0.1"
- dc = "eqdc10"
-
- [servers.beta]
- ip = "10.0.0.2"
- dc = "eqdc10"
-
-[clients]
-data = [ ["gamma", "delta"], [1, 2] ] # just an update to make sure parsers support it
-score = 4e-08 # to make sure leading zeroes in exponent parts of floats are supported
\ No newline at end of file
diff --git a/vendor/github.com/pelletier/go-toml/example.toml b/vendor/github.com/pelletier/go-toml/example.toml
deleted file mode 100644
index f45bf88b8..000000000
--- a/vendor/github.com/pelletier/go-toml/example.toml
+++ /dev/null
@@ -1,30 +0,0 @@
-# This is a TOML document. Boom.
-
-title = "TOML Example"
-
-[owner]
-name = "Tom Preston-Werner"
-organization = "GitHub"
-bio = "GitHub Cofounder & CEO\nLikes tater tots and beer."
-dob = 1979-05-27T07:32:00Z # First class dates? Why not?
-
-[database]
-server = "192.168.1.1"
-ports = [ 8001, 8001, 8002 ]
-connection_max = 5000
-enabled = true
-
-[servers]
-
- # You can indent as you please. Tabs or spaces. TOML don't care.
- [servers.alpha]
- ip = "10.0.0.1"
- dc = "eqdc10"
-
- [servers.beta]
- ip = "10.0.0.2"
- dc = "eqdc10"
-
-[clients]
-data = [ ["gamma", "delta"], [1, 2] ] # just an update to make sure parsers support it
-score = 4e-08 # to make sure leading zeroes in exponent parts of floats are supported
\ No newline at end of file
diff --git a/vendor/github.com/pelletier/go-toml/fuzz.go b/vendor/github.com/pelletier/go-toml/fuzz.go
deleted file mode 100644
index 14570c8d3..000000000
--- a/vendor/github.com/pelletier/go-toml/fuzz.go
+++ /dev/null
@@ -1,31 +0,0 @@
-// +build gofuzz
-
-package toml
-
-func Fuzz(data []byte) int {
- tree, err := LoadBytes(data)
- if err != nil {
- if tree != nil {
- panic("tree must be nil if there is an error")
- }
- return 0
- }
-
- str, err := tree.ToTomlString()
- if err != nil {
- if str != "" {
- panic(`str must be "" if there is an error`)
- }
- panic(err)
- }
-
- tree, err = Load(str)
- if err != nil {
- if tree != nil {
- panic("tree must be nil if there is an error")
- }
- return 0
- }
-
- return 1
-}
diff --git a/vendor/github.com/pelletier/go-toml/fuzz.sh b/vendor/github.com/pelletier/go-toml/fuzz.sh
deleted file mode 100644
index 3204b4c44..000000000
--- a/vendor/github.com/pelletier/go-toml/fuzz.sh
+++ /dev/null
@@ -1,15 +0,0 @@
-#! /bin/sh
-set -eu
-
-go get github.com/dvyukov/go-fuzz/go-fuzz
-go get github.com/dvyukov/go-fuzz/go-fuzz-build
-
-if [ ! -e toml-fuzz.zip ]; then
- go-fuzz-build github.com/pelletier/go-toml
-fi
-
-rm -fr fuzz
-mkdir -p fuzz/corpus
-cp *.toml fuzz/corpus
-
-go-fuzz -bin=toml-fuzz.zip -workdir=fuzz
diff --git a/vendor/github.com/pelletier/go-toml/keysparsing.go b/vendor/github.com/pelletier/go-toml/keysparsing.go
deleted file mode 100644
index e091500b2..000000000
--- a/vendor/github.com/pelletier/go-toml/keysparsing.go
+++ /dev/null
@@ -1,112 +0,0 @@
-// Parsing keys handling both bare and quoted keys.
-
-package toml
-
-import (
- "errors"
- "fmt"
-)
-
-// Convert the bare key group string to an array.
-// The input supports double quotation and single quotation,
-// but escape sequences are not supported. Lexers must unescape them beforehand.
-func parseKey(key string) ([]string, error) {
- runes := []rune(key)
- var groups []string
-
- if len(key) == 0 {
- return nil, errors.New("empty key")
- }
-
- idx := 0
- for idx < len(runes) {
- for ; idx < len(runes) && isSpace(runes[idx]); idx++ {
- // skip leading whitespace
- }
- if idx >= len(runes) {
- break
- }
- r := runes[idx]
- if isValidBareChar(r) {
- // parse bare key
- startIdx := idx
- endIdx := -1
- idx++
- for idx < len(runes) {
- r = runes[idx]
- if isValidBareChar(r) {
- idx++
- } else if r == '.' {
- endIdx = idx
- break
- } else if isSpace(r) {
- endIdx = idx
- for ; idx < len(runes) && isSpace(runes[idx]); idx++ {
- // skip trailing whitespace
- }
- if idx < len(runes) && runes[idx] != '.' {
- return nil, fmt.Errorf("invalid key character after whitespace: %c", runes[idx])
- }
- break
- } else {
- return nil, fmt.Errorf("invalid bare key character: %c", r)
- }
- }
- if endIdx == -1 {
- endIdx = idx
- }
- groups = append(groups, string(runes[startIdx:endIdx]))
- } else if r == '\'' {
- // parse single quoted key
- idx++
- startIdx := idx
- for {
- if idx >= len(runes) {
- return nil, fmt.Errorf("unclosed single-quoted key")
- }
- r = runes[idx]
- if r == '\'' {
- groups = append(groups, string(runes[startIdx:idx]))
- idx++
- break
- }
- idx++
- }
- } else if r == '"' {
- // parse double quoted key
- idx++
- startIdx := idx
- for {
- if idx >= len(runes) {
- return nil, fmt.Errorf("unclosed double-quoted key")
- }
- r = runes[idx]
- if r == '"' {
- groups = append(groups, string(runes[startIdx:idx]))
- idx++
- break
- }
- idx++
- }
- } else if r == '.' {
- idx++
- if idx >= len(runes) {
- return nil, fmt.Errorf("unexpected end of key")
- }
- r = runes[idx]
- if !isValidBareChar(r) && r != '\'' && r != '"' && r != ' ' {
- return nil, fmt.Errorf("expecting key part after dot")
- }
- } else {
- return nil, fmt.Errorf("invalid key character: %c", r)
- }
- }
- if len(groups) == 0 {
- return nil, fmt.Errorf("empty key")
- }
- return groups, nil
-}
-
-func isValidBareChar(r rune) bool {
- return isAlphanumeric(r) || r == '-' || isDigit(r)
-}
diff --git a/vendor/github.com/pelletier/go-toml/lexer.go b/vendor/github.com/pelletier/go-toml/lexer.go
deleted file mode 100644
index 313908e3e..000000000
--- a/vendor/github.com/pelletier/go-toml/lexer.go
+++ /dev/null
@@ -1,1031 +0,0 @@
-// TOML lexer.
-//
-// Written using the principles developed by Rob Pike in
-// http://www.youtube.com/watch?v=HxaD_trXwRE
-
-package toml
-
-import (
- "bytes"
- "errors"
- "fmt"
- "strconv"
- "strings"
-)
-
-// Define state functions
-type tomlLexStateFn func() tomlLexStateFn
-
-// Define lexer
-type tomlLexer struct {
- inputIdx int
- input []rune // Textual source
- currentTokenStart int
- currentTokenStop int
- tokens []token
- brackets []rune
- line int
- col int
- endbufferLine int
- endbufferCol int
-}
-
-// Basic read operations on input
-
-func (l *tomlLexer) read() rune {
- r := l.peek()
- if r == '\n' {
- l.endbufferLine++
- l.endbufferCol = 1
- } else {
- l.endbufferCol++
- }
- l.inputIdx++
- return r
-}
-
-func (l *tomlLexer) next() rune {
- r := l.read()
-
- if r != eof {
- l.currentTokenStop++
- }
- return r
-}
-
-func (l *tomlLexer) ignore() {
- l.currentTokenStart = l.currentTokenStop
- l.line = l.endbufferLine
- l.col = l.endbufferCol
-}
-
-func (l *tomlLexer) skip() {
- l.next()
- l.ignore()
-}
-
-func (l *tomlLexer) fastForward(n int) {
- for i := 0; i < n; i++ {
- l.next()
- }
-}
-
-func (l *tomlLexer) emitWithValue(t tokenType, value string) {
- l.tokens = append(l.tokens, token{
- Position: Position{l.line, l.col},
- typ: t,
- val: value,
- })
- l.ignore()
-}
-
-func (l *tomlLexer) emit(t tokenType) {
- l.emitWithValue(t, string(l.input[l.currentTokenStart:l.currentTokenStop]))
-}
-
-func (l *tomlLexer) peek() rune {
- if l.inputIdx >= len(l.input) {
- return eof
- }
- return l.input[l.inputIdx]
-}
-
-func (l *tomlLexer) peekString(size int) string {
- maxIdx := len(l.input)
- upperIdx := l.inputIdx + size // FIXME: potential overflow
- if upperIdx > maxIdx {
- upperIdx = maxIdx
- }
- return string(l.input[l.inputIdx:upperIdx])
-}
-
-func (l *tomlLexer) follow(next string) bool {
- return next == l.peekString(len(next))
-}
-
-// Error management
-
-func (l *tomlLexer) errorf(format string, args ...interface{}) tomlLexStateFn {
- l.tokens = append(l.tokens, token{
- Position: Position{l.line, l.col},
- typ: tokenError,
- val: fmt.Sprintf(format, args...),
- })
- return nil
-}
-
-// State functions
-
-func (l *tomlLexer) lexVoid() tomlLexStateFn {
- for {
- next := l.peek()
- switch next {
- case '}': // after '{'
- return l.lexRightCurlyBrace
- case '[':
- return l.lexTableKey
- case '#':
- return l.lexComment(l.lexVoid)
- case '=':
- return l.lexEqual
- case '\r':
- fallthrough
- case '\n':
- l.skip()
- continue
- }
-
- if isSpace(next) {
- l.skip()
- }
-
- if isKeyStartChar(next) {
- return l.lexKey
- }
-
- if next == eof {
- l.next()
- break
- }
- }
-
- l.emit(tokenEOF)
- return nil
-}
-
-func (l *tomlLexer) lexRvalue() tomlLexStateFn {
- for {
- next := l.peek()
- switch next {
- case '.':
- return l.errorf("cannot start float with a dot")
- case '=':
- return l.lexEqual
- case '[':
- return l.lexLeftBracket
- case ']':
- return l.lexRightBracket
- case '{':
- return l.lexLeftCurlyBrace
- case '}':
- return l.lexRightCurlyBrace
- case '#':
- return l.lexComment(l.lexRvalue)
- case '"':
- return l.lexString
- case '\'':
- return l.lexLiteralString
- case ',':
- return l.lexComma
- case '\r':
- fallthrough
- case '\n':
- l.skip()
- if len(l.brackets) > 0 && l.brackets[len(l.brackets)-1] == '[' {
- return l.lexRvalue
- }
- return l.lexVoid
- }
-
- if l.follow("true") {
- return l.lexTrue
- }
-
- if l.follow("false") {
- return l.lexFalse
- }
-
- if l.follow("inf") {
- return l.lexInf
- }
-
- if l.follow("nan") {
- return l.lexNan
- }
-
- if isSpace(next) {
- l.skip()
- continue
- }
-
- if next == eof {
- l.next()
- break
- }
-
- if next == '+' || next == '-' {
- return l.lexNumber
- }
-
- if isDigit(next) {
- return l.lexDateTimeOrNumber
- }
-
- return l.errorf("no value can start with %c", next)
- }
-
- l.emit(tokenEOF)
- return nil
-}
-
-func (l *tomlLexer) lexDateTimeOrNumber() tomlLexStateFn {
- // Could be either a date/time, or a digit.
- // The options for date/times are:
- // YYYY-... => date or date-time
- // HH:... => time
- // Anything else should be a number.
-
- lookAhead := l.peekString(5)
- if len(lookAhead) < 3 {
- return l.lexNumber()
- }
-
- for idx, r := range lookAhead {
- if !isDigit(r) {
- if idx == 2 && r == ':' {
- return l.lexDateTimeOrTime()
- }
- if idx == 4 && r == '-' {
- return l.lexDateTimeOrTime()
- }
- return l.lexNumber()
- }
- }
- return l.lexNumber()
-}
-
-func (l *tomlLexer) lexLeftCurlyBrace() tomlLexStateFn {
- l.next()
- l.emit(tokenLeftCurlyBrace)
- l.brackets = append(l.brackets, '{')
- return l.lexVoid
-}
-
-func (l *tomlLexer) lexRightCurlyBrace() tomlLexStateFn {
- l.next()
- l.emit(tokenRightCurlyBrace)
- if len(l.brackets) == 0 || l.brackets[len(l.brackets)-1] != '{' {
- return l.errorf("cannot have '}' here")
- }
- l.brackets = l.brackets[:len(l.brackets)-1]
- return l.lexRvalue
-}
-
-func (l *tomlLexer) lexDateTimeOrTime() tomlLexStateFn {
- // Example matches:
- // 1979-05-27T07:32:00Z
- // 1979-05-27T00:32:00-07:00
- // 1979-05-27T00:32:00.999999-07:00
- // 1979-05-27 07:32:00Z
- // 1979-05-27 00:32:00-07:00
- // 1979-05-27 00:32:00.999999-07:00
- // 1979-05-27T07:32:00
- // 1979-05-27T00:32:00.999999
- // 1979-05-27 07:32:00
- // 1979-05-27 00:32:00.999999
- // 1979-05-27
- // 07:32:00
- // 00:32:00.999999
-
- // we already know those two are digits
- l.next()
- l.next()
-
- // Got 2 digits. At that point it could be either a time or a date(-time).
-
- r := l.next()
- if r == ':' {
- return l.lexTime()
- }
-
- return l.lexDateTime()
-}
-
-func (l *tomlLexer) lexDateTime() tomlLexStateFn {
- // This state accepts an offset date-time, a local date-time, or a local date.
- //
- // v--- cursor
- // 1979-05-27T07:32:00Z
- // 1979-05-27T00:32:00-07:00
- // 1979-05-27T00:32:00.999999-07:00
- // 1979-05-27 07:32:00Z
- // 1979-05-27 00:32:00-07:00
- // 1979-05-27 00:32:00.999999-07:00
- // 1979-05-27T07:32:00
- // 1979-05-27T00:32:00.999999
- // 1979-05-27 07:32:00
- // 1979-05-27 00:32:00.999999
- // 1979-05-27
-
- // date
-
- // already checked by lexRvalue
- l.next() // digit
- l.next() // -
-
- for i := 0; i < 2; i++ {
- r := l.next()
- if !isDigit(r) {
- return l.errorf("invalid month digit in date: %c", r)
- }
- }
-
- r := l.next()
- if r != '-' {
- return l.errorf("expected - to separate month of a date, not %c", r)
- }
-
- for i := 0; i < 2; i++ {
- r := l.next()
- if !isDigit(r) {
- return l.errorf("invalid day digit in date: %c", r)
- }
- }
-
- l.emit(tokenLocalDate)
-
- r = l.peek()
-
- if r == eof {
-
- return l.lexRvalue
- }
-
- if r != ' ' && r != 'T' {
- return l.errorf("incorrect date/time separation character: %c", r)
- }
-
- if r == ' ' {
- lookAhead := l.peekString(3)[1:]
- if len(lookAhead) < 2 {
- return l.lexRvalue
- }
- for _, r := range lookAhead {
- if !isDigit(r) {
- return l.lexRvalue
- }
- }
- }
-
- l.skip() // skip the T or ' '
-
- // time
-
- for i := 0; i < 2; i++ {
- r := l.next()
- if !isDigit(r) {
- return l.errorf("invalid hour digit in time: %c", r)
- }
- }
-
- r = l.next()
- if r != ':' {
- return l.errorf("time hour/minute separator should be :, not %c", r)
- }
-
- for i := 0; i < 2; i++ {
- r := l.next()
- if !isDigit(r) {
- return l.errorf("invalid minute digit in time: %c", r)
- }
- }
-
- r = l.next()
- if r != ':' {
- return l.errorf("time minute/second separator should be :, not %c", r)
- }
-
- for i := 0; i < 2; i++ {
- r := l.next()
- if !isDigit(r) {
- return l.errorf("invalid second digit in time: %c", r)
- }
- }
-
- r = l.peek()
- if r == '.' {
- l.next()
- r := l.next()
- if !isDigit(r) {
- return l.errorf("expected at least one digit in time's fraction, not %c", r)
- }
-
- for {
- r := l.peek()
- if !isDigit(r) {
- break
- }
- l.next()
- }
- }
-
- l.emit(tokenLocalTime)
-
- return l.lexTimeOffset
-
-}
-
-func (l *tomlLexer) lexTimeOffset() tomlLexStateFn {
- // potential offset
-
- // Z
- // -07:00
- // +07:00
- // nothing
-
- r := l.peek()
-
- if r == 'Z' {
- l.next()
- l.emit(tokenTimeOffset)
- } else if r == '+' || r == '-' {
- l.next()
-
- for i := 0; i < 2; i++ {
- r := l.next()
- if !isDigit(r) {
- return l.errorf("invalid hour digit in time offset: %c", r)
- }
- }
-
- r = l.next()
- if r != ':' {
- return l.errorf("time offset hour/minute separator should be :, not %c", r)
- }
-
- for i := 0; i < 2; i++ {
- r := l.next()
- if !isDigit(r) {
- return l.errorf("invalid minute digit in time offset: %c", r)
- }
- }
-
- l.emit(tokenTimeOffset)
- }
-
- return l.lexRvalue
-}
-
-func (l *tomlLexer) lexTime() tomlLexStateFn {
- // v--- cursor
- // 07:32:00
- // 00:32:00.999999
-
- for i := 0; i < 2; i++ {
- r := l.next()
- if !isDigit(r) {
- return l.errorf("invalid minute digit in time: %c", r)
- }
- }
-
- r := l.next()
- if r != ':' {
- return l.errorf("time minute/second separator should be :, not %c", r)
- }
-
- for i := 0; i < 2; i++ {
- r := l.next()
- if !isDigit(r) {
- return l.errorf("invalid second digit in time: %c", r)
- }
- }
-
- r = l.peek()
- if r == '.' {
- l.next()
- r := l.next()
- if !isDigit(r) {
- return l.errorf("expected at least one digit in time's fraction, not %c", r)
- }
-
- for {
- r := l.peek()
- if !isDigit(r) {
- break
- }
- l.next()
- }
- }
-
- l.emit(tokenLocalTime)
- return l.lexRvalue
-
-}
-
-func (l *tomlLexer) lexTrue() tomlLexStateFn {
- l.fastForward(4)
- l.emit(tokenTrue)
- return l.lexRvalue
-}
-
-func (l *tomlLexer) lexFalse() tomlLexStateFn {
- l.fastForward(5)
- l.emit(tokenFalse)
- return l.lexRvalue
-}
-
-func (l *tomlLexer) lexInf() tomlLexStateFn {
- l.fastForward(3)
- l.emit(tokenInf)
- return l.lexRvalue
-}
-
-func (l *tomlLexer) lexNan() tomlLexStateFn {
- l.fastForward(3)
- l.emit(tokenNan)
- return l.lexRvalue
-}
-
-func (l *tomlLexer) lexEqual() tomlLexStateFn {
- l.next()
- l.emit(tokenEqual)
- return l.lexRvalue
-}
-
-func (l *tomlLexer) lexComma() tomlLexStateFn {
- l.next()
- l.emit(tokenComma)
- if len(l.brackets) > 0 && l.brackets[len(l.brackets)-1] == '{' {
- return l.lexVoid
- }
- return l.lexRvalue
-}
-
-// Parse the key and emits its value without escape sequences.
-// bare keys, basic string keys and literal string keys are supported.
-func (l *tomlLexer) lexKey() tomlLexStateFn {
- var sb strings.Builder
-
- for r := l.peek(); isKeyChar(r) || r == '\n' || r == '\r'; r = l.peek() {
- if r == '"' {
- l.next()
- str, err := l.lexStringAsString(`"`, false, true)
- if err != nil {
- return l.errorf(err.Error())
- }
- sb.WriteString("\"")
- sb.WriteString(str)
- sb.WriteString("\"")
- l.next()
- continue
- } else if r == '\'' {
- l.next()
- str, err := l.lexLiteralStringAsString(`'`, false)
- if err != nil {
- return l.errorf(err.Error())
- }
- sb.WriteString("'")
- sb.WriteString(str)
- sb.WriteString("'")
- l.next()
- continue
- } else if r == '\n' {
- return l.errorf("keys cannot contain new lines")
- } else if isSpace(r) {
- var str strings.Builder
- str.WriteString(" ")
-
- // skip trailing whitespace
- l.next()
- for r = l.peek(); isSpace(r); r = l.peek() {
- str.WriteRune(r)
- l.next()
- }
- // break loop if not a dot
- if r != '.' {
- break
- }
- str.WriteString(".")
- // skip trailing whitespace after dot
- l.next()
- for r = l.peek(); isSpace(r); r = l.peek() {
- str.WriteRune(r)
- l.next()
- }
- sb.WriteString(str.String())
- continue
- } else if r == '.' {
- // skip
- } else if !isValidBareChar(r) {
- return l.errorf("keys cannot contain %c character", r)
- }
- sb.WriteRune(r)
- l.next()
- }
- l.emitWithValue(tokenKey, sb.String())
- return l.lexVoid
-}
-
-func (l *tomlLexer) lexComment(previousState tomlLexStateFn) tomlLexStateFn {
- return func() tomlLexStateFn {
- for next := l.peek(); next != '\n' && next != eof; next = l.peek() {
- if next == '\r' && l.follow("\r\n") {
- break
- }
- l.next()
- }
- l.ignore()
- return previousState
- }
-}
-
-func (l *tomlLexer) lexLeftBracket() tomlLexStateFn {
- l.next()
- l.emit(tokenLeftBracket)
- l.brackets = append(l.brackets, '[')
- return l.lexRvalue
-}
-
-func (l *tomlLexer) lexLiteralStringAsString(terminator string, discardLeadingNewLine bool) (string, error) {
- var sb strings.Builder
-
- if discardLeadingNewLine {
- if l.follow("\r\n") {
- l.skip()
- l.skip()
- } else if l.peek() == '\n' {
- l.skip()
- }
- }
-
- // find end of string
- for {
- if l.follow(terminator) {
- return sb.String(), nil
- }
-
- next := l.peek()
- if next == eof {
- break
- }
- sb.WriteRune(l.next())
- }
-
- return "", errors.New("unclosed string")
-}
-
-func (l *tomlLexer) lexLiteralString() tomlLexStateFn {
- l.skip()
-
- // handle special case for triple-quote
- terminator := "'"
- discardLeadingNewLine := false
- if l.follow("''") {
- l.skip()
- l.skip()
- terminator = "'''"
- discardLeadingNewLine = true
- }
-
- str, err := l.lexLiteralStringAsString(terminator, discardLeadingNewLine)
- if err != nil {
- return l.errorf(err.Error())
- }
-
- l.emitWithValue(tokenString, str)
- l.fastForward(len(terminator))
- l.ignore()
- return l.lexRvalue
-}
-
-// Lex a string and return the results as a string.
-// Terminator is the substring indicating the end of the token.
-// The resulting string does not include the terminator.
-func (l *tomlLexer) lexStringAsString(terminator string, discardLeadingNewLine, acceptNewLines bool) (string, error) {
- var sb strings.Builder
-
- if discardLeadingNewLine {
- if l.follow("\r\n") {
- l.skip()
- l.skip()
- } else if l.peek() == '\n' {
- l.skip()
- }
- }
-
- for {
- if l.follow(terminator) {
- return sb.String(), nil
- }
-
- if l.follow("\\") {
- l.next()
- switch l.peek() {
- case '\r':
- fallthrough
- case '\n':
- fallthrough
- case '\t':
- fallthrough
- case ' ':
- // skip all whitespace chars following backslash
- for strings.ContainsRune("\r\n\t ", l.peek()) {
- l.next()
- }
- case '"':
- sb.WriteString("\"")
- l.next()
- case 'n':
- sb.WriteString("\n")
- l.next()
- case 'b':
- sb.WriteString("\b")
- l.next()
- case 'f':
- sb.WriteString("\f")
- l.next()
- case '/':
- sb.WriteString("/")
- l.next()
- case 't':
- sb.WriteString("\t")
- l.next()
- case 'r':
- sb.WriteString("\r")
- l.next()
- case '\\':
- sb.WriteString("\\")
- l.next()
- case 'u':
- l.next()
- var code strings.Builder
- for i := 0; i < 4; i++ {
- c := l.peek()
- if !isHexDigit(c) {
- return "", errors.New("unfinished unicode escape")
- }
- l.next()
- code.WriteRune(c)
- }
- intcode, err := strconv.ParseInt(code.String(), 16, 32)
- if err != nil {
- return "", errors.New("invalid unicode escape: \\u" + code.String())
- }
- sb.WriteRune(rune(intcode))
- case 'U':
- l.next()
- var code strings.Builder
- for i := 0; i < 8; i++ {
- c := l.peek()
- if !isHexDigit(c) {
- return "", errors.New("unfinished unicode escape")
- }
- l.next()
- code.WriteRune(c)
- }
- intcode, err := strconv.ParseInt(code.String(), 16, 64)
- if err != nil {
- return "", errors.New("invalid unicode escape: \\U" + code.String())
- }
- sb.WriteRune(rune(intcode))
- default:
- return "", errors.New("invalid escape sequence: \\" + string(l.peek()))
- }
- } else {
- r := l.peek()
-
- if 0x00 <= r && r <= 0x1F && r != '\t' && !(acceptNewLines && (r == '\n' || r == '\r')) {
- return "", fmt.Errorf("unescaped control character %U", r)
- }
- l.next()
- sb.WriteRune(r)
- }
-
- if l.peek() == eof {
- break
- }
- }
-
- return "", errors.New("unclosed string")
-}
-
-func (l *tomlLexer) lexString() tomlLexStateFn {
- l.skip()
-
- // handle special case for triple-quote
- terminator := `"`
- discardLeadingNewLine := false
- acceptNewLines := false
- if l.follow(`""`) {
- l.skip()
- l.skip()
- terminator = `"""`
- discardLeadingNewLine = true
- acceptNewLines = true
- }
-
- str, err := l.lexStringAsString(terminator, discardLeadingNewLine, acceptNewLines)
- if err != nil {
- return l.errorf(err.Error())
- }
-
- l.emitWithValue(tokenString, str)
- l.fastForward(len(terminator))
- l.ignore()
- return l.lexRvalue
-}
-
-func (l *tomlLexer) lexTableKey() tomlLexStateFn {
- l.next()
-
- if l.peek() == '[' {
- // token '[[' signifies an array of tables
- l.next()
- l.emit(tokenDoubleLeftBracket)
- return l.lexInsideTableArrayKey
- }
- // vanilla table key
- l.emit(tokenLeftBracket)
- return l.lexInsideTableKey
-}
-
-// Parse the key till "]]", but only bare keys are supported
-func (l *tomlLexer) lexInsideTableArrayKey() tomlLexStateFn {
- for r := l.peek(); r != eof; r = l.peek() {
- switch r {
- case ']':
- if l.currentTokenStop > l.currentTokenStart {
- l.emit(tokenKeyGroupArray)
- }
- l.next()
- if l.peek() != ']' {
- break
- }
- l.next()
- l.emit(tokenDoubleRightBracket)
- return l.lexVoid
- case '[':
- return l.errorf("table array key cannot contain ']'")
- default:
- l.next()
- }
- }
- return l.errorf("unclosed table array key")
-}
-
-// Parse the key till "]" but only bare keys are supported
-func (l *tomlLexer) lexInsideTableKey() tomlLexStateFn {
- for r := l.peek(); r != eof; r = l.peek() {
- switch r {
- case ']':
- if l.currentTokenStop > l.currentTokenStart {
- l.emit(tokenKeyGroup)
- }
- l.next()
- l.emit(tokenRightBracket)
- return l.lexVoid
- case '[':
- return l.errorf("table key cannot contain ']'")
- default:
- l.next()
- }
- }
- return l.errorf("unclosed table key")
-}
-
-func (l *tomlLexer) lexRightBracket() tomlLexStateFn {
- l.next()
- l.emit(tokenRightBracket)
- if len(l.brackets) == 0 || l.brackets[len(l.brackets)-1] != '[' {
- return l.errorf("cannot have ']' here")
- }
- l.brackets = l.brackets[:len(l.brackets)-1]
- return l.lexRvalue
-}
-
-type validRuneFn func(r rune) bool
-
-func isValidHexRune(r rune) bool {
- return r >= 'a' && r <= 'f' ||
- r >= 'A' && r <= 'F' ||
- r >= '0' && r <= '9' ||
- r == '_'
-}
-
-func isValidOctalRune(r rune) bool {
- return r >= '0' && r <= '7' || r == '_'
-}
-
-func isValidBinaryRune(r rune) bool {
- return r == '0' || r == '1' || r == '_'
-}
-
-func (l *tomlLexer) lexNumber() tomlLexStateFn {
- r := l.peek()
-
- if r == '0' {
- follow := l.peekString(2)
- if len(follow) == 2 {
- var isValidRune validRuneFn
- switch follow[1] {
- case 'x':
- isValidRune = isValidHexRune
- case 'o':
- isValidRune = isValidOctalRune
- case 'b':
- isValidRune = isValidBinaryRune
- default:
- if follow[1] >= 'a' && follow[1] <= 'z' || follow[1] >= 'A' && follow[1] <= 'Z' {
- return l.errorf("unknown number base: %s. possible options are x (hex) o (octal) b (binary)", string(follow[1]))
- }
- }
-
- if isValidRune != nil {
- l.next()
- l.next()
- digitSeen := false
- for {
- next := l.peek()
- if !isValidRune(next) {
- break
- }
- digitSeen = true
- l.next()
- }
-
- if !digitSeen {
- return l.errorf("number needs at least one digit")
- }
-
- l.emit(tokenInteger)
-
- return l.lexRvalue
- }
- }
- }
-
- if r == '+' || r == '-' {
- l.next()
- if l.follow("inf") {
- return l.lexInf
- }
- if l.follow("nan") {
- return l.lexNan
- }
- }
-
- pointSeen := false
- expSeen := false
- digitSeen := false
- for {
- next := l.peek()
- if next == '.' {
- if pointSeen {
- return l.errorf("cannot have two dots in one float")
- }
- l.next()
- if !isDigit(l.peek()) {
- return l.errorf("float cannot end with a dot")
- }
- pointSeen = true
- } else if next == 'e' || next == 'E' {
- expSeen = true
- l.next()
- r := l.peek()
- if r == '+' || r == '-' {
- l.next()
- }
- } else if isDigit(next) {
- digitSeen = true
- l.next()
- } else if next == '_' {
- l.next()
- } else {
- break
- }
- if pointSeen && !digitSeen {
- return l.errorf("cannot start float with a dot")
- }
- }
-
- if !digitSeen {
- return l.errorf("no digit in that number")
- }
- if pointSeen || expSeen {
- l.emit(tokenFloat)
- } else {
- l.emit(tokenInteger)
- }
- return l.lexRvalue
-}
-
-func (l *tomlLexer) run() {
- for state := l.lexVoid; state != nil; {
- state = state()
- }
-}
-
-// Entry point
-func lexToml(inputBytes []byte) []token {
- runes := bytes.Runes(inputBytes)
- l := &tomlLexer{
- input: runes,
- tokens: make([]token, 0, 256),
- line: 1,
- col: 1,
- endbufferLine: 1,
- endbufferCol: 1,
- }
- l.run()
- return l.tokens
-}
diff --git a/vendor/github.com/pelletier/go-toml/localtime.go b/vendor/github.com/pelletier/go-toml/localtime.go
deleted file mode 100644
index 9dfe4b9e6..000000000
--- a/vendor/github.com/pelletier/go-toml/localtime.go
+++ /dev/null
@@ -1,287 +0,0 @@
-// Implementation of TOML's local date/time.
-//
-// Copied over from Google's civil to avoid pulling all the Google dependencies.
-// Originals:
-// https://raw.githubusercontent.com/googleapis/google-cloud-go/ed46f5086358513cf8c25f8e3f022cb838a49d66/civil/civil.go
-// Changes:
-// * Renamed files from civil* to localtime*.
-// * Package changed from civil to toml.
-// * 'Local' prefix added to all structs.
-//
-// Copyright 2016 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// Package civil implements types for civil time, a time-zone-independent
-// representation of time that follows the rules of the proleptic
-// Gregorian calendar with exactly 24-hour days, 60-minute hours, and 60-second
-// minutes.
-//
-// Because they lack location information, these types do not represent unique
-// moments or intervals of time. Use time.Time for that purpose.
-package toml
-
-import (
- "fmt"
- "time"
-)
-
-// A LocalDate represents a date (year, month, day).
-//
-// This type does not include location information, and therefore does not
-// describe a unique 24-hour timespan.
-type LocalDate struct {
- Year int // Year (e.g., 2014).
- Month time.Month // Month of the year (January = 1, ...).
- Day int // Day of the month, starting at 1.
-}
-
-// LocalDateOf returns the LocalDate in which a time occurs in that time's location.
-func LocalDateOf(t time.Time) LocalDate {
- var d LocalDate
- d.Year, d.Month, d.Day = t.Date()
- return d
-}
-
-// ParseLocalDate parses a string in RFC3339 full-date format and returns the date value it represents.
-func ParseLocalDate(s string) (LocalDate, error) {
- t, err := time.Parse("2006-01-02", s)
- if err != nil {
- return LocalDate{}, err
- }
- return LocalDateOf(t), nil
-}
-
-// String returns the date in RFC3339 full-date format.
-func (d LocalDate) String() string {
- return fmt.Sprintf("%04d-%02d-%02d", d.Year, d.Month, d.Day)
-}
-
-// IsValid reports whether the date is valid.
-func (d LocalDate) IsValid() bool {
- return LocalDateOf(d.In(time.UTC)) == d
-}
-
-// In returns the time corresponding to time 00:00:00 of the date in the location.
-//
-// In is always consistent with time.LocalDate, even when time.LocalDate returns a time
-// on a different day. For example, if loc is America/Indiana/Vincennes, then both
-// time.LocalDate(1955, time.May, 1, 0, 0, 0, 0, loc)
-// and
-// civil.LocalDate{Year: 1955, Month: time.May, Day: 1}.In(loc)
-// return 23:00:00 on April 30, 1955.
-//
-// In panics if loc is nil.
-func (d LocalDate) In(loc *time.Location) time.Time {
- return time.Date(d.Year, d.Month, d.Day, 0, 0, 0, 0, loc)
-}
-
-// AddDays returns the date that is n days in the future.
-// n can also be negative to go into the past.
-func (d LocalDate) AddDays(n int) LocalDate {
- return LocalDateOf(d.In(time.UTC).AddDate(0, 0, n))
-}
-
-// DaysSince returns the signed number of days between the date and s, not including the end day.
-// This is the inverse operation to AddDays.
-func (d LocalDate) DaysSince(s LocalDate) (days int) {
- // We convert to Unix time so we do not have to worry about leap seconds:
- // Unix time increases by exactly 86400 seconds per day.
- deltaUnix := d.In(time.UTC).Unix() - s.In(time.UTC).Unix()
- return int(deltaUnix / 86400)
-}
-
-// Before reports whether d1 occurs before d2.
-func (d1 LocalDate) Before(d2 LocalDate) bool {
- if d1.Year != d2.Year {
- return d1.Year < d2.Year
- }
- if d1.Month != d2.Month {
- return d1.Month < d2.Month
- }
- return d1.Day < d2.Day
-}
-
-// After reports whether d1 occurs after d2.
-func (d1 LocalDate) After(d2 LocalDate) bool {
- return d2.Before(d1)
-}
-
-// MarshalText implements the encoding.TextMarshaler interface.
-// The output is the result of d.String().
-func (d LocalDate) MarshalText() ([]byte, error) {
- return []byte(d.String()), nil
-}
-
-// UnmarshalText implements the encoding.TextUnmarshaler interface.
-// The date is expected to be a string in a format accepted by ParseLocalDate.
-func (d *LocalDate) UnmarshalText(data []byte) error {
- var err error
- *d, err = ParseLocalDate(string(data))
- return err
-}
-
-// A LocalTime represents a time with nanosecond precision.
-//
-// This type does not include location information, and therefore does not
-// describe a unique moment in time.
-//
-// This type exists to represent the TIME type in storage-based APIs like BigQuery.
-// Most operations on Times are unlikely to be meaningful. Prefer the LocalDateTime type.
-type LocalTime struct {
- Hour int // The hour of the day in 24-hour format; range [0-23]
- Minute int // The minute of the hour; range [0-59]
- Second int // The second of the minute; range [0-59]
- Nanosecond int // The nanosecond of the second; range [0-999999999]
-}
-
-// LocalTimeOf returns the LocalTime representing the time of day in which a time occurs
-// in that time's location. It ignores the date.
-func LocalTimeOf(t time.Time) LocalTime {
- var tm LocalTime
- tm.Hour, tm.Minute, tm.Second = t.Clock()
- tm.Nanosecond = t.Nanosecond()
- return tm
-}
-
-// ParseLocalTime parses a string and returns the time value it represents.
-// ParseLocalTime accepts an extended form of the RFC3339 partial-time format. After
-// the HH:MM:SS part of the string, an optional fractional part may appear,
-// consisting of a decimal point followed by one to nine decimal digits.
-// (RFC3339 admits only one digit after the decimal point).
-func ParseLocalTime(s string) (LocalTime, error) {
- t, err := time.Parse("15:04:05.999999999", s)
- if err != nil {
- return LocalTime{}, err
- }
- return LocalTimeOf(t), nil
-}
-
-// String returns the date in the format described in ParseLocalTime. If Nanoseconds
-// is zero, no fractional part will be generated. Otherwise, the result will
-// end with a fractional part consisting of a decimal point and nine digits.
-func (t LocalTime) String() string {
- s := fmt.Sprintf("%02d:%02d:%02d", t.Hour, t.Minute, t.Second)
- if t.Nanosecond == 0 {
- return s
- }
- return s + fmt.Sprintf(".%09d", t.Nanosecond)
-}
-
-// IsValid reports whether the time is valid.
-func (t LocalTime) IsValid() bool {
- // Construct a non-zero time.
- tm := time.Date(2, 2, 2, t.Hour, t.Minute, t.Second, t.Nanosecond, time.UTC)
- return LocalTimeOf(tm) == t
-}
-
-// MarshalText implements the encoding.TextMarshaler interface.
-// The output is the result of t.String().
-func (t LocalTime) MarshalText() ([]byte, error) {
- return []byte(t.String()), nil
-}
-
-// UnmarshalText implements the encoding.TextUnmarshaler interface.
-// The time is expected to be a string in a format accepted by ParseLocalTime.
-func (t *LocalTime) UnmarshalText(data []byte) error {
- var err error
- *t, err = ParseLocalTime(string(data))
- return err
-}
-
-// A LocalDateTime represents a date and time.
-//
-// This type does not include location information, and therefore does not
-// describe a unique moment in time.
-type LocalDateTime struct {
- Date LocalDate
- Time LocalTime
-}
-
-// Note: We deliberately do not embed LocalDate into LocalDateTime, to avoid promoting AddDays and Sub.
-
-// LocalDateTimeOf returns the LocalDateTime in which a time occurs in that time's location.
-func LocalDateTimeOf(t time.Time) LocalDateTime {
- return LocalDateTime{
- Date: LocalDateOf(t),
- Time: LocalTimeOf(t),
- }
-}
-
-// ParseLocalDateTime parses a string and returns the LocalDateTime it represents.
-// ParseLocalDateTime accepts a variant of the RFC3339 date-time format that omits
-// the time offset but includes an optional fractional time, as described in
-// ParseLocalTime. Informally, the accepted format is
-// YYYY-MM-DDTHH:MM:SS[.FFFFFFFFF]
-// where the 'T' may be a lower-case 't'.
-func ParseLocalDateTime(s string) (LocalDateTime, error) {
- t, err := time.Parse("2006-01-02T15:04:05.999999999", s)
- if err != nil {
- t, err = time.Parse("2006-01-02t15:04:05.999999999", s)
- if err != nil {
- return LocalDateTime{}, err
- }
- }
- return LocalDateTimeOf(t), nil
-}
-
-// String returns the date in the format described in ParseLocalDate.
-func (dt LocalDateTime) String() string {
- return dt.Date.String() + "T" + dt.Time.String()
-}
-
-// IsValid reports whether the datetime is valid.
-func (dt LocalDateTime) IsValid() bool {
- return dt.Date.IsValid() && dt.Time.IsValid()
-}
-
-// In returns the time corresponding to the LocalDateTime in the given location.
-//
-// If the time is missing or ambigous at the location, In returns the same
-// result as time.LocalDate. For example, if loc is America/Indiana/Vincennes, then
-// both
-// time.LocalDate(1955, time.May, 1, 0, 30, 0, 0, loc)
-// and
-// civil.LocalDateTime{
-// civil.LocalDate{Year: 1955, Month: time.May, Day: 1}},
-// civil.LocalTime{Minute: 30}}.In(loc)
-// return 23:30:00 on April 30, 1955.
-//
-// In panics if loc is nil.
-func (dt LocalDateTime) In(loc *time.Location) time.Time {
- return time.Date(dt.Date.Year, dt.Date.Month, dt.Date.Day, dt.Time.Hour, dt.Time.Minute, dt.Time.Second, dt.Time.Nanosecond, loc)
-}
-
-// Before reports whether dt1 occurs before dt2.
-func (dt1 LocalDateTime) Before(dt2 LocalDateTime) bool {
- return dt1.In(time.UTC).Before(dt2.In(time.UTC))
-}
-
-// After reports whether dt1 occurs after dt2.
-func (dt1 LocalDateTime) After(dt2 LocalDateTime) bool {
- return dt2.Before(dt1)
-}
-
-// MarshalText implements the encoding.TextMarshaler interface.
-// The output is the result of dt.String().
-func (dt LocalDateTime) MarshalText() ([]byte, error) {
- return []byte(dt.String()), nil
-}
-
-// UnmarshalText implements the encoding.TextUnmarshaler interface.
-// The datetime is expected to be a string in a format accepted by ParseLocalDateTime
-func (dt *LocalDateTime) UnmarshalText(data []byte) error {
- var err error
- *dt, err = ParseLocalDateTime(string(data))
- return err
-}
diff --git a/vendor/github.com/pelletier/go-toml/marshal.go b/vendor/github.com/pelletier/go-toml/marshal.go
deleted file mode 100644
index 3443c3545..000000000
--- a/vendor/github.com/pelletier/go-toml/marshal.go
+++ /dev/null
@@ -1,1308 +0,0 @@
-package toml
-
-import (
- "bytes"
- "encoding"
- "errors"
- "fmt"
- "io"
- "reflect"
- "sort"
- "strconv"
- "strings"
- "time"
-)
-
-const (
- tagFieldName = "toml"
- tagFieldComment = "comment"
- tagCommented = "commented"
- tagMultiline = "multiline"
- tagLiteral = "literal"
- tagDefault = "default"
-)
-
-type tomlOpts struct {
- name string
- nameFromTag bool
- comment string
- commented bool
- multiline bool
- literal bool
- include bool
- omitempty bool
- defaultValue string
-}
-
-type encOpts struct {
- quoteMapKeys bool
- arraysOneElementPerLine bool
-}
-
-var encOptsDefaults = encOpts{
- quoteMapKeys: false,
-}
-
-type annotation struct {
- tag string
- comment string
- commented string
- multiline string
- literal string
- defaultValue string
-}
-
-var annotationDefault = annotation{
- tag: tagFieldName,
- comment: tagFieldComment,
- commented: tagCommented,
- multiline: tagMultiline,
- literal: tagLiteral,
- defaultValue: tagDefault,
-}
-
-type MarshalOrder int
-
-// Orders the Encoder can write the fields to the output stream.
-const (
- // Sort fields alphabetically.
- OrderAlphabetical MarshalOrder = iota + 1
- // Preserve the order the fields are encountered. For example, the order of fields in
- // a struct.
- OrderPreserve
-)
-
-var timeType = reflect.TypeOf(time.Time{})
-var marshalerType = reflect.TypeOf(new(Marshaler)).Elem()
-var unmarshalerType = reflect.TypeOf(new(Unmarshaler)).Elem()
-var textMarshalerType = reflect.TypeOf(new(encoding.TextMarshaler)).Elem()
-var textUnmarshalerType = reflect.TypeOf(new(encoding.TextUnmarshaler)).Elem()
-var localDateType = reflect.TypeOf(LocalDate{})
-var localTimeType = reflect.TypeOf(LocalTime{})
-var localDateTimeType = reflect.TypeOf(LocalDateTime{})
-var mapStringInterfaceType = reflect.TypeOf(map[string]interface{}{})
-
-// Check if the given marshal type maps to a Tree primitive
-func isPrimitive(mtype reflect.Type) bool {
- switch mtype.Kind() {
- case reflect.Ptr:
- return isPrimitive(mtype.Elem())
- case reflect.Bool:
- return true
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- return true
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
- return true
- case reflect.Float32, reflect.Float64:
- return true
- case reflect.String:
- return true
- case reflect.Struct:
- return isTimeType(mtype)
- default:
- return false
- }
-}
-
-func isTimeType(mtype reflect.Type) bool {
- return mtype == timeType || mtype == localDateType || mtype == localDateTimeType || mtype == localTimeType
-}
-
-// Check if the given marshal type maps to a Tree slice or array
-func isTreeSequence(mtype reflect.Type) bool {
- switch mtype.Kind() {
- case reflect.Ptr:
- return isTreeSequence(mtype.Elem())
- case reflect.Slice, reflect.Array:
- return isTree(mtype.Elem())
- default:
- return false
- }
-}
-
-// Check if the given marshal type maps to a slice or array of a custom marshaler type
-func isCustomMarshalerSequence(mtype reflect.Type) bool {
- switch mtype.Kind() {
- case reflect.Ptr:
- return isCustomMarshalerSequence(mtype.Elem())
- case reflect.Slice, reflect.Array:
- return isCustomMarshaler(mtype.Elem()) || isCustomMarshaler(reflect.New(mtype.Elem()).Type())
- default:
- return false
- }
-}
-
-// Check if the given marshal type maps to a slice or array of a text marshaler type
-func isTextMarshalerSequence(mtype reflect.Type) bool {
- switch mtype.Kind() {
- case reflect.Ptr:
- return isTextMarshalerSequence(mtype.Elem())
- case reflect.Slice, reflect.Array:
- return isTextMarshaler(mtype.Elem()) || isTextMarshaler(reflect.New(mtype.Elem()).Type())
- default:
- return false
- }
-}
-
-// Check if the given marshal type maps to a non-Tree slice or array
-func isOtherSequence(mtype reflect.Type) bool {
- switch mtype.Kind() {
- case reflect.Ptr:
- return isOtherSequence(mtype.Elem())
- case reflect.Slice, reflect.Array:
- return !isTreeSequence(mtype)
- default:
- return false
- }
-}
-
-// Check if the given marshal type maps to a Tree
-func isTree(mtype reflect.Type) bool {
- switch mtype.Kind() {
- case reflect.Ptr:
- return isTree(mtype.Elem())
- case reflect.Map:
- return true
- case reflect.Struct:
- return !isPrimitive(mtype)
- default:
- return false
- }
-}
-
-func isCustomMarshaler(mtype reflect.Type) bool {
- return mtype.Implements(marshalerType)
-}
-
-func callCustomMarshaler(mval reflect.Value) ([]byte, error) {
- return mval.Interface().(Marshaler).MarshalTOML()
-}
-
-func isTextMarshaler(mtype reflect.Type) bool {
- return mtype.Implements(textMarshalerType) && !isTimeType(mtype)
-}
-
-func callTextMarshaler(mval reflect.Value) ([]byte, error) {
- return mval.Interface().(encoding.TextMarshaler).MarshalText()
-}
-
-func isCustomUnmarshaler(mtype reflect.Type) bool {
- return mtype.Implements(unmarshalerType)
-}
-
-func callCustomUnmarshaler(mval reflect.Value, tval interface{}) error {
- return mval.Interface().(Unmarshaler).UnmarshalTOML(tval)
-}
-
-func isTextUnmarshaler(mtype reflect.Type) bool {
- return mtype.Implements(textUnmarshalerType)
-}
-
-func callTextUnmarshaler(mval reflect.Value, text []byte) error {
- return mval.Interface().(encoding.TextUnmarshaler).UnmarshalText(text)
-}
-
-// Marshaler is the interface implemented by types that
-// can marshal themselves into valid TOML.
-type Marshaler interface {
- MarshalTOML() ([]byte, error)
-}
-
-// Unmarshaler is the interface implemented by types that
-// can unmarshal a TOML description of themselves.
-type Unmarshaler interface {
- UnmarshalTOML(interface{}) error
-}
-
-/*
-Marshal returns the TOML encoding of v. Behavior is similar to the Go json
-encoder, except that there is no concept of a Marshaler interface or MarshalTOML
-function for sub-structs, and currently only definite types can be marshaled
-(i.e. no `interface{}`).
-
-The following struct annotations are supported:
-
- toml:"Field" Overrides the field's name to output.
- omitempty When set, empty values and groups are not emitted.
- comment:"comment" Emits a # comment on the same line. This supports new lines.
- commented:"true" Emits the value as commented.
-
-Note that pointers are automatically assigned the "omitempty" option, as TOML
-explicitly does not handle null values (saying instead the label should be
-dropped).
-
-Tree structural types and corresponding marshal types:
-
- *Tree (*)struct, (*)map[string]interface{}
- []*Tree (*)[](*)struct, (*)[](*)map[string]interface{}
- []interface{} (as interface{}) (*)[]primitive, (*)[]([]interface{})
- interface{} (*)primitive
-
-Tree primitive types and corresponding marshal types:
-
- uint64 uint, uint8-uint64, pointers to same
- int64 int, int8-uint64, pointers to same
- float64 float32, float64, pointers to same
- string string, pointers to same
- bool bool, pointers to same
- time.LocalTime time.LocalTime{}, pointers to same
-
-For additional flexibility, use the Encoder API.
-*/
-func Marshal(v interface{}) ([]byte, error) {
- return NewEncoder(nil).marshal(v)
-}
-
-// Encoder writes TOML values to an output stream.
-type Encoder struct {
- w io.Writer
- encOpts
- annotation
- line int
- col int
- order MarshalOrder
- promoteAnon bool
- compactComments bool
- indentation string
-}
-
-// NewEncoder returns a new encoder that writes to w.
-func NewEncoder(w io.Writer) *Encoder {
- return &Encoder{
- w: w,
- encOpts: encOptsDefaults,
- annotation: annotationDefault,
- line: 0,
- col: 1,
- order: OrderAlphabetical,
- indentation: " ",
- }
-}
-
-// Encode writes the TOML encoding of v to the stream.
-//
-// See the documentation for Marshal for details.
-func (e *Encoder) Encode(v interface{}) error {
- b, err := e.marshal(v)
- if err != nil {
- return err
- }
- if _, err := e.w.Write(b); err != nil {
- return err
- }
- return nil
-}
-
-// QuoteMapKeys sets up the encoder to encode
-// maps with string type keys with quoted TOML keys.
-//
-// This relieves the character limitations on map keys.
-func (e *Encoder) QuoteMapKeys(v bool) *Encoder {
- e.quoteMapKeys = v
- return e
-}
-
-// ArraysWithOneElementPerLine sets up the encoder to encode arrays
-// with more than one element on multiple lines instead of one.
-//
-// For example:
-//
-// A = [1,2,3]
-//
-// Becomes
-//
-// A = [
-// 1,
-// 2,
-// 3,
-// ]
-func (e *Encoder) ArraysWithOneElementPerLine(v bool) *Encoder {
- e.arraysOneElementPerLine = v
- return e
-}
-
-// Order allows to change in which order fields will be written to the output stream.
-func (e *Encoder) Order(ord MarshalOrder) *Encoder {
- e.order = ord
- return e
-}
-
-// Indentation allows to change indentation when marshalling.
-func (e *Encoder) Indentation(indent string) *Encoder {
- e.indentation = indent
- return e
-}
-
-// SetTagName allows changing default tag "toml"
-func (e *Encoder) SetTagName(v string) *Encoder {
- e.tag = v
- return e
-}
-
-// SetTagComment allows changing default tag "comment"
-func (e *Encoder) SetTagComment(v string) *Encoder {
- e.comment = v
- return e
-}
-
-// SetTagCommented allows changing default tag "commented"
-func (e *Encoder) SetTagCommented(v string) *Encoder {
- e.commented = v
- return e
-}
-
-// SetTagMultiline allows changing default tag "multiline"
-func (e *Encoder) SetTagMultiline(v string) *Encoder {
- e.multiline = v
- return e
-}
-
-// PromoteAnonymous allows to change how anonymous struct fields are marshaled.
-// Usually, they are marshaled as if the inner exported fields were fields in
-// the outer struct. However, if an anonymous struct field is given a name in
-// its TOML tag, it is treated like a regular struct field with that name.
-// rather than being anonymous.
-//
-// In case anonymous promotion is enabled, all anonymous structs are promoted
-// and treated like regular struct fields.
-func (e *Encoder) PromoteAnonymous(promote bool) *Encoder {
- e.promoteAnon = promote
- return e
-}
-
-// CompactComments removes the new line before each comment in the tree.
-func (e *Encoder) CompactComments(cc bool) *Encoder {
- e.compactComments = cc
- return e
-}
-
-func (e *Encoder) marshal(v interface{}) ([]byte, error) {
- // Check if indentation is valid
- for _, char := range e.indentation {
- if !isSpace(char) {
- return []byte{}, fmt.Errorf("invalid indentation: must only contains space or tab characters")
- }
- }
-
- mtype := reflect.TypeOf(v)
- if mtype == nil {
- return []byte{}, errors.New("nil cannot be marshaled to TOML")
- }
-
- switch mtype.Kind() {
- case reflect.Struct, reflect.Map:
- case reflect.Ptr:
- if mtype.Elem().Kind() != reflect.Struct {
- return []byte{}, errors.New("Only pointer to struct can be marshaled to TOML")
- }
- if reflect.ValueOf(v).IsNil() {
- return []byte{}, errors.New("nil pointer cannot be marshaled to TOML")
- }
- default:
- return []byte{}, errors.New("Only a struct or map can be marshaled to TOML")
- }
-
- sval := reflect.ValueOf(v)
- if isCustomMarshaler(mtype) {
- return callCustomMarshaler(sval)
- }
- if isTextMarshaler(mtype) {
- return callTextMarshaler(sval)
- }
- t, err := e.valueToTree(mtype, sval)
- if err != nil {
- return []byte{}, err
- }
-
- var buf bytes.Buffer
- _, err = t.writeToOrdered(&buf, "", "", 0, e.arraysOneElementPerLine, e.order, e.indentation, e.compactComments, false)
-
- return buf.Bytes(), err
-}
-
-// Create next tree with a position based on Encoder.line
-func (e *Encoder) nextTree() *Tree {
- return newTreeWithPosition(Position{Line: e.line, Col: 1})
-}
-
-// Convert given marshal struct or map value to toml tree
-func (e *Encoder) valueToTree(mtype reflect.Type, mval reflect.Value) (*Tree, error) {
- if mtype.Kind() == reflect.Ptr {
- return e.valueToTree(mtype.Elem(), mval.Elem())
- }
- tval := e.nextTree()
- switch mtype.Kind() {
- case reflect.Struct:
- switch mval.Interface().(type) {
- case Tree:
- reflect.ValueOf(tval).Elem().Set(mval)
- default:
- for i := 0; i < mtype.NumField(); i++ {
- mtypef, mvalf := mtype.Field(i), mval.Field(i)
- opts := tomlOptions(mtypef, e.annotation)
- if opts.include && ((mtypef.Type.Kind() != reflect.Interface && !opts.omitempty) || !isZero(mvalf)) {
- val, err := e.valueToToml(mtypef.Type, mvalf)
- if err != nil {
- return nil, err
- }
- if tree, ok := val.(*Tree); ok && mtypef.Anonymous && !opts.nameFromTag && !e.promoteAnon {
- e.appendTree(tval, tree)
- } else {
- val = e.wrapTomlValue(val, tval)
- tval.SetPathWithOptions([]string{opts.name}, SetOptions{
- Comment: opts.comment,
- Commented: opts.commented,
- Multiline: opts.multiline,
- Literal: opts.literal,
- }, val)
- }
- }
- }
- }
- case reflect.Map:
- keys := mval.MapKeys()
- if e.order == OrderPreserve && len(keys) > 0 {
- // Sorting []reflect.Value is not straight forward.
- //
- // OrderPreserve will support deterministic results when string is used
- // as the key to maps.
- typ := keys[0].Type()
- kind := keys[0].Kind()
- if kind == reflect.String {
- ikeys := make([]string, len(keys))
- for i := range keys {
- ikeys[i] = keys[i].Interface().(string)
- }
- sort.Strings(ikeys)
- for i := range ikeys {
- keys[i] = reflect.ValueOf(ikeys[i]).Convert(typ)
- }
- }
- }
- for _, key := range keys {
- mvalf := mval.MapIndex(key)
- if (mtype.Elem().Kind() == reflect.Ptr || mtype.Elem().Kind() == reflect.Interface) && mvalf.IsNil() {
- continue
- }
- val, err := e.valueToToml(mtype.Elem(), mvalf)
- if err != nil {
- return nil, err
- }
- val = e.wrapTomlValue(val, tval)
- if e.quoteMapKeys {
- keyStr, err := tomlValueStringRepresentation(key.String(), "", "", e.order, e.arraysOneElementPerLine)
- if err != nil {
- return nil, err
- }
- tval.SetPath([]string{keyStr}, val)
- } else {
- tval.SetPath([]string{key.String()}, val)
- }
- }
- }
- return tval, nil
-}
-
-// Convert given marshal slice to slice of Toml trees
-func (e *Encoder) valueToTreeSlice(mtype reflect.Type, mval reflect.Value) ([]*Tree, error) {
- tval := make([]*Tree, mval.Len(), mval.Len())
- for i := 0; i < mval.Len(); i++ {
- val, err := e.valueToTree(mtype.Elem(), mval.Index(i))
- if err != nil {
- return nil, err
- }
- tval[i] = val
- }
- return tval, nil
-}
-
-// Convert given marshal slice to slice of toml values
-func (e *Encoder) valueToOtherSlice(mtype reflect.Type, mval reflect.Value) (interface{}, error) {
- tval := make([]interface{}, mval.Len(), mval.Len())
- for i := 0; i < mval.Len(); i++ {
- val, err := e.valueToToml(mtype.Elem(), mval.Index(i))
- if err != nil {
- return nil, err
- }
- tval[i] = val
- }
- return tval, nil
-}
-
-// Convert given marshal value to toml value
-func (e *Encoder) valueToToml(mtype reflect.Type, mval reflect.Value) (interface{}, error) {
- if mtype.Kind() == reflect.Ptr {
- switch {
- case isCustomMarshaler(mtype):
- return callCustomMarshaler(mval)
- case isTextMarshaler(mtype):
- b, err := callTextMarshaler(mval)
- return string(b), err
- default:
- return e.valueToToml(mtype.Elem(), mval.Elem())
- }
- }
- if mtype.Kind() == reflect.Interface {
- return e.valueToToml(mval.Elem().Type(), mval.Elem())
- }
- switch {
- case isCustomMarshaler(mtype):
- return callCustomMarshaler(mval)
- case isTextMarshaler(mtype):
- b, err := callTextMarshaler(mval)
- return string(b), err
- case isTree(mtype):
- return e.valueToTree(mtype, mval)
- case isOtherSequence(mtype), isCustomMarshalerSequence(mtype), isTextMarshalerSequence(mtype):
- return e.valueToOtherSlice(mtype, mval)
- case isTreeSequence(mtype):
- return e.valueToTreeSlice(mtype, mval)
- default:
- switch mtype.Kind() {
- case reflect.Bool:
- return mval.Bool(), nil
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- if mtype.Kind() == reflect.Int64 && mtype == reflect.TypeOf(time.Duration(1)) {
- return fmt.Sprint(mval), nil
- }
- return mval.Int(), nil
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
- return mval.Uint(), nil
- case reflect.Float32, reflect.Float64:
- return mval.Float(), nil
- case reflect.String:
- return mval.String(), nil
- case reflect.Struct:
- return mval.Interface(), nil
- default:
- return nil, fmt.Errorf("Marshal can't handle %v(%v)", mtype, mtype.Kind())
- }
- }
-}
-
-func (e *Encoder) appendTree(t, o *Tree) error {
- for key, value := range o.values {
- if _, ok := t.values[key]; ok {
- continue
- }
- if tomlValue, ok := value.(*tomlValue); ok {
- tomlValue.position.Col = t.position.Col
- }
- t.values[key] = value
- }
- return nil
-}
-
-// Create a toml value with the current line number as the position line
-func (e *Encoder) wrapTomlValue(val interface{}, parent *Tree) interface{} {
- _, isTree := val.(*Tree)
- _, isTreeS := val.([]*Tree)
- if isTree || isTreeS {
- e.line++
- return val
- }
-
- ret := &tomlValue{
- value: val,
- position: Position{
- e.line,
- parent.position.Col,
- },
- }
- e.line++
- return ret
-}
-
-// Unmarshal attempts to unmarshal the Tree into a Go struct pointed by v.
-// Neither Unmarshaler interfaces nor UnmarshalTOML functions are supported for
-// sub-structs, and only definite types can be unmarshaled.
-func (t *Tree) Unmarshal(v interface{}) error {
- d := Decoder{tval: t, tagName: tagFieldName}
- return d.unmarshal(v)
-}
-
-// Marshal returns the TOML encoding of Tree.
-// See Marshal() documentation for types mapping table.
-func (t *Tree) Marshal() ([]byte, error) {
- var buf bytes.Buffer
- _, err := t.WriteTo(&buf)
- if err != nil {
- return nil, err
- }
- return buf.Bytes(), nil
-}
-
-// Unmarshal parses the TOML-encoded data and stores the result in the value
-// pointed to by v. Behavior is similar to the Go json encoder, except that there
-// is no concept of an Unmarshaler interface or UnmarshalTOML function for
-// sub-structs, and currently only definite types can be unmarshaled to (i.e. no
-// `interface{}`).
-//
-// The following struct annotations are supported:
-//
-// toml:"Field" Overrides the field's name to map to.
-// default:"foo" Provides a default value.
-//
-// For default values, only fields of the following types are supported:
-// * string
-// * bool
-// * int
-// * int64
-// * float64
-//
-// See Marshal() documentation for types mapping table.
-func Unmarshal(data []byte, v interface{}) error {
- t, err := LoadReader(bytes.NewReader(data))
- if err != nil {
- return err
- }
- return t.Unmarshal(v)
-}
-
-// Decoder reads and decodes TOML values from an input stream.
-type Decoder struct {
- r io.Reader
- tval *Tree
- encOpts
- tagName string
- strict bool
- visitor visitorState
-}
-
-// NewDecoder returns a new decoder that reads from r.
-func NewDecoder(r io.Reader) *Decoder {
- return &Decoder{
- r: r,
- encOpts: encOptsDefaults,
- tagName: tagFieldName,
- }
-}
-
-// Decode reads a TOML-encoded value from it's input
-// and unmarshals it in the value pointed at by v.
-//
-// See the documentation for Marshal for details.
-func (d *Decoder) Decode(v interface{}) error {
- var err error
- d.tval, err = LoadReader(d.r)
- if err != nil {
- return err
- }
- return d.unmarshal(v)
-}
-
-// SetTagName allows changing default tag "toml"
-func (d *Decoder) SetTagName(v string) *Decoder {
- d.tagName = v
- return d
-}
-
-// Strict allows changing to strict decoding. Any fields that are found in the
-// input data and do not have a corresponding struct member cause an error.
-func (d *Decoder) Strict(strict bool) *Decoder {
- d.strict = strict
- return d
-}
-
-func (d *Decoder) unmarshal(v interface{}) error {
- mtype := reflect.TypeOf(v)
- if mtype == nil {
- return errors.New("nil cannot be unmarshaled from TOML")
- }
- if mtype.Kind() != reflect.Ptr {
- return errors.New("only a pointer to struct or map can be unmarshaled from TOML")
- }
-
- elem := mtype.Elem()
-
- switch elem.Kind() {
- case reflect.Struct, reflect.Map:
- case reflect.Interface:
- elem = mapStringInterfaceType
- default:
- return errors.New("only a pointer to struct or map can be unmarshaled from TOML")
- }
-
- if reflect.ValueOf(v).IsNil() {
- return errors.New("nil pointer cannot be unmarshaled from TOML")
- }
-
- vv := reflect.ValueOf(v).Elem()
-
- if d.strict {
- d.visitor = newVisitorState(d.tval)
- }
-
- sval, err := d.valueFromTree(elem, d.tval, &vv)
- if err != nil {
- return err
- }
- if err := d.visitor.validate(); err != nil {
- return err
- }
- reflect.ValueOf(v).Elem().Set(sval)
- return nil
-}
-
-// Convert toml tree to marshal struct or map, using marshal type. When mval1
-// is non-nil, merge fields into the given value instead of allocating a new one.
-func (d *Decoder) valueFromTree(mtype reflect.Type, tval *Tree, mval1 *reflect.Value) (reflect.Value, error) {
- if mtype.Kind() == reflect.Ptr {
- return d.unwrapPointer(mtype, tval, mval1)
- }
-
- // Check if pointer to value implements the Unmarshaler interface.
- if mvalPtr := reflect.New(mtype); isCustomUnmarshaler(mvalPtr.Type()) {
- d.visitor.visitAll()
-
- if tval == nil {
- return mvalPtr.Elem(), nil
- }
-
- if err := callCustomUnmarshaler(mvalPtr, tval.ToMap()); err != nil {
- return reflect.ValueOf(nil), fmt.Errorf("unmarshal toml: %v", err)
- }
- return mvalPtr.Elem(), nil
- }
-
- var mval reflect.Value
- switch mtype.Kind() {
- case reflect.Struct:
- if mval1 != nil {
- mval = *mval1
- } else {
- mval = reflect.New(mtype).Elem()
- }
-
- switch mval.Interface().(type) {
- case Tree:
- mval.Set(reflect.ValueOf(tval).Elem())
- default:
- for i := 0; i < mtype.NumField(); i++ {
- mtypef := mtype.Field(i)
- an := annotation{tag: d.tagName}
- opts := tomlOptions(mtypef, an)
- if !opts.include {
- continue
- }
- baseKey := opts.name
- keysToTry := []string{
- baseKey,
- strings.ToLower(baseKey),
- strings.ToTitle(baseKey),
- strings.ToLower(string(baseKey[0])) + baseKey[1:],
- }
-
- found := false
- if tval != nil {
- for _, key := range keysToTry {
- exists := tval.HasPath([]string{key})
- if !exists {
- continue
- }
-
- d.visitor.push(key)
- val := tval.GetPath([]string{key})
- fval := mval.Field(i)
- mvalf, err := d.valueFromToml(mtypef.Type, val, &fval)
- if err != nil {
- return mval, formatError(err, tval.GetPositionPath([]string{key}))
- }
- mval.Field(i).Set(mvalf)
- found = true
- d.visitor.pop()
- break
- }
- }
-
- if !found && opts.defaultValue != "" {
- mvalf := mval.Field(i)
- var val interface{}
- var err error
- switch mvalf.Kind() {
- case reflect.String:
- val = opts.defaultValue
- case reflect.Bool:
- val, err = strconv.ParseBool(opts.defaultValue)
- case reflect.Uint:
- val, err = strconv.ParseUint(opts.defaultValue, 10, 0)
- case reflect.Uint8:
- val, err = strconv.ParseUint(opts.defaultValue, 10, 8)
- case reflect.Uint16:
- val, err = strconv.ParseUint(opts.defaultValue, 10, 16)
- case reflect.Uint32:
- val, err = strconv.ParseUint(opts.defaultValue, 10, 32)
- case reflect.Uint64:
- val, err = strconv.ParseUint(opts.defaultValue, 10, 64)
- case reflect.Int:
- val, err = strconv.ParseInt(opts.defaultValue, 10, 0)
- case reflect.Int8:
- val, err = strconv.ParseInt(opts.defaultValue, 10, 8)
- case reflect.Int16:
- val, err = strconv.ParseInt(opts.defaultValue, 10, 16)
- case reflect.Int32:
- val, err = strconv.ParseInt(opts.defaultValue, 10, 32)
- case reflect.Int64:
- // Check if the provided number has a non-numeric extension.
- var hasExtension bool
- if len(opts.defaultValue) > 0 {
- lastChar := opts.defaultValue[len(opts.defaultValue)-1]
- if lastChar < '0' || lastChar > '9' {
- hasExtension = true
- }
- }
- // If the value is a time.Duration with extension, parse as duration.
- // If the value is an int64 or a time.Duration without extension, parse as number.
- if hasExtension && mvalf.Type().String() == "time.Duration" {
- val, err = time.ParseDuration(opts.defaultValue)
- } else {
- val, err = strconv.ParseInt(opts.defaultValue, 10, 64)
- }
- case reflect.Float32:
- val, err = strconv.ParseFloat(opts.defaultValue, 32)
- case reflect.Float64:
- val, err = strconv.ParseFloat(opts.defaultValue, 64)
- default:
- return mvalf, fmt.Errorf("unsupported field type for default option")
- }
-
- if err != nil {
- return mvalf, err
- }
- mvalf.Set(reflect.ValueOf(val).Convert(mvalf.Type()))
- }
-
- // save the old behavior above and try to check structs
- if !found && opts.defaultValue == "" && mtypef.Type.Kind() == reflect.Struct {
- tmpTval := tval
- if !mtypef.Anonymous {
- tmpTval = nil
- }
- fval := mval.Field(i)
- v, err := d.valueFromTree(mtypef.Type, tmpTval, &fval)
- if err != nil {
- return v, err
- }
- mval.Field(i).Set(v)
- }
- }
- }
- case reflect.Map:
- mval = reflect.MakeMap(mtype)
- for _, key := range tval.Keys() {
- d.visitor.push(key)
- // TODO: path splits key
- val := tval.GetPath([]string{key})
- mvalf, err := d.valueFromToml(mtype.Elem(), val, nil)
- if err != nil {
- return mval, formatError(err, tval.GetPositionPath([]string{key}))
- }
- mval.SetMapIndex(reflect.ValueOf(key).Convert(mtype.Key()), mvalf)
- d.visitor.pop()
- }
- }
- return mval, nil
-}
-
-// Convert toml value to marshal struct/map slice, using marshal type
-func (d *Decoder) valueFromTreeSlice(mtype reflect.Type, tval []*Tree) (reflect.Value, error) {
- mval, err := makeSliceOrArray(mtype, len(tval))
- if err != nil {
- return mval, err
- }
-
- for i := 0; i < len(tval); i++ {
- d.visitor.push(strconv.Itoa(i))
- val, err := d.valueFromTree(mtype.Elem(), tval[i], nil)
- if err != nil {
- return mval, err
- }
- mval.Index(i).Set(val)
- d.visitor.pop()
- }
- return mval, nil
-}
-
-// Convert toml value to marshal primitive slice, using marshal type
-func (d *Decoder) valueFromOtherSlice(mtype reflect.Type, tval []interface{}) (reflect.Value, error) {
- mval, err := makeSliceOrArray(mtype, len(tval))
- if err != nil {
- return mval, err
- }
-
- for i := 0; i < len(tval); i++ {
- val, err := d.valueFromToml(mtype.Elem(), tval[i], nil)
- if err != nil {
- return mval, err
- }
- mval.Index(i).Set(val)
- }
- return mval, nil
-}
-
-// Convert toml value to marshal primitive slice, using marshal type
-func (d *Decoder) valueFromOtherSliceI(mtype reflect.Type, tval interface{}) (reflect.Value, error) {
- val := reflect.ValueOf(tval)
- length := val.Len()
-
- mval, err := makeSliceOrArray(mtype, length)
- if err != nil {
- return mval, err
- }
-
- for i := 0; i < length; i++ {
- val, err := d.valueFromToml(mtype.Elem(), val.Index(i).Interface(), nil)
- if err != nil {
- return mval, err
- }
- mval.Index(i).Set(val)
- }
- return mval, nil
-}
-
-// Create a new slice or a new array with specified length
-func makeSliceOrArray(mtype reflect.Type, tLength int) (reflect.Value, error) {
- var mval reflect.Value
- switch mtype.Kind() {
- case reflect.Slice:
- mval = reflect.MakeSlice(mtype, tLength, tLength)
- case reflect.Array:
- mval = reflect.New(reflect.ArrayOf(mtype.Len(), mtype.Elem())).Elem()
- if tLength > mtype.Len() {
- return mval, fmt.Errorf("unmarshal: TOML array length (%v) exceeds destination array length (%v)", tLength, mtype.Len())
- }
- }
- return mval, nil
-}
-
-// Convert toml value to marshal value, using marshal type. When mval1 is non-nil
-// and the given type is a struct value, merge fields into it.
-func (d *Decoder) valueFromToml(mtype reflect.Type, tval interface{}, mval1 *reflect.Value) (reflect.Value, error) {
- if mtype.Kind() == reflect.Ptr {
- return d.unwrapPointer(mtype, tval, mval1)
- }
-
- switch t := tval.(type) {
- case *Tree:
- var mval11 *reflect.Value
- if mtype.Kind() == reflect.Struct {
- mval11 = mval1
- }
-
- if isTree(mtype) {
- return d.valueFromTree(mtype, t, mval11)
- }
-
- if mtype.Kind() == reflect.Interface {
- if mval1 == nil || mval1.IsNil() {
- return d.valueFromTree(reflect.TypeOf(map[string]interface{}{}), t, nil)
- } else {
- return d.valueFromToml(mval1.Elem().Type(), t, nil)
- }
- }
-
- return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to a tree", tval, tval)
- case []*Tree:
- if isTreeSequence(mtype) {
- return d.valueFromTreeSlice(mtype, t)
- }
- if mtype.Kind() == reflect.Interface {
- if mval1 == nil || mval1.IsNil() {
- return d.valueFromTreeSlice(reflect.TypeOf([]map[string]interface{}{}), t)
- } else {
- ival := mval1.Elem()
- return d.valueFromToml(mval1.Elem().Type(), t, &ival)
- }
- }
- return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to trees", tval, tval)
- case []interface{}:
- d.visitor.visit()
- if isOtherSequence(mtype) {
- return d.valueFromOtherSlice(mtype, t)
- }
- if mtype.Kind() == reflect.Interface {
- if mval1 == nil || mval1.IsNil() {
- return d.valueFromOtherSlice(reflect.TypeOf([]interface{}{}), t)
- } else {
- ival := mval1.Elem()
- return d.valueFromToml(mval1.Elem().Type(), t, &ival)
- }
- }
- return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to a slice", tval, tval)
- default:
- d.visitor.visit()
- mvalPtr := reflect.New(mtype)
-
- // Check if pointer to value implements the Unmarshaler interface.
- if isCustomUnmarshaler(mvalPtr.Type()) {
- if err := callCustomUnmarshaler(mvalPtr, tval); err != nil {
- return reflect.ValueOf(nil), fmt.Errorf("unmarshal toml: %v", err)
- }
- return mvalPtr.Elem(), nil
- }
-
- // Check if pointer to value implements the encoding.TextUnmarshaler.
- if isTextUnmarshaler(mvalPtr.Type()) && !isTimeType(mtype) {
- if err := d.unmarshalText(tval, mvalPtr); err != nil {
- return reflect.ValueOf(nil), fmt.Errorf("unmarshal text: %v", err)
- }
- return mvalPtr.Elem(), nil
- }
-
- switch mtype.Kind() {
- case reflect.Bool, reflect.Struct:
- val := reflect.ValueOf(tval)
-
- switch val.Type() {
- case localDateType:
- localDate := val.Interface().(LocalDate)
- switch mtype {
- case timeType:
- return reflect.ValueOf(time.Date(localDate.Year, localDate.Month, localDate.Day, 0, 0, 0, 0, time.Local)), nil
- }
- case localDateTimeType:
- localDateTime := val.Interface().(LocalDateTime)
- switch mtype {
- case timeType:
- return reflect.ValueOf(time.Date(
- localDateTime.Date.Year,
- localDateTime.Date.Month,
- localDateTime.Date.Day,
- localDateTime.Time.Hour,
- localDateTime.Time.Minute,
- localDateTime.Time.Second,
- localDateTime.Time.Nanosecond,
- time.Local)), nil
- }
- }
-
- // if this passes for when mtype is reflect.Struct, tval is a time.LocalTime
- if !val.Type().ConvertibleTo(mtype) {
- return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v", tval, tval, mtype.String())
- }
-
- return val.Convert(mtype), nil
- case reflect.String:
- val := reflect.ValueOf(tval)
- // stupidly, int64 is convertible to string. So special case this.
- if !val.Type().ConvertibleTo(mtype) || val.Kind() == reflect.Int64 {
- return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v", tval, tval, mtype.String())
- }
-
- return val.Convert(mtype), nil
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- val := reflect.ValueOf(tval)
- if mtype.Kind() == reflect.Int64 && mtype == reflect.TypeOf(time.Duration(1)) && val.Kind() == reflect.String {
- d, err := time.ParseDuration(val.String())
- if err != nil {
- return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v. %s", tval, tval, mtype.String(), err)
- }
- return reflect.ValueOf(d), nil
- }
- if !val.Type().ConvertibleTo(mtype) || val.Kind() == reflect.Float64 {
- return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v", tval, tval, mtype.String())
- }
- if reflect.Indirect(reflect.New(mtype)).OverflowInt(val.Convert(reflect.TypeOf(int64(0))).Int()) {
- return reflect.ValueOf(nil), fmt.Errorf("%v(%T) would overflow %v", tval, tval, mtype.String())
- }
-
- return val.Convert(mtype), nil
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
- val := reflect.ValueOf(tval)
- if !val.Type().ConvertibleTo(mtype) || val.Kind() == reflect.Float64 {
- return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v", tval, tval, mtype.String())
- }
-
- if val.Convert(reflect.TypeOf(int(1))).Int() < 0 {
- return reflect.ValueOf(nil), fmt.Errorf("%v(%T) is negative so does not fit in %v", tval, tval, mtype.String())
- }
- if reflect.Indirect(reflect.New(mtype)).OverflowUint(val.Convert(reflect.TypeOf(uint64(0))).Uint()) {
- return reflect.ValueOf(nil), fmt.Errorf("%v(%T) would overflow %v", tval, tval, mtype.String())
- }
-
- return val.Convert(mtype), nil
- case reflect.Float32, reflect.Float64:
- val := reflect.ValueOf(tval)
- if !val.Type().ConvertibleTo(mtype) || val.Kind() == reflect.Int64 {
- return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v", tval, tval, mtype.String())
- }
- if reflect.Indirect(reflect.New(mtype)).OverflowFloat(val.Convert(reflect.TypeOf(float64(0))).Float()) {
- return reflect.ValueOf(nil), fmt.Errorf("%v(%T) would overflow %v", tval, tval, mtype.String())
- }
-
- return val.Convert(mtype), nil
- case reflect.Interface:
- if mval1 == nil || mval1.IsNil() {
- return reflect.ValueOf(tval), nil
- } else {
- ival := mval1.Elem()
- return d.valueFromToml(mval1.Elem().Type(), t, &ival)
- }
- case reflect.Slice, reflect.Array:
- if isOtherSequence(mtype) && isOtherSequence(reflect.TypeOf(t)) {
- return d.valueFromOtherSliceI(mtype, t)
- }
- return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v(%v)", tval, tval, mtype, mtype.Kind())
- default:
- return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v(%v)", tval, tval, mtype, mtype.Kind())
- }
- }
-}
-
-func (d *Decoder) unwrapPointer(mtype reflect.Type, tval interface{}, mval1 *reflect.Value) (reflect.Value, error) {
- var melem *reflect.Value
-
- if mval1 != nil && !mval1.IsNil() && (mtype.Elem().Kind() == reflect.Struct || mtype.Elem().Kind() == reflect.Interface) {
- elem := mval1.Elem()
- melem = &elem
- }
-
- val, err := d.valueFromToml(mtype.Elem(), tval, melem)
- if err != nil {
- return reflect.ValueOf(nil), err
- }
- mval := reflect.New(mtype.Elem())
- mval.Elem().Set(val)
- return mval, nil
-}
-
-func (d *Decoder) unmarshalText(tval interface{}, mval reflect.Value) error {
- var buf bytes.Buffer
- fmt.Fprint(&buf, tval)
- return callTextUnmarshaler(mval, buf.Bytes())
-}
-
-func tomlOptions(vf reflect.StructField, an annotation) tomlOpts {
- tag := vf.Tag.Get(an.tag)
- parse := strings.Split(tag, ",")
- var comment string
- if c := vf.Tag.Get(an.comment); c != "" {
- comment = c
- }
- commented, _ := strconv.ParseBool(vf.Tag.Get(an.commented))
- multiline, _ := strconv.ParseBool(vf.Tag.Get(an.multiline))
- literal, _ := strconv.ParseBool(vf.Tag.Get(an.literal))
- defaultValue := vf.Tag.Get(tagDefault)
- result := tomlOpts{
- name: vf.Name,
- nameFromTag: false,
- comment: comment,
- commented: commented,
- multiline: multiline,
- literal: literal,
- include: true,
- omitempty: false,
- defaultValue: defaultValue,
- }
- if parse[0] != "" {
- if parse[0] == "-" && len(parse) == 1 {
- result.include = false
- } else {
- result.name = strings.Trim(parse[0], " ")
- result.nameFromTag = true
- }
- }
- if vf.PkgPath != "" {
- result.include = false
- }
- if len(parse) > 1 && strings.Trim(parse[1], " ") == "omitempty" {
- result.omitempty = true
- }
- if vf.Type.Kind() == reflect.Ptr {
- result.omitempty = true
- }
- return result
-}
-
-func isZero(val reflect.Value) bool {
- switch val.Type().Kind() {
- case reflect.Slice, reflect.Array, reflect.Map:
- return val.Len() == 0
- default:
- return reflect.DeepEqual(val.Interface(), reflect.Zero(val.Type()).Interface())
- }
-}
-
-func formatError(err error, pos Position) error {
- if err.Error()[0] == '(' { // Error already contains position information
- return err
- }
- return fmt.Errorf("%s: %s", pos, err)
-}
-
-// visitorState keeps track of which keys were unmarshaled.
-type visitorState struct {
- tree *Tree
- path []string
- keys map[string]struct{}
- active bool
-}
-
-func newVisitorState(tree *Tree) visitorState {
- path, result := []string{}, map[string]struct{}{}
- insertKeys(path, result, tree)
- return visitorState{
- tree: tree,
- path: path[:0],
- keys: result,
- active: true,
- }
-}
-
-func (s *visitorState) push(key string) {
- if s.active {
- s.path = append(s.path, key)
- }
-}
-
-func (s *visitorState) pop() {
- if s.active {
- s.path = s.path[:len(s.path)-1]
- }
-}
-
-func (s *visitorState) visit() {
- if s.active {
- delete(s.keys, strings.Join(s.path, "."))
- }
-}
-
-func (s *visitorState) visitAll() {
- if s.active {
- for k := range s.keys {
- if strings.HasPrefix(k, strings.Join(s.path, ".")) {
- delete(s.keys, k)
- }
- }
- }
-}
-
-func (s *visitorState) validate() error {
- if !s.active {
- return nil
- }
- undecoded := make([]string, 0, len(s.keys))
- for key := range s.keys {
- undecoded = append(undecoded, key)
- }
- sort.Strings(undecoded)
- if len(undecoded) > 0 {
- return fmt.Errorf("undecoded keys: %q", undecoded)
- }
- return nil
-}
-
-func insertKeys(path []string, m map[string]struct{}, tree *Tree) {
- for k, v := range tree.values {
- switch node := v.(type) {
- case []*Tree:
- for i, item := range node {
- insertKeys(append(path, k, strconv.Itoa(i)), m, item)
- }
- case *Tree:
- insertKeys(append(path, k), m, node)
- case *tomlValue:
- m[strings.Join(append(path, k), ".")] = struct{}{}
- }
- }
-}
diff --git a/vendor/github.com/pelletier/go-toml/marshal_OrderPreserve_test.toml b/vendor/github.com/pelletier/go-toml/marshal_OrderPreserve_test.toml
deleted file mode 100644
index 792b72ed7..000000000
--- a/vendor/github.com/pelletier/go-toml/marshal_OrderPreserve_test.toml
+++ /dev/null
@@ -1,39 +0,0 @@
-title = "TOML Marshal Testing"
-
-[basic_lists]
- floats = [12.3,45.6,78.9]
- bools = [true,false,true]
- dates = [1979-05-27T07:32:00Z,1980-05-27T07:32:00Z]
- ints = [8001,8001,8002]
- uints = [5002,5003]
- strings = ["One","Two","Three"]
-
-[[subdocptrs]]
- name = "Second"
-
-[basic_map]
- one = "one"
- two = "two"
-
-[subdoc]
-
- [subdoc.second]
- name = "Second"
-
- [subdoc.first]
- name = "First"
-
-[basic]
- uint = 5001
- bool = true
- float = 123.4
- float64 = 123.456782132399
- int = 5000
- string = "Bite me"
- date = 1979-05-27T07:32:00Z
-
-[[subdoclist]]
- name = "List.First"
-
-[[subdoclist]]
- name = "List.Second"
diff --git a/vendor/github.com/pelletier/go-toml/marshal_test.toml b/vendor/github.com/pelletier/go-toml/marshal_test.toml
deleted file mode 100644
index ba5e110bf..000000000
--- a/vendor/github.com/pelletier/go-toml/marshal_test.toml
+++ /dev/null
@@ -1,39 +0,0 @@
-title = "TOML Marshal Testing"
-
-[basic]
- bool = true
- date = 1979-05-27T07:32:00Z
- float = 123.4
- float64 = 123.456782132399
- int = 5000
- string = "Bite me"
- uint = 5001
-
-[basic_lists]
- bools = [true,false,true]
- dates = [1979-05-27T07:32:00Z,1980-05-27T07:32:00Z]
- floats = [12.3,45.6,78.9]
- ints = [8001,8001,8002]
- strings = ["One","Two","Three"]
- uints = [5002,5003]
-
-[basic_map]
- one = "one"
- two = "two"
-
-[subdoc]
-
- [subdoc.first]
- name = "First"
-
- [subdoc.second]
- name = "Second"
-
-[[subdoclist]]
- name = "List.First"
-
-[[subdoclist]]
- name = "List.Second"
-
-[[subdocptrs]]
- name = "Second"
diff --git a/vendor/github.com/pelletier/go-toml/parser.go b/vendor/github.com/pelletier/go-toml/parser.go
deleted file mode 100644
index f5e1a44fb..000000000
--- a/vendor/github.com/pelletier/go-toml/parser.go
+++ /dev/null
@@ -1,508 +0,0 @@
-// TOML Parser.
-
-package toml
-
-import (
- "errors"
- "fmt"
- "math"
- "reflect"
- "strconv"
- "strings"
- "time"
-)
-
-type tomlParser struct {
- flowIdx int
- flow []token
- tree *Tree
- currentTable []string
- seenTableKeys []string
-}
-
-type tomlParserStateFn func() tomlParserStateFn
-
-// Formats and panics an error message based on a token
-func (p *tomlParser) raiseError(tok *token, msg string, args ...interface{}) {
- panic(tok.Position.String() + ": " + fmt.Sprintf(msg, args...))
-}
-
-func (p *tomlParser) run() {
- for state := p.parseStart; state != nil; {
- state = state()
- }
-}
-
-func (p *tomlParser) peek() *token {
- if p.flowIdx >= len(p.flow) {
- return nil
- }
- return &p.flow[p.flowIdx]
-}
-
-func (p *tomlParser) assume(typ tokenType) {
- tok := p.getToken()
- if tok == nil {
- p.raiseError(tok, "was expecting token %s, but token stream is empty", tok)
- }
- if tok.typ != typ {
- p.raiseError(tok, "was expecting token %s, but got %s instead", typ, tok)
- }
-}
-
-func (p *tomlParser) getToken() *token {
- tok := p.peek()
- if tok == nil {
- return nil
- }
- p.flowIdx++
- return tok
-}
-
-func (p *tomlParser) parseStart() tomlParserStateFn {
- tok := p.peek()
-
- // end of stream, parsing is finished
- if tok == nil {
- return nil
- }
-
- switch tok.typ {
- case tokenDoubleLeftBracket:
- return p.parseGroupArray
- case tokenLeftBracket:
- return p.parseGroup
- case tokenKey:
- return p.parseAssign
- case tokenEOF:
- return nil
- case tokenError:
- p.raiseError(tok, "parsing error: %s", tok.String())
- default:
- p.raiseError(tok, "unexpected token %s", tok.typ)
- }
- return nil
-}
-
-func (p *tomlParser) parseGroupArray() tomlParserStateFn {
- startToken := p.getToken() // discard the [[
- key := p.getToken()
- if key.typ != tokenKeyGroupArray {
- p.raiseError(key, "unexpected token %s, was expecting a table array key", key)
- }
-
- // get or create table array element at the indicated part in the path
- keys, err := parseKey(key.val)
- if err != nil {
- p.raiseError(key, "invalid table array key: %s", err)
- }
- p.tree.createSubTree(keys[:len(keys)-1], startToken.Position) // create parent entries
- destTree := p.tree.GetPath(keys)
- var array []*Tree
- if destTree == nil {
- array = make([]*Tree, 0)
- } else if target, ok := destTree.([]*Tree); ok && target != nil {
- array = destTree.([]*Tree)
- } else {
- p.raiseError(key, "key %s is already assigned and not of type table array", key)
- }
- p.currentTable = keys
-
- // add a new tree to the end of the table array
- newTree := newTree()
- newTree.position = startToken.Position
- array = append(array, newTree)
- p.tree.SetPath(p.currentTable, array)
-
- // remove all keys that were children of this table array
- prefix := key.val + "."
- found := false
- for ii := 0; ii < len(p.seenTableKeys); {
- tableKey := p.seenTableKeys[ii]
- if strings.HasPrefix(tableKey, prefix) {
- p.seenTableKeys = append(p.seenTableKeys[:ii], p.seenTableKeys[ii+1:]...)
- } else {
- found = (tableKey == key.val)
- ii++
- }
- }
-
- // keep this key name from use by other kinds of assignments
- if !found {
- p.seenTableKeys = append(p.seenTableKeys, key.val)
- }
-
- // move to next parser state
- p.assume(tokenDoubleRightBracket)
- return p.parseStart
-}
-
-func (p *tomlParser) parseGroup() tomlParserStateFn {
- startToken := p.getToken() // discard the [
- key := p.getToken()
- if key.typ != tokenKeyGroup {
- p.raiseError(key, "unexpected token %s, was expecting a table key", key)
- }
- for _, item := range p.seenTableKeys {
- if item == key.val {
- p.raiseError(key, "duplicated tables")
- }
- }
-
- p.seenTableKeys = append(p.seenTableKeys, key.val)
- keys, err := parseKey(key.val)
- if err != nil {
- p.raiseError(key, "invalid table array key: %s", err)
- }
- if err := p.tree.createSubTree(keys, startToken.Position); err != nil {
- p.raiseError(key, "%s", err)
- }
- destTree := p.tree.GetPath(keys)
- if target, ok := destTree.(*Tree); ok && target != nil && target.inline {
- p.raiseError(key, "could not re-define exist inline table or its sub-table : %s",
- strings.Join(keys, "."))
- }
- p.assume(tokenRightBracket)
- p.currentTable = keys
- return p.parseStart
-}
-
-func (p *tomlParser) parseAssign() tomlParserStateFn {
- key := p.getToken()
- p.assume(tokenEqual)
-
- parsedKey, err := parseKey(key.val)
- if err != nil {
- p.raiseError(key, "invalid key: %s", err.Error())
- }
-
- value := p.parseRvalue()
- var tableKey []string
- if len(p.currentTable) > 0 {
- tableKey = p.currentTable
- } else {
- tableKey = []string{}
- }
-
- prefixKey := parsedKey[0 : len(parsedKey)-1]
- tableKey = append(tableKey, prefixKey...)
-
- // find the table to assign, looking out for arrays of tables
- var targetNode *Tree
- switch node := p.tree.GetPath(tableKey).(type) {
- case []*Tree:
- targetNode = node[len(node)-1]
- case *Tree:
- targetNode = node
- case nil:
- // create intermediate
- if err := p.tree.createSubTree(tableKey, key.Position); err != nil {
- p.raiseError(key, "could not create intermediate group: %s", err)
- }
- targetNode = p.tree.GetPath(tableKey).(*Tree)
- default:
- p.raiseError(key, "Unknown table type for path: %s",
- strings.Join(tableKey, "."))
- }
-
- if targetNode.inline {
- p.raiseError(key, "could not add key or sub-table to exist inline table or its sub-table : %s",
- strings.Join(tableKey, "."))
- }
-
- // assign value to the found table
- keyVal := parsedKey[len(parsedKey)-1]
- localKey := []string{keyVal}
- finalKey := append(tableKey, keyVal)
- if targetNode.GetPath(localKey) != nil {
- p.raiseError(key, "The following key was defined twice: %s",
- strings.Join(finalKey, "."))
- }
- var toInsert interface{}
-
- switch value.(type) {
- case *Tree, []*Tree:
- toInsert = value
- default:
- toInsert = &tomlValue{value: value, position: key.Position}
- }
- targetNode.values[keyVal] = toInsert
- return p.parseStart
-}
-
-var errInvalidUnderscore = errors.New("invalid use of _ in number")
-
-func numberContainsInvalidUnderscore(value string) error {
- // For large numbers, you may use underscores between digits to enhance
- // readability. Each underscore must be surrounded by at least one digit on
- // each side.
-
- hasBefore := false
- for idx, r := range value {
- if r == '_' {
- if !hasBefore || idx+1 >= len(value) {
- // can't end with an underscore
- return errInvalidUnderscore
- }
- }
- hasBefore = isDigit(r)
- }
- return nil
-}
-
-var errInvalidUnderscoreHex = errors.New("invalid use of _ in hex number")
-
-func hexNumberContainsInvalidUnderscore(value string) error {
- hasBefore := false
- for idx, r := range value {
- if r == '_' {
- if !hasBefore || idx+1 >= len(value) {
- // can't end with an underscore
- return errInvalidUnderscoreHex
- }
- }
- hasBefore = isHexDigit(r)
- }
- return nil
-}
-
-func cleanupNumberToken(value string) string {
- cleanedVal := strings.Replace(value, "_", "", -1)
- return cleanedVal
-}
-
-func (p *tomlParser) parseRvalue() interface{} {
- tok := p.getToken()
- if tok == nil || tok.typ == tokenEOF {
- p.raiseError(tok, "expecting a value")
- }
-
- switch tok.typ {
- case tokenString:
- return tok.val
- case tokenTrue:
- return true
- case tokenFalse:
- return false
- case tokenInf:
- if tok.val[0] == '-' {
- return math.Inf(-1)
- }
- return math.Inf(1)
- case tokenNan:
- return math.NaN()
- case tokenInteger:
- cleanedVal := cleanupNumberToken(tok.val)
- var err error
- var val int64
- if len(cleanedVal) >= 3 && cleanedVal[0] == '0' {
- switch cleanedVal[1] {
- case 'x':
- err = hexNumberContainsInvalidUnderscore(tok.val)
- if err != nil {
- p.raiseError(tok, "%s", err)
- }
- val, err = strconv.ParseInt(cleanedVal[2:], 16, 64)
- case 'o':
- err = numberContainsInvalidUnderscore(tok.val)
- if err != nil {
- p.raiseError(tok, "%s", err)
- }
- val, err = strconv.ParseInt(cleanedVal[2:], 8, 64)
- case 'b':
- err = numberContainsInvalidUnderscore(tok.val)
- if err != nil {
- p.raiseError(tok, "%s", err)
- }
- val, err = strconv.ParseInt(cleanedVal[2:], 2, 64)
- default:
- panic("invalid base") // the lexer should catch this first
- }
- } else {
- err = numberContainsInvalidUnderscore(tok.val)
- if err != nil {
- p.raiseError(tok, "%s", err)
- }
- val, err = strconv.ParseInt(cleanedVal, 10, 64)
- }
- if err != nil {
- p.raiseError(tok, "%s", err)
- }
- return val
- case tokenFloat:
- err := numberContainsInvalidUnderscore(tok.val)
- if err != nil {
- p.raiseError(tok, "%s", err)
- }
- cleanedVal := cleanupNumberToken(tok.val)
- val, err := strconv.ParseFloat(cleanedVal, 64)
- if err != nil {
- p.raiseError(tok, "%s", err)
- }
- return val
- case tokenLocalTime:
- val, err := ParseLocalTime(tok.val)
- if err != nil {
- p.raiseError(tok, "%s", err)
- }
- return val
- case tokenLocalDate:
- // a local date may be followed by:
- // * nothing: this is a local date
- // * a local time: this is a local date-time
-
- next := p.peek()
- if next == nil || next.typ != tokenLocalTime {
- val, err := ParseLocalDate(tok.val)
- if err != nil {
- p.raiseError(tok, "%s", err)
- }
- return val
- }
-
- localDate := tok
- localTime := p.getToken()
-
- next = p.peek()
- if next == nil || next.typ != tokenTimeOffset {
- v := localDate.val + "T" + localTime.val
- val, err := ParseLocalDateTime(v)
- if err != nil {
- p.raiseError(tok, "%s", err)
- }
- return val
- }
-
- offset := p.getToken()
-
- layout := time.RFC3339Nano
- v := localDate.val + "T" + localTime.val + offset.val
- val, err := time.ParseInLocation(layout, v, time.UTC)
- if err != nil {
- p.raiseError(tok, "%s", err)
- }
- return val
- case tokenLeftBracket:
- return p.parseArray()
- case tokenLeftCurlyBrace:
- return p.parseInlineTable()
- case tokenEqual:
- p.raiseError(tok, "cannot have multiple equals for the same key")
- case tokenError:
- p.raiseError(tok, "%s", tok)
- default:
- panic(fmt.Errorf("unhandled token: %v", tok))
- }
-
- return nil
-}
-
-func tokenIsComma(t *token) bool {
- return t != nil && t.typ == tokenComma
-}
-
-func (p *tomlParser) parseInlineTable() *Tree {
- tree := newTree()
- var previous *token
-Loop:
- for {
- follow := p.peek()
- if follow == nil || follow.typ == tokenEOF {
- p.raiseError(follow, "unterminated inline table")
- }
- switch follow.typ {
- case tokenRightCurlyBrace:
- p.getToken()
- break Loop
- case tokenKey, tokenInteger, tokenString:
- if !tokenIsComma(previous) && previous != nil {
- p.raiseError(follow, "comma expected between fields in inline table")
- }
- key := p.getToken()
- p.assume(tokenEqual)
-
- parsedKey, err := parseKey(key.val)
- if err != nil {
- p.raiseError(key, "invalid key: %s", err)
- }
-
- value := p.parseRvalue()
- tree.SetPath(parsedKey, value)
- case tokenComma:
- if tokenIsComma(previous) {
- p.raiseError(follow, "need field between two commas in inline table")
- }
- p.getToken()
- default:
- p.raiseError(follow, "unexpected token type in inline table: %s", follow.String())
- }
- previous = follow
- }
- if tokenIsComma(previous) {
- p.raiseError(previous, "trailing comma at the end of inline table")
- }
- tree.inline = true
- return tree
-}
-
-func (p *tomlParser) parseArray() interface{} {
- var array []interface{}
- arrayType := reflect.TypeOf(newTree())
- for {
- follow := p.peek()
- if follow == nil || follow.typ == tokenEOF {
- p.raiseError(follow, "unterminated array")
- }
- if follow.typ == tokenRightBracket {
- p.getToken()
- break
- }
- val := p.parseRvalue()
- if reflect.TypeOf(val) != arrayType {
- arrayType = nil
- }
- array = append(array, val)
- follow = p.peek()
- if follow == nil || follow.typ == tokenEOF {
- p.raiseError(follow, "unterminated array")
- }
- if follow.typ != tokenRightBracket && follow.typ != tokenComma {
- p.raiseError(follow, "missing comma")
- }
- if follow.typ == tokenComma {
- p.getToken()
- }
- }
-
- // if the array is a mixed-type array or its length is 0,
- // don't convert it to a table array
- if len(array) <= 0 {
- arrayType = nil
- }
- // An array of Trees is actually an array of inline
- // tables, which is a shorthand for a table array. If the
- // array was not converted from []interface{} to []*Tree,
- // the two notations would not be equivalent.
- if arrayType == reflect.TypeOf(newTree()) {
- tomlArray := make([]*Tree, len(array))
- for i, v := range array {
- tomlArray[i] = v.(*Tree)
- }
- return tomlArray
- }
- return array
-}
-
-func parseToml(flow []token) *Tree {
- result := newTree()
- result.position = Position{1, 1}
- parser := &tomlParser{
- flowIdx: 0,
- flow: flow,
- tree: result,
- currentTable: make([]string, 0),
- seenTableKeys: make([]string, 0),
- }
- parser.run()
- return result
-}
diff --git a/vendor/github.com/pelletier/go-toml/position.go b/vendor/github.com/pelletier/go-toml/position.go
deleted file mode 100644
index c17bff87b..000000000
--- a/vendor/github.com/pelletier/go-toml/position.go
+++ /dev/null
@@ -1,29 +0,0 @@
-// Position support for go-toml
-
-package toml
-
-import (
- "fmt"
-)
-
-// Position of a document element within a TOML document.
-//
-// Line and Col are both 1-indexed positions for the element's line number and
-// column number, respectively. Values of zero or less will cause Invalid(),
-// to return true.
-type Position struct {
- Line int // line within the document
- Col int // column within the line
-}
-
-// String representation of the position.
-// Displays 1-indexed line and column numbers.
-func (p Position) String() string {
- return fmt.Sprintf("(%d, %d)", p.Line, p.Col)
-}
-
-// Invalid returns whether or not the position is valid (i.e. with negative or
-// null values)
-func (p Position) Invalid() bool {
- return p.Line <= 0 || p.Col <= 0
-}
diff --git a/vendor/github.com/pelletier/go-toml/token.go b/vendor/github.com/pelletier/go-toml/token.go
deleted file mode 100644
index b437fdd3b..000000000
--- a/vendor/github.com/pelletier/go-toml/token.go
+++ /dev/null
@@ -1,136 +0,0 @@
-package toml
-
-import "fmt"
-
-// Define tokens
-type tokenType int
-
-const (
- eof = -(iota + 1)
-)
-
-const (
- tokenError tokenType = iota
- tokenEOF
- tokenComment
- tokenKey
- tokenString
- tokenInteger
- tokenTrue
- tokenFalse
- tokenFloat
- tokenInf
- tokenNan
- tokenEqual
- tokenLeftBracket
- tokenRightBracket
- tokenLeftCurlyBrace
- tokenRightCurlyBrace
- tokenLeftParen
- tokenRightParen
- tokenDoubleLeftBracket
- tokenDoubleRightBracket
- tokenLocalDate
- tokenLocalTime
- tokenTimeOffset
- tokenKeyGroup
- tokenKeyGroupArray
- tokenComma
- tokenColon
- tokenDollar
- tokenStar
- tokenQuestion
- tokenDot
- tokenDotDot
- tokenEOL
-)
-
-var tokenTypeNames = []string{
- "Error",
- "EOF",
- "Comment",
- "Key",
- "String",
- "Integer",
- "True",
- "False",
- "Float",
- "Inf",
- "NaN",
- "=",
- "[",
- "]",
- "{",
- "}",
- "(",
- ")",
- "]]",
- "[[",
- "LocalDate",
- "LocalTime",
- "TimeOffset",
- "KeyGroup",
- "KeyGroupArray",
- ",",
- ":",
- "$",
- "*",
- "?",
- ".",
- "..",
- "EOL",
-}
-
-type token struct {
- Position
- typ tokenType
- val string
-}
-
-func (tt tokenType) String() string {
- idx := int(tt)
- if idx < len(tokenTypeNames) {
- return tokenTypeNames[idx]
- }
- return "Unknown"
-}
-
-func (t token) String() string {
- switch t.typ {
- case tokenEOF:
- return "EOF"
- case tokenError:
- return t.val
- }
-
- return fmt.Sprintf("%q", t.val)
-}
-
-func isSpace(r rune) bool {
- return r == ' ' || r == '\t'
-}
-
-func isAlphanumeric(r rune) bool {
- return 'a' <= r && r <= 'z' || 'A' <= r && r <= 'Z' || r == '_'
-}
-
-func isKeyChar(r rune) bool {
- // Keys start with the first character that isn't whitespace or [ and end
- // with the last non-whitespace character before the equals sign. Keys
- // cannot contain a # character."
- return !(r == '\r' || r == '\n' || r == eof || r == '=')
-}
-
-func isKeyStartChar(r rune) bool {
- return !(isSpace(r) || r == '\r' || r == '\n' || r == eof || r == '[')
-}
-
-func isDigit(r rune) bool {
- return '0' <= r && r <= '9'
-}
-
-func isHexDigit(r rune) bool {
- return isDigit(r) ||
- (r >= 'a' && r <= 'f') ||
- (r >= 'A' && r <= 'F')
-}
diff --git a/vendor/github.com/pelletier/go-toml/toml.go b/vendor/github.com/pelletier/go-toml/toml.go
deleted file mode 100644
index 6d82587c4..000000000
--- a/vendor/github.com/pelletier/go-toml/toml.go
+++ /dev/null
@@ -1,533 +0,0 @@
-package toml
-
-import (
- "errors"
- "fmt"
- "io"
- "io/ioutil"
- "os"
- "runtime"
- "strings"
-)
-
-type tomlValue struct {
- value interface{} // string, int64, uint64, float64, bool, time.Time, [] of any of this list
- comment string
- commented bool
- multiline bool
- literal bool
- position Position
-}
-
-// Tree is the result of the parsing of a TOML file.
-type Tree struct {
- values map[string]interface{} // string -> *tomlValue, *Tree, []*Tree
- comment string
- commented bool
- inline bool
- position Position
-}
-
-func newTree() *Tree {
- return newTreeWithPosition(Position{})
-}
-
-func newTreeWithPosition(pos Position) *Tree {
- return &Tree{
- values: make(map[string]interface{}),
- position: pos,
- }
-}
-
-// TreeFromMap initializes a new Tree object using the given map.
-func TreeFromMap(m map[string]interface{}) (*Tree, error) {
- result, err := toTree(m)
- if err != nil {
- return nil, err
- }
- return result.(*Tree), nil
-}
-
-// Position returns the position of the tree.
-func (t *Tree) Position() Position {
- return t.position
-}
-
-// Has returns a boolean indicating if the given key exists.
-func (t *Tree) Has(key string) bool {
- if key == "" {
- return false
- }
- return t.HasPath(strings.Split(key, "."))
-}
-
-// HasPath returns true if the given path of keys exists, false otherwise.
-func (t *Tree) HasPath(keys []string) bool {
- return t.GetPath(keys) != nil
-}
-
-// Keys returns the keys of the toplevel tree (does not recurse).
-func (t *Tree) Keys() []string {
- keys := make([]string, len(t.values))
- i := 0
- for k := range t.values {
- keys[i] = k
- i++
- }
- return keys
-}
-
-// Get the value at key in the Tree.
-// Key is a dot-separated path (e.g. a.b.c) without single/double quoted strings.
-// If you need to retrieve non-bare keys, use GetPath.
-// Returns nil if the path does not exist in the tree.
-// If keys is of length zero, the current tree is returned.
-func (t *Tree) Get(key string) interface{} {
- if key == "" {
- return t
- }
- return t.GetPath(strings.Split(key, "."))
-}
-
-// GetPath returns the element in the tree indicated by 'keys'.
-// If keys is of length zero, the current tree is returned.
-func (t *Tree) GetPath(keys []string) interface{} {
- if len(keys) == 0 {
- return t
- }
- subtree := t
- for _, intermediateKey := range keys[:len(keys)-1] {
- value, exists := subtree.values[intermediateKey]
- if !exists {
- return nil
- }
- switch node := value.(type) {
- case *Tree:
- subtree = node
- case []*Tree:
- // go to most recent element
- if len(node) == 0 {
- return nil
- }
- subtree = node[len(node)-1]
- default:
- return nil // cannot navigate through other node types
- }
- }
- // branch based on final node type
- switch node := subtree.values[keys[len(keys)-1]].(type) {
- case *tomlValue:
- return node.value
- default:
- return node
- }
-}
-
-// GetArray returns the value at key in the Tree.
-// It returns []string, []int64, etc type if key has homogeneous lists
-// Key is a dot-separated path (e.g. a.b.c) without single/double quoted strings.
-// Returns nil if the path does not exist in the tree.
-// If keys is of length zero, the current tree is returned.
-func (t *Tree) GetArray(key string) interface{} {
- if key == "" {
- return t
- }
- return t.GetArrayPath(strings.Split(key, "."))
-}
-
-// GetArrayPath returns the element in the tree indicated by 'keys'.
-// If keys is of length zero, the current tree is returned.
-func (t *Tree) GetArrayPath(keys []string) interface{} {
- if len(keys) == 0 {
- return t
- }
- subtree := t
- for _, intermediateKey := range keys[:len(keys)-1] {
- value, exists := subtree.values[intermediateKey]
- if !exists {
- return nil
- }
- switch node := value.(type) {
- case *Tree:
- subtree = node
- case []*Tree:
- // go to most recent element
- if len(node) == 0 {
- return nil
- }
- subtree = node[len(node)-1]
- default:
- return nil // cannot navigate through other node types
- }
- }
- // branch based on final node type
- switch node := subtree.values[keys[len(keys)-1]].(type) {
- case *tomlValue:
- switch n := node.value.(type) {
- case []interface{}:
- return getArray(n)
- default:
- return node.value
- }
- default:
- return node
- }
-}
-
-// if homogeneous array, then return slice type object over []interface{}
-func getArray(n []interface{}) interface{} {
- var s []string
- var i64 []int64
- var f64 []float64
- var bl []bool
- for _, value := range n {
- switch v := value.(type) {
- case string:
- s = append(s, v)
- case int64:
- i64 = append(i64, v)
- case float64:
- f64 = append(f64, v)
- case bool:
- bl = append(bl, v)
- default:
- return n
- }
- }
- if len(s) == len(n) {
- return s
- } else if len(i64) == len(n) {
- return i64
- } else if len(f64) == len(n) {
- return f64
- } else if len(bl) == len(n) {
- return bl
- }
- return n
-}
-
-// GetPosition returns the position of the given key.
-func (t *Tree) GetPosition(key string) Position {
- if key == "" {
- return t.position
- }
- return t.GetPositionPath(strings.Split(key, "."))
-}
-
-// SetPositionPath sets the position of element in the tree indicated by 'keys'.
-// If keys is of length zero, the current tree position is set.
-func (t *Tree) SetPositionPath(keys []string, pos Position) {
- if len(keys) == 0 {
- t.position = pos
- return
- }
- subtree := t
- for _, intermediateKey := range keys[:len(keys)-1] {
- value, exists := subtree.values[intermediateKey]
- if !exists {
- return
- }
- switch node := value.(type) {
- case *Tree:
- subtree = node
- case []*Tree:
- // go to most recent element
- if len(node) == 0 {
- return
- }
- subtree = node[len(node)-1]
- default:
- return
- }
- }
- // branch based on final node type
- switch node := subtree.values[keys[len(keys)-1]].(type) {
- case *tomlValue:
- node.position = pos
- return
- case *Tree:
- node.position = pos
- return
- case []*Tree:
- // go to most recent element
- if len(node) == 0 {
- return
- }
- node[len(node)-1].position = pos
- return
- }
-}
-
-// GetPositionPath returns the element in the tree indicated by 'keys'.
-// If keys is of length zero, the current tree is returned.
-func (t *Tree) GetPositionPath(keys []string) Position {
- if len(keys) == 0 {
- return t.position
- }
- subtree := t
- for _, intermediateKey := range keys[:len(keys)-1] {
- value, exists := subtree.values[intermediateKey]
- if !exists {
- return Position{0, 0}
- }
- switch node := value.(type) {
- case *Tree:
- subtree = node
- case []*Tree:
- // go to most recent element
- if len(node) == 0 {
- return Position{0, 0}
- }
- subtree = node[len(node)-1]
- default:
- return Position{0, 0}
- }
- }
- // branch based on final node type
- switch node := subtree.values[keys[len(keys)-1]].(type) {
- case *tomlValue:
- return node.position
- case *Tree:
- return node.position
- case []*Tree:
- // go to most recent element
- if len(node) == 0 {
- return Position{0, 0}
- }
- return node[len(node)-1].position
- default:
- return Position{0, 0}
- }
-}
-
-// GetDefault works like Get but with a default value
-func (t *Tree) GetDefault(key string, def interface{}) interface{} {
- val := t.Get(key)
- if val == nil {
- return def
- }
- return val
-}
-
-// SetOptions arguments are supplied to the SetWithOptions and SetPathWithOptions functions to modify marshalling behaviour.
-// The default values within the struct are valid default options.
-type SetOptions struct {
- Comment string
- Commented bool
- Multiline bool
- Literal bool
-}
-
-// SetWithOptions is the same as Set, but allows you to provide formatting
-// instructions to the key, that will be used by Marshal().
-func (t *Tree) SetWithOptions(key string, opts SetOptions, value interface{}) {
- t.SetPathWithOptions(strings.Split(key, "."), opts, value)
-}
-
-// SetPathWithOptions is the same as SetPath, but allows you to provide
-// formatting instructions to the key, that will be reused by Marshal().
-func (t *Tree) SetPathWithOptions(keys []string, opts SetOptions, value interface{}) {
- subtree := t
- for i, intermediateKey := range keys[:len(keys)-1] {
- nextTree, exists := subtree.values[intermediateKey]
- if !exists {
- nextTree = newTreeWithPosition(Position{Line: t.position.Line + i, Col: t.position.Col})
- subtree.values[intermediateKey] = nextTree // add new element here
- }
- switch node := nextTree.(type) {
- case *Tree:
- subtree = node
- case []*Tree:
- // go to most recent element
- if len(node) == 0 {
- // create element if it does not exist
- node = append(node, newTreeWithPosition(Position{Line: t.position.Line + i, Col: t.position.Col}))
- subtree.values[intermediateKey] = node
- }
- subtree = node[len(node)-1]
- }
- }
-
- var toInsert interface{}
-
- switch v := value.(type) {
- case *Tree:
- v.comment = opts.Comment
- v.commented = opts.Commented
- toInsert = value
- case []*Tree:
- for i := range v {
- v[i].commented = opts.Commented
- }
- toInsert = value
- case *tomlValue:
- v.comment = opts.Comment
- v.commented = opts.Commented
- v.multiline = opts.Multiline
- v.literal = opts.Literal
- toInsert = v
- default:
- toInsert = &tomlValue{value: value,
- comment: opts.Comment,
- commented: opts.Commented,
- multiline: opts.Multiline,
- literal: opts.Literal,
- position: Position{Line: subtree.position.Line + len(subtree.values) + 1, Col: subtree.position.Col}}
- }
-
- subtree.values[keys[len(keys)-1]] = toInsert
-}
-
-// Set an element in the tree.
-// Key is a dot-separated path (e.g. a.b.c).
-// Creates all necessary intermediate trees, if needed.
-func (t *Tree) Set(key string, value interface{}) {
- t.SetWithComment(key, "", false, value)
-}
-
-// SetWithComment is the same as Set, but allows you to provide comment
-// information to the key, that will be reused by Marshal().
-func (t *Tree) SetWithComment(key string, comment string, commented bool, value interface{}) {
- t.SetPathWithComment(strings.Split(key, "."), comment, commented, value)
-}
-
-// SetPath sets an element in the tree.
-// Keys is an array of path elements (e.g. {"a","b","c"}).
-// Creates all necessary intermediate trees, if needed.
-func (t *Tree) SetPath(keys []string, value interface{}) {
- t.SetPathWithComment(keys, "", false, value)
-}
-
-// SetPathWithComment is the same as SetPath, but allows you to provide comment
-// information to the key, that will be reused by Marshal().
-func (t *Tree) SetPathWithComment(keys []string, comment string, commented bool, value interface{}) {
- t.SetPathWithOptions(keys, SetOptions{Comment: comment, Commented: commented}, value)
-}
-
-// Delete removes a key from the tree.
-// Key is a dot-separated path (e.g. a.b.c).
-func (t *Tree) Delete(key string) error {
- keys, err := parseKey(key)
- if err != nil {
- return err
- }
- return t.DeletePath(keys)
-}
-
-// DeletePath removes a key from the tree.
-// Keys is an array of path elements (e.g. {"a","b","c"}).
-func (t *Tree) DeletePath(keys []string) error {
- keyLen := len(keys)
- if keyLen == 1 {
- delete(t.values, keys[0])
- return nil
- }
- tree := t.GetPath(keys[:keyLen-1])
- item := keys[keyLen-1]
- switch node := tree.(type) {
- case *Tree:
- delete(node.values, item)
- return nil
- }
- return errors.New("no such key to delete")
-}
-
-// createSubTree takes a tree and a key and create the necessary intermediate
-// subtrees to create a subtree at that point. In-place.
-//
-// e.g. passing a.b.c will create (assuming tree is empty) tree[a], tree[a][b]
-// and tree[a][b][c]
-//
-// Returns nil on success, error object on failure
-func (t *Tree) createSubTree(keys []string, pos Position) error {
- subtree := t
- for i, intermediateKey := range keys {
- nextTree, exists := subtree.values[intermediateKey]
- if !exists {
- tree := newTreeWithPosition(Position{Line: t.position.Line + i, Col: t.position.Col})
- tree.position = pos
- tree.inline = subtree.inline
- subtree.values[intermediateKey] = tree
- nextTree = tree
- }
-
- switch node := nextTree.(type) {
- case []*Tree:
- subtree = node[len(node)-1]
- case *Tree:
- subtree = node
- default:
- return fmt.Errorf("unknown type for path %s (%s): %T (%#v)",
- strings.Join(keys, "."), intermediateKey, nextTree, nextTree)
- }
- }
- return nil
-}
-
-// LoadBytes creates a Tree from a []byte.
-func LoadBytes(b []byte) (tree *Tree, err error) {
- defer func() {
- if r := recover(); r != nil {
- if _, ok := r.(runtime.Error); ok {
- panic(r)
- }
- err = errors.New(r.(string))
- }
- }()
-
- if len(b) >= 4 && (hasUTF32BigEndianBOM4(b) || hasUTF32LittleEndianBOM4(b)) {
- b = b[4:]
- } else if len(b) >= 3 && hasUTF8BOM3(b) {
- b = b[3:]
- } else if len(b) >= 2 && (hasUTF16BigEndianBOM2(b) || hasUTF16LittleEndianBOM2(b)) {
- b = b[2:]
- }
-
- tree = parseToml(lexToml(b))
- return
-}
-
-func hasUTF16BigEndianBOM2(b []byte) bool {
- return b[0] == 0xFE && b[1] == 0xFF
-}
-
-func hasUTF16LittleEndianBOM2(b []byte) bool {
- return b[0] == 0xFF && b[1] == 0xFE
-}
-
-func hasUTF8BOM3(b []byte) bool {
- return b[0] == 0xEF && b[1] == 0xBB && b[2] == 0xBF
-}
-
-func hasUTF32BigEndianBOM4(b []byte) bool {
- return b[0] == 0x00 && b[1] == 0x00 && b[2] == 0xFE && b[3] == 0xFF
-}
-
-func hasUTF32LittleEndianBOM4(b []byte) bool {
- return b[0] == 0xFF && b[1] == 0xFE && b[2] == 0x00 && b[3] == 0x00
-}
-
-// LoadReader creates a Tree from any io.Reader.
-func LoadReader(reader io.Reader) (tree *Tree, err error) {
- inputBytes, err := ioutil.ReadAll(reader)
- if err != nil {
- return
- }
- tree, err = LoadBytes(inputBytes)
- return
-}
-
-// Load creates a Tree from a string.
-func Load(content string) (tree *Tree, err error) {
- return LoadBytes([]byte(content))
-}
-
-// LoadFile creates a Tree from a file.
-func LoadFile(path string) (tree *Tree, err error) {
- file, err := os.Open(path)
- if err != nil {
- return nil, err
- }
- defer file.Close()
- return LoadReader(file)
-}
diff --git a/vendor/github.com/pelletier/go-toml/tomlpub.go b/vendor/github.com/pelletier/go-toml/tomlpub.go
deleted file mode 100644
index 4136b4625..000000000
--- a/vendor/github.com/pelletier/go-toml/tomlpub.go
+++ /dev/null
@@ -1,71 +0,0 @@
-package toml
-
-// PubTOMLValue wrapping tomlValue in order to access all properties from outside.
-type PubTOMLValue = tomlValue
-
-func (ptv *PubTOMLValue) Value() interface{} {
- return ptv.value
-}
-func (ptv *PubTOMLValue) Comment() string {
- return ptv.comment
-}
-func (ptv *PubTOMLValue) Commented() bool {
- return ptv.commented
-}
-func (ptv *PubTOMLValue) Multiline() bool {
- return ptv.multiline
-}
-func (ptv *PubTOMLValue) Position() Position {
- return ptv.position
-}
-
-func (ptv *PubTOMLValue) SetValue(v interface{}) {
- ptv.value = v
-}
-func (ptv *PubTOMLValue) SetComment(s string) {
- ptv.comment = s
-}
-func (ptv *PubTOMLValue) SetCommented(c bool) {
- ptv.commented = c
-}
-func (ptv *PubTOMLValue) SetMultiline(m bool) {
- ptv.multiline = m
-}
-func (ptv *PubTOMLValue) SetPosition(p Position) {
- ptv.position = p
-}
-
-// PubTree wrapping Tree in order to access all properties from outside.
-type PubTree = Tree
-
-func (pt *PubTree) Values() map[string]interface{} {
- return pt.values
-}
-
-func (pt *PubTree) Comment() string {
- return pt.comment
-}
-
-func (pt *PubTree) Commented() bool {
- return pt.commented
-}
-
-func (pt *PubTree) Inline() bool {
- return pt.inline
-}
-
-func (pt *PubTree) SetValues(v map[string]interface{}) {
- pt.values = v
-}
-
-func (pt *PubTree) SetComment(c string) {
- pt.comment = c
-}
-
-func (pt *PubTree) SetCommented(c bool) {
- pt.commented = c
-}
-
-func (pt *PubTree) SetInline(i bool) {
- pt.inline = i
-}
diff --git a/vendor/github.com/pelletier/go-toml/tomltree_create.go b/vendor/github.com/pelletier/go-toml/tomltree_create.go
deleted file mode 100644
index 80353500a..000000000
--- a/vendor/github.com/pelletier/go-toml/tomltree_create.go
+++ /dev/null
@@ -1,155 +0,0 @@
-package toml
-
-import (
- "fmt"
- "reflect"
- "time"
-)
-
-var kindToType = [reflect.String + 1]reflect.Type{
- reflect.Bool: reflect.TypeOf(true),
- reflect.String: reflect.TypeOf(""),
- reflect.Float32: reflect.TypeOf(float64(1)),
- reflect.Float64: reflect.TypeOf(float64(1)),
- reflect.Int: reflect.TypeOf(int64(1)),
- reflect.Int8: reflect.TypeOf(int64(1)),
- reflect.Int16: reflect.TypeOf(int64(1)),
- reflect.Int32: reflect.TypeOf(int64(1)),
- reflect.Int64: reflect.TypeOf(int64(1)),
- reflect.Uint: reflect.TypeOf(uint64(1)),
- reflect.Uint8: reflect.TypeOf(uint64(1)),
- reflect.Uint16: reflect.TypeOf(uint64(1)),
- reflect.Uint32: reflect.TypeOf(uint64(1)),
- reflect.Uint64: reflect.TypeOf(uint64(1)),
-}
-
-// typeFor returns a reflect.Type for a reflect.Kind, or nil if none is found.
-// supported values:
-// string, bool, int64, uint64, float64, time.Time, int, int8, int16, int32, uint, uint8, uint16, uint32, float32
-func typeFor(k reflect.Kind) reflect.Type {
- if k > 0 && int(k) < len(kindToType) {
- return kindToType[k]
- }
- return nil
-}
-
-func simpleValueCoercion(object interface{}) (interface{}, error) {
- switch original := object.(type) {
- case string, bool, int64, uint64, float64, time.Time:
- return original, nil
- case int:
- return int64(original), nil
- case int8:
- return int64(original), nil
- case int16:
- return int64(original), nil
- case int32:
- return int64(original), nil
- case uint:
- return uint64(original), nil
- case uint8:
- return uint64(original), nil
- case uint16:
- return uint64(original), nil
- case uint32:
- return uint64(original), nil
- case float32:
- return float64(original), nil
- case fmt.Stringer:
- return original.String(), nil
- case []interface{}:
- value := reflect.ValueOf(original)
- length := value.Len()
- arrayValue := reflect.MakeSlice(value.Type(), 0, length)
- for i := 0; i < length; i++ {
- val := value.Index(i).Interface()
- simpleValue, err := simpleValueCoercion(val)
- if err != nil {
- return nil, err
- }
- arrayValue = reflect.Append(arrayValue, reflect.ValueOf(simpleValue))
- }
- return arrayValue.Interface(), nil
- default:
- return nil, fmt.Errorf("cannot convert type %T to Tree", object)
- }
-}
-
-func sliceToTree(object interface{}) (interface{}, error) {
- // arrays are a bit tricky, since they can represent either a
- // collection of simple values, which is represented by one
- // *tomlValue, or an array of tables, which is represented by an
- // array of *Tree.
-
- // holding the assumption that this function is called from toTree only when value.Kind() is Array or Slice
- value := reflect.ValueOf(object)
- insideType := value.Type().Elem()
- length := value.Len()
- if length > 0 {
- insideType = reflect.ValueOf(value.Index(0).Interface()).Type()
- }
- if insideType.Kind() == reflect.Map {
- // this is considered as an array of tables
- tablesArray := make([]*Tree, 0, length)
- for i := 0; i < length; i++ {
- table := value.Index(i)
- tree, err := toTree(table.Interface())
- if err != nil {
- return nil, err
- }
- tablesArray = append(tablesArray, tree.(*Tree))
- }
- return tablesArray, nil
- }
-
- sliceType := typeFor(insideType.Kind())
- if sliceType == nil {
- sliceType = insideType
- }
-
- arrayValue := reflect.MakeSlice(reflect.SliceOf(sliceType), 0, length)
-
- for i := 0; i < length; i++ {
- val := value.Index(i).Interface()
- simpleValue, err := simpleValueCoercion(val)
- if err != nil {
- return nil, err
- }
- arrayValue = reflect.Append(arrayValue, reflect.ValueOf(simpleValue))
- }
- return &tomlValue{value: arrayValue.Interface(), position: Position{}}, nil
-}
-
-func toTree(object interface{}) (interface{}, error) {
- value := reflect.ValueOf(object)
-
- if value.Kind() == reflect.Map {
- values := map[string]interface{}{}
- keys := value.MapKeys()
- for _, key := range keys {
- if key.Kind() != reflect.String {
- if _, ok := key.Interface().(string); !ok {
- return nil, fmt.Errorf("map key needs to be a string, not %T (%v)", key.Interface(), key.Kind())
- }
- }
-
- v := value.MapIndex(key)
- newValue, err := toTree(v.Interface())
- if err != nil {
- return nil, err
- }
- values[key.String()] = newValue
- }
- return &Tree{values: values, position: Position{}}, nil
- }
-
- if value.Kind() == reflect.Array || value.Kind() == reflect.Slice {
- return sliceToTree(object)
- }
-
- simpleValue, err := simpleValueCoercion(object)
- if err != nil {
- return nil, err
- }
- return &tomlValue{value: simpleValue, position: Position{}}, nil
-}
diff --git a/vendor/github.com/pelletier/go-toml/tomltree_write.go b/vendor/github.com/pelletier/go-toml/tomltree_write.go
deleted file mode 100644
index c9afbdab7..000000000
--- a/vendor/github.com/pelletier/go-toml/tomltree_write.go
+++ /dev/null
@@ -1,552 +0,0 @@
-package toml
-
-import (
- "bytes"
- "fmt"
- "io"
- "math"
- "math/big"
- "reflect"
- "sort"
- "strconv"
- "strings"
- "time"
-)
-
-type valueComplexity int
-
-const (
- valueSimple valueComplexity = iota + 1
- valueComplex
-)
-
-type sortNode struct {
- key string
- complexity valueComplexity
-}
-
-// Encodes a string to a TOML-compliant multi-line string value
-// This function is a clone of the existing encodeTomlString function, except that whitespace characters
-// are preserved. Quotation marks and backslashes are also not escaped.
-func encodeMultilineTomlString(value string, commented string) string {
- var b bytes.Buffer
- adjacentQuoteCount := 0
-
- b.WriteString(commented)
- for i, rr := range value {
- if rr != '"' {
- adjacentQuoteCount = 0
- } else {
- adjacentQuoteCount++
- }
- switch rr {
- case '\b':
- b.WriteString(`\b`)
- case '\t':
- b.WriteString("\t")
- case '\n':
- b.WriteString("\n" + commented)
- case '\f':
- b.WriteString(`\f`)
- case '\r':
- b.WriteString("\r")
- case '"':
- if adjacentQuoteCount >= 3 || i == len(value)-1 {
- adjacentQuoteCount = 0
- b.WriteString(`\"`)
- } else {
- b.WriteString(`"`)
- }
- case '\\':
- b.WriteString(`\`)
- default:
- intRr := uint16(rr)
- if intRr < 0x001F {
- b.WriteString(fmt.Sprintf("\\u%0.4X", intRr))
- } else {
- b.WriteRune(rr)
- }
- }
- }
- return b.String()
-}
-
-// Encodes a string to a TOML-compliant string value
-func encodeTomlString(value string) string {
- var b bytes.Buffer
-
- for _, rr := range value {
- switch rr {
- case '\b':
- b.WriteString(`\b`)
- case '\t':
- b.WriteString(`\t`)
- case '\n':
- b.WriteString(`\n`)
- case '\f':
- b.WriteString(`\f`)
- case '\r':
- b.WriteString(`\r`)
- case '"':
- b.WriteString(`\"`)
- case '\\':
- b.WriteString(`\\`)
- default:
- intRr := uint16(rr)
- if intRr < 0x001F {
- b.WriteString(fmt.Sprintf("\\u%0.4X", intRr))
- } else {
- b.WriteRune(rr)
- }
- }
- }
- return b.String()
-}
-
-func tomlTreeStringRepresentation(t *Tree, ord MarshalOrder) (string, error) {
- var orderedVals []sortNode
- switch ord {
- case OrderPreserve:
- orderedVals = sortByLines(t)
- default:
- orderedVals = sortAlphabetical(t)
- }
-
- var values []string
- for _, node := range orderedVals {
- k := node.key
- v := t.values[k]
-
- repr, err := tomlValueStringRepresentation(v, "", "", ord, false)
- if err != nil {
- return "", err
- }
- values = append(values, quoteKeyIfNeeded(k)+" = "+repr)
- }
- return "{ " + strings.Join(values, ", ") + " }", nil
-}
-
-func tomlValueStringRepresentation(v interface{}, commented string, indent string, ord MarshalOrder, arraysOneElementPerLine bool) (string, error) {
- // this interface check is added to dereference the change made in the writeTo function.
- // That change was made to allow this function to see formatting options.
- tv, ok := v.(*tomlValue)
- if ok {
- v = tv.value
- } else {
- tv = &tomlValue{}
- }
-
- switch value := v.(type) {
- case uint64:
- return strconv.FormatUint(value, 10), nil
- case int64:
- return strconv.FormatInt(value, 10), nil
- case float64:
- // Default bit length is full 64
- bits := 64
- // Float panics if nan is used
- if !math.IsNaN(value) {
- // if 32 bit accuracy is enough to exactly show, use 32
- _, acc := big.NewFloat(value).Float32()
- if acc == big.Exact {
- bits = 32
- }
- }
- if math.Trunc(value) == value {
- return strings.ToLower(strconv.FormatFloat(value, 'f', 1, bits)), nil
- }
- return strings.ToLower(strconv.FormatFloat(value, 'f', -1, bits)), nil
- case string:
- if tv.multiline {
- if tv.literal {
- b := strings.Builder{}
- b.WriteString("'''\n")
- b.Write([]byte(value))
- b.WriteString("\n'''")
- return b.String(), nil
- } else {
- return "\"\"\"\n" + encodeMultilineTomlString(value, commented) + "\"\"\"", nil
- }
- }
- return "\"" + encodeTomlString(value) + "\"", nil
- case []byte:
- b, _ := v.([]byte)
- return string(b), nil
- case bool:
- if value {
- return "true", nil
- }
- return "false", nil
- case time.Time:
- return value.Format(time.RFC3339), nil
- case LocalDate:
- return value.String(), nil
- case LocalDateTime:
- return value.String(), nil
- case LocalTime:
- return value.String(), nil
- case *Tree:
- return tomlTreeStringRepresentation(value, ord)
- case nil:
- return "", nil
- }
-
- rv := reflect.ValueOf(v)
-
- if rv.Kind() == reflect.Slice {
- var values []string
- for i := 0; i < rv.Len(); i++ {
- item := rv.Index(i).Interface()
- itemRepr, err := tomlValueStringRepresentation(item, commented, indent, ord, arraysOneElementPerLine)
- if err != nil {
- return "", err
- }
- values = append(values, itemRepr)
- }
- if arraysOneElementPerLine && len(values) > 1 {
- stringBuffer := bytes.Buffer{}
- valueIndent := indent + ` ` // TODO: move that to a shared encoder state
-
- stringBuffer.WriteString("[\n")
-
- for _, value := range values {
- stringBuffer.WriteString(valueIndent)
- stringBuffer.WriteString(commented + value)
- stringBuffer.WriteString(`,`)
- stringBuffer.WriteString("\n")
- }
-
- stringBuffer.WriteString(indent + commented + "]")
-
- return stringBuffer.String(), nil
- }
- return "[" + strings.Join(values, ", ") + "]", nil
- }
- return "", fmt.Errorf("unsupported value type %T: %v", v, v)
-}
-
-func getTreeArrayLine(trees []*Tree) (line int) {
- // Prevent returning 0 for empty trees
- line = int(^uint(0) >> 1)
- // get lowest line number >= 0
- for _, tv := range trees {
- if tv.position.Line < line || line == 0 {
- line = tv.position.Line
- }
- }
- return
-}
-
-func sortByLines(t *Tree) (vals []sortNode) {
- var (
- line int
- lines []int
- tv *Tree
- tom *tomlValue
- node sortNode
- )
- vals = make([]sortNode, 0)
- m := make(map[int]sortNode)
-
- for k := range t.values {
- v := t.values[k]
- switch v.(type) {
- case *Tree:
- tv = v.(*Tree)
- line = tv.position.Line
- node = sortNode{key: k, complexity: valueComplex}
- case []*Tree:
- line = getTreeArrayLine(v.([]*Tree))
- node = sortNode{key: k, complexity: valueComplex}
- default:
- tom = v.(*tomlValue)
- line = tom.position.Line
- node = sortNode{key: k, complexity: valueSimple}
- }
- lines = append(lines, line)
- vals = append(vals, node)
- m[line] = node
- }
- sort.Ints(lines)
-
- for i, line := range lines {
- vals[i] = m[line]
- }
-
- return vals
-}
-
-func sortAlphabetical(t *Tree) (vals []sortNode) {
- var (
- node sortNode
- simpVals []string
- compVals []string
- )
- vals = make([]sortNode, 0)
- m := make(map[string]sortNode)
-
- for k := range t.values {
- v := t.values[k]
- switch v.(type) {
- case *Tree, []*Tree:
- node = sortNode{key: k, complexity: valueComplex}
- compVals = append(compVals, node.key)
- default:
- node = sortNode{key: k, complexity: valueSimple}
- simpVals = append(simpVals, node.key)
- }
- vals = append(vals, node)
- m[node.key] = node
- }
-
- // Simples first to match previous implementation
- sort.Strings(simpVals)
- i := 0
- for _, key := range simpVals {
- vals[i] = m[key]
- i++
- }
-
- sort.Strings(compVals)
- for _, key := range compVals {
- vals[i] = m[key]
- i++
- }
-
- return vals
-}
-
-func (t *Tree) writeTo(w io.Writer, indent, keyspace string, bytesCount int64, arraysOneElementPerLine bool) (int64, error) {
- return t.writeToOrdered(w, indent, keyspace, bytesCount, arraysOneElementPerLine, OrderAlphabetical, " ", false, false)
-}
-
-func (t *Tree) writeToOrdered(w io.Writer, indent, keyspace string, bytesCount int64, arraysOneElementPerLine bool, ord MarshalOrder, indentString string, compactComments, parentCommented bool) (int64, error) {
- var orderedVals []sortNode
-
- switch ord {
- case OrderPreserve:
- orderedVals = sortByLines(t)
- default:
- orderedVals = sortAlphabetical(t)
- }
-
- for _, node := range orderedVals {
- switch node.complexity {
- case valueComplex:
- k := node.key
- v := t.values[k]
-
- combinedKey := quoteKeyIfNeeded(k)
- if keyspace != "" {
- combinedKey = keyspace + "." + combinedKey
- }
-
- switch node := v.(type) {
- // node has to be of those two types given how keys are sorted above
- case *Tree:
- tv, ok := t.values[k].(*Tree)
- if !ok {
- return bytesCount, fmt.Errorf("invalid value type at %s: %T", k, t.values[k])
- }
- if tv.comment != "" {
- comment := strings.Replace(tv.comment, "\n", "\n"+indent+"#", -1)
- start := "# "
- if strings.HasPrefix(comment, "#") {
- start = ""
- }
- writtenBytesCountComment, errc := writeStrings(w, "\n", indent, start, comment)
- bytesCount += int64(writtenBytesCountComment)
- if errc != nil {
- return bytesCount, errc
- }
- }
-
- var commented string
- if parentCommented || t.commented || tv.commented {
- commented = "# "
- }
- writtenBytesCount, err := writeStrings(w, "\n", indent, commented, "[", combinedKey, "]\n")
- bytesCount += int64(writtenBytesCount)
- if err != nil {
- return bytesCount, err
- }
- bytesCount, err = node.writeToOrdered(w, indent+indentString, combinedKey, bytesCount, arraysOneElementPerLine, ord, indentString, compactComments, parentCommented || t.commented || tv.commented)
- if err != nil {
- return bytesCount, err
- }
- case []*Tree:
- for _, subTree := range node {
- var commented string
- if parentCommented || t.commented || subTree.commented {
- commented = "# "
- }
- writtenBytesCount, err := writeStrings(w, "\n", indent, commented, "[[", combinedKey, "]]\n")
- bytesCount += int64(writtenBytesCount)
- if err != nil {
- return bytesCount, err
- }
-
- bytesCount, err = subTree.writeToOrdered(w, indent+indentString, combinedKey, bytesCount, arraysOneElementPerLine, ord, indentString, compactComments, parentCommented || t.commented || subTree.commented)
- if err != nil {
- return bytesCount, err
- }
- }
- }
- default: // Simple
- k := node.key
- v, ok := t.values[k].(*tomlValue)
- if !ok {
- return bytesCount, fmt.Errorf("invalid value type at %s: %T", k, t.values[k])
- }
-
- var commented string
- if parentCommented || t.commented || v.commented {
- commented = "# "
- }
- repr, err := tomlValueStringRepresentation(v, commented, indent, ord, arraysOneElementPerLine)
- if err != nil {
- return bytesCount, err
- }
-
- if v.comment != "" {
- comment := strings.Replace(v.comment, "\n", "\n"+indent+"#", -1)
- start := "# "
- if strings.HasPrefix(comment, "#") {
- start = ""
- }
- if !compactComments {
- writtenBytesCountComment, errc := writeStrings(w, "\n")
- bytesCount += int64(writtenBytesCountComment)
- if errc != nil {
- return bytesCount, errc
- }
- }
- writtenBytesCountComment, errc := writeStrings(w, indent, start, comment, "\n")
- bytesCount += int64(writtenBytesCountComment)
- if errc != nil {
- return bytesCount, errc
- }
- }
-
- quotedKey := quoteKeyIfNeeded(k)
- writtenBytesCount, err := writeStrings(w, indent, commented, quotedKey, " = ", repr, "\n")
- bytesCount += int64(writtenBytesCount)
- if err != nil {
- return bytesCount, err
- }
- }
- }
-
- return bytesCount, nil
-}
-
-// quote a key if it does not fit the bare key format (A-Za-z0-9_-)
-// quoted keys use the same rules as strings
-func quoteKeyIfNeeded(k string) string {
- // when encoding a map with the 'quoteMapKeys' option enabled, the tree will contain
- // keys that have already been quoted.
- // not an ideal situation, but good enough of a stop gap.
- if len(k) >= 2 && k[0] == '"' && k[len(k)-1] == '"' {
- return k
- }
- isBare := true
- for _, r := range k {
- if !isValidBareChar(r) {
- isBare = false
- break
- }
- }
- if isBare {
- return k
- }
- return quoteKey(k)
-}
-
-func quoteKey(k string) string {
- return "\"" + encodeTomlString(k) + "\""
-}
-
-func writeStrings(w io.Writer, s ...string) (int, error) {
- var n int
- for i := range s {
- b, err := io.WriteString(w, s[i])
- n += b
- if err != nil {
- return n, err
- }
- }
- return n, nil
-}
-
-// WriteTo encode the Tree as Toml and writes it to the writer w.
-// Returns the number of bytes written in case of success, or an error if anything happened.
-func (t *Tree) WriteTo(w io.Writer) (int64, error) {
- return t.writeTo(w, "", "", 0, false)
-}
-
-// ToTomlString generates a human-readable representation of the current tree.
-// Output spans multiple lines, and is suitable for ingest by a TOML parser.
-// If the conversion cannot be performed, ToString returns a non-nil error.
-func (t *Tree) ToTomlString() (string, error) {
- b, err := t.Marshal()
- if err != nil {
- return "", err
- }
- return string(b), nil
-}
-
-// String generates a human-readable representation of the current tree.
-// Alias of ToString. Present to implement the fmt.Stringer interface.
-func (t *Tree) String() string {
- result, _ := t.ToTomlString()
- return result
-}
-
-// ToMap recursively generates a representation of the tree using Go built-in structures.
-// The following types are used:
-//
-// * bool
-// * float64
-// * int64
-// * string
-// * uint64
-// * time.Time
-// * map[string]interface{} (where interface{} is any of this list)
-// * []interface{} (where interface{} is any of this list)
-func (t *Tree) ToMap() map[string]interface{} {
- result := map[string]interface{}{}
-
- for k, v := range t.values {
- switch node := v.(type) {
- case []*Tree:
- var array []interface{}
- for _, item := range node {
- array = append(array, item.ToMap())
- }
- result[k] = array
- case *Tree:
- result[k] = node.ToMap()
- case *tomlValue:
- result[k] = tomlValueToGo(node.value)
- }
- }
- return result
-}
-
-func tomlValueToGo(v interface{}) interface{} {
- if tree, ok := v.(*Tree); ok {
- return tree.ToMap()
- }
-
- rv := reflect.ValueOf(v)
-
- if rv.Kind() != reflect.Slice {
- return v
- }
- values := make([]interface{}, rv.Len())
- for i := 0; i < rv.Len(); i++ {
- item := rv.Index(i).Interface()
- values[i] = tomlValueToGo(item)
- }
- return values
-}
diff --git a/vendor/github.com/pelletier/go-toml/tomltree_writepub.go b/vendor/github.com/pelletier/go-toml/tomltree_writepub.go
deleted file mode 100644
index fa326308c..000000000
--- a/vendor/github.com/pelletier/go-toml/tomltree_writepub.go
+++ /dev/null
@@ -1,6 +0,0 @@
-package toml
-
-// ValueStringRepresentation transforms an interface{} value into its toml string representation.
-func ValueStringRepresentation(v interface{}, commented string, indent string, ord MarshalOrder, arraysOneElementPerLine bool) (string, error) {
- return tomlValueStringRepresentation(v, commented, indent, ord, arraysOneElementPerLine)
-}
diff --git a/vendor/github.com/pelletier/go-toml/.dockerignore b/vendor/github.com/pelletier/go-toml/v2/.dockerignore
similarity index 100%
rename from vendor/github.com/pelletier/go-toml/.dockerignore
rename to vendor/github.com/pelletier/go-toml/v2/.dockerignore
diff --git a/vendor/github.com/pelletier/go-toml/v2/.gitattributes b/vendor/github.com/pelletier/go-toml/v2/.gitattributes
new file mode 100644
index 000000000..34a0a21a3
--- /dev/null
+++ b/vendor/github.com/pelletier/go-toml/v2/.gitattributes
@@ -0,0 +1,4 @@
+* text=auto
+
+benchmark/benchmark.toml text eol=lf
+testdata/** text eol=lf
diff --git a/vendor/github.com/pelletier/go-toml/.gitignore b/vendor/github.com/pelletier/go-toml/v2/.gitignore
similarity index 96%
rename from vendor/github.com/pelletier/go-toml/.gitignore
rename to vendor/github.com/pelletier/go-toml/v2/.gitignore
index e6ba63a5c..a69e2b0eb 100644
--- a/vendor/github.com/pelletier/go-toml/.gitignore
+++ b/vendor/github.com/pelletier/go-toml/v2/.gitignore
@@ -3,3 +3,4 @@ fuzz/
cmd/tomll/tomll
cmd/tomljson/tomljson
cmd/tomltestgen/tomltestgen
+dist
\ No newline at end of file
diff --git a/vendor/github.com/pelletier/go-toml/v2/.golangci.toml b/vendor/github.com/pelletier/go-toml/v2/.golangci.toml
new file mode 100644
index 000000000..067db5517
--- /dev/null
+++ b/vendor/github.com/pelletier/go-toml/v2/.golangci.toml
@@ -0,0 +1,84 @@
+[service]
+golangci-lint-version = "1.39.0"
+
+[linters-settings.wsl]
+allow-assign-and-anything = true
+
+[linters-settings.exhaustive]
+default-signifies-exhaustive = true
+
+[linters]
+disable-all = true
+enable = [
+ "asciicheck",
+ "bodyclose",
+ "cyclop",
+ "deadcode",
+ "depguard",
+ "dogsled",
+ "dupl",
+ "durationcheck",
+ "errcheck",
+ "errorlint",
+ "exhaustive",
+ # "exhaustivestruct",
+ "exportloopref",
+ "forbidigo",
+ # "forcetypeassert",
+ "funlen",
+ "gci",
+ # "gochecknoglobals",
+ "gochecknoinits",
+ "gocognit",
+ "goconst",
+ "gocritic",
+ "gocyclo",
+ "godot",
+ "godox",
+ # "goerr113",
+ "gofmt",
+ "gofumpt",
+ "goheader",
+ "goimports",
+ "golint",
+ "gomnd",
+ # "gomoddirectives",
+ "gomodguard",
+ "goprintffuncname",
+ "gosec",
+ "gosimple",
+ "govet",
+ # "ifshort",
+ "importas",
+ "ineffassign",
+ "lll",
+ "makezero",
+ "misspell",
+ "nakedret",
+ "nestif",
+ "nilerr",
+ # "nlreturn",
+ "noctx",
+ "nolintlint",
+ #"paralleltest",
+ "prealloc",
+ "predeclared",
+ "revive",
+ "rowserrcheck",
+ "sqlclosecheck",
+ "staticcheck",
+ "structcheck",
+ "stylecheck",
+ # "testpackage",
+ "thelper",
+ "tparallel",
+ "typecheck",
+ "unconvert",
+ "unparam",
+ "unused",
+ "varcheck",
+ "wastedassign",
+ "whitespace",
+ # "wrapcheck",
+ # "wsl"
+]
diff --git a/vendor/github.com/pelletier/go-toml/v2/.goreleaser.yaml b/vendor/github.com/pelletier/go-toml/v2/.goreleaser.yaml
new file mode 100644
index 000000000..3aa1840ec
--- /dev/null
+++ b/vendor/github.com/pelletier/go-toml/v2/.goreleaser.yaml
@@ -0,0 +1,123 @@
+before:
+ hooks:
+ - go mod tidy
+ - go fmt ./...
+ - go test ./...
+builds:
+ - id: tomll
+ main: ./cmd/tomll
+ binary: tomll
+ env:
+ - CGO_ENABLED=0
+ flags:
+ - -trimpath
+ ldflags:
+ - -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.CommitDate}}
+ mod_timestamp: '{{ .CommitTimestamp }}'
+ targets:
+ - linux_amd64
+ - linux_arm64
+ - linux_arm
+ - windows_amd64
+ - windows_arm64
+ - windows_arm
+ - darwin_amd64
+ - darwin_arm64
+ - id: tomljson
+ main: ./cmd/tomljson
+ binary: tomljson
+ env:
+ - CGO_ENABLED=0
+ flags:
+ - -trimpath
+ ldflags:
+ - -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.CommitDate}}
+ mod_timestamp: '{{ .CommitTimestamp }}'
+ targets:
+ - linux_amd64
+ - linux_arm64
+ - linux_arm
+ - windows_amd64
+ - windows_arm64
+ - windows_arm
+ - darwin_amd64
+ - darwin_arm64
+ - id: jsontoml
+ main: ./cmd/jsontoml
+ binary: jsontoml
+ env:
+ - CGO_ENABLED=0
+ flags:
+ - -trimpath
+ ldflags:
+ - -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.CommitDate}}
+ mod_timestamp: '{{ .CommitTimestamp }}'
+ targets:
+ - linux_amd64
+ - linux_arm64
+ - linux_arm
+ - windows_amd64
+ - windows_arm64
+ - windows_arm
+ - darwin_amd64
+ - darwin_arm64
+universal_binaries:
+ - id: tomll
+ replace: true
+ name_template: tomll
+ - id: tomljson
+ replace: true
+ name_template: tomljson
+ - id: jsontoml
+ replace: true
+ name_template: jsontoml
+archives:
+- id: jsontoml
+ format: tar.xz
+ builds:
+ - jsontoml
+ files:
+ - none*
+ name_template: "{{ .Binary }}_{{.Version}}_{{ .Os }}_{{ .Arch }}"
+- id: tomljson
+ format: tar.xz
+ builds:
+ - tomljson
+ files:
+ - none*
+ name_template: "{{ .Binary }}_{{.Version}}_{{ .Os }}_{{ .Arch }}"
+- id: tomll
+ format: tar.xz
+ builds:
+ - tomll
+ files:
+ - none*
+ name_template: "{{ .Binary }}_{{.Version}}_{{ .Os }}_{{ .Arch }}"
+dockers:
+ - id: tools
+ goos: linux
+ goarch: amd64
+ ids:
+ - jsontoml
+ - tomljson
+ - tomll
+ image_templates:
+ - "ghcr.io/pelletier/go-toml:latest"
+ - "ghcr.io/pelletier/go-toml:{{ .Tag }}"
+ - "ghcr.io/pelletier/go-toml:v{{ .Major }}"
+ skip_push: false
+checksum:
+ name_template: 'sha256sums.txt'
+snapshot:
+ name_template: "{{ incpatch .Version }}-next"
+release:
+ github:
+ owner: pelletier
+ name: go-toml
+ draft: true
+ prerelease: auto
+ mode: replace
+changelog:
+ use: github-native
+announce:
+ skip: true
diff --git a/vendor/github.com/pelletier/go-toml/v2/CONTRIBUTING.md b/vendor/github.com/pelletier/go-toml/v2/CONTRIBUTING.md
new file mode 100644
index 000000000..04dd12bcb
--- /dev/null
+++ b/vendor/github.com/pelletier/go-toml/v2/CONTRIBUTING.md
@@ -0,0 +1,196 @@
+# Contributing
+
+Thank you for your interest in go-toml! We appreciate you considering
+contributing to go-toml!
+
+The main goal is the project is to provide an easy-to-use and efficient TOML
+implementation for Go that gets the job done and gets out of your way – dealing
+with TOML is probably not the central piece of your project.
+
+As the single maintainer of go-toml, time is scarce. All help, big or small, is
+more than welcomed!
+
+## Ask questions
+
+Any question you may have, somebody else might have it too. Always feel free to
+ask them on the [discussion board][discussions]. We will try to answer them as
+clearly and quickly as possible, time permitting.
+
+Asking questions also helps us identify areas where the documentation needs
+improvement, or new features that weren't envisioned before. Sometimes, a
+seemingly innocent question leads to the fix of a bug. Don't hesitate and ask
+away!
+
+[discussions]: https://github.com/pelletier/go-toml/discussions
+
+## Improve the documentation
+
+The best way to share your knowledge and experience with go-toml is to improve
+the documentation. Fix a typo, clarify an interface, add an example, anything
+goes!
+
+The documentation is present in the [README][readme] and thorough the source
+code. On release, it gets updated on [pkg.go.dev][pkg.go.dev]. To make a change
+to the documentation, create a pull request with your proposed changes. For
+simple changes like that, the easiest way to go is probably the "Fork this
+project and edit the file" button on Github, displayed at the top right of the
+file. Unless it's a trivial change (for example a typo), provide a little bit of
+context in your pull request description or commit message.
+
+## Report a bug
+
+Found a bug! Sorry to hear that :(. Help us and other track them down and fix by
+reporting it. [File a new bug report][bug-report] on the [issues
+tracker][issues-tracker]. The template should provide enough guidance on what to
+include. When in doubt: add more details! By reducing ambiguity and providing
+more information, it decreases back and forth and saves everyone time.
+
+## Code changes
+
+Want to contribute a patch? Very happy to hear that!
+
+First, some high-level rules:
+
+- A short proposal with some POC code is better than a lengthy piece of text
+ with no code. Code speaks louder than words. That being said, bigger changes
+ should probably start with a [discussion][discussions].
+- No backward-incompatible patch will be accepted unless discussed. Sometimes
+ it's hard, but we try not to break people's programs unless we absolutely have
+ to.
+- If you are writing a new feature or extending an existing one, make sure to
+ write some documentation.
+- Bug fixes need to be accompanied with regression tests.
+- New code needs to be tested.
+- Your commit messages need to explain why the change is needed, even if already
+ included in the PR description.
+
+It does sound like a lot, but those best practices are here to save time overall
+and continuously improve the quality of the project, which is something everyone
+benefits from.
+
+### Get started
+
+The fairly standard code contribution process looks like that:
+
+1. [Fork the project][fork].
+2. Make your changes, commit on any branch you like.
+3. [Open up a pull request][pull-request]
+4. Review, potential ask for changes.
+5. Merge.
+
+Feel free to ask for help! You can create draft pull requests to gather
+some early feedback!
+
+### Run the tests
+
+You can run tests for go-toml using Go's test tool: `go test -race ./...`.
+
+During the pull request process, all tests will be ran on Linux, Windows, and
+MacOS on the last two versions of Go.
+
+However, given GitHub's new policy to _not_ run Actions on pull requests until a
+maintainer clicks on button, it is highly recommended that you run them locally
+as you make changes.
+
+### Check coverage
+
+We use `go tool cover` to compute test coverage. Most code editors have a way to
+run and display code coverage, but at the end of the day, we do this:
+
+```
+go test -covermode=atomic -coverprofile=coverage.out
+go tool cover -func=coverage.out
+```
+
+and verify that the overall percentage of tested code does not go down. This is
+a requirement. As a rule of thumb, all lines of code touched by your changes
+should be covered. On Unix you can use `./ci.sh coverage -d v2` to check if your
+code lowers the coverage.
+
+### Verify performance
+
+Go-toml aims to stay efficient. We rely on a set of scenarios executed with Go's
+builtin benchmark systems. Because of their noisy nature, containers provided by
+Github Actions cannot be reliably used for benchmarking. As a result, you are
+responsible for checking that your changes do not incur a performance penalty.
+You can run their following to execute benchmarks:
+
+```
+go test ./... -bench=. -count=10
+```
+
+Benchmark results should be compared against each other with
+[benchstat][benchstat]. Typical flow looks like this:
+
+1. On the `v2` branch, run `go test ./... -bench=. -count 10` and save output to
+ a file (for example `old.txt`).
+2. Make some code changes.
+3. Run `go test ....` again, and save the output to an other file (for example
+ `new.txt`).
+4. Run `benchstat old.txt new.txt` to check that time/op does not go up in any
+ test.
+
+On Unix you can use `./ci.sh benchmark -d v2` to verify how your code impacts
+performance.
+
+It is highly encouraged to add the benchstat results to your pull request
+description. Pull requests that lower performance will receive more scrutiny.
+
+[benchstat]: https://pkg.go.dev/golang.org/x/perf/cmd/benchstat
+
+### Style
+
+Try to look around and follow the same format and structure as the rest of the
+code. We enforce using `go fmt` on the whole code base.
+
+---
+
+## Maintainers-only
+
+### Merge pull request
+
+Checklist:
+
+- Passing CI.
+- Does not introduce backward-incompatible changes (unless discussed).
+- Has relevant doc changes.
+- Benchstat does not show performance regression.
+- Pull request is [labeled appropriately][pr-labels].
+- Title will be understandable in the changelog.
+
+1. Merge using "squash and merge".
+2. Make sure to edit the commit message to keep all the useful information
+ nice and clean.
+3. Make sure the commit title is clear and contains the PR number (#123).
+
+### New release
+
+1. Decide on the next version number. Use semver.
+2. Generate release notes using [`gh`][gh]. Example:
+```
+$ gh api -X POST \
+ -F tag_name='v2.0.0-beta.5' \
+ -F target_commitish='v2' \
+ -F previous_tag_name='v2.0.0-beta.4' \
+ --jq '.body' \
+ repos/pelletier/go-toml/releases/generate-notes
+```
+3. Look for "Other changes". That would indicate a pull request not labeled
+ properly. Tweak labels and pull request titles until changelog looks good for
+ users.
+4. [Draft new release][new-release].
+5. Fill tag and target with the same value used to generate the changelog.
+6. Set title to the new tag value.
+7. Paste the generated changelog.
+8. Check "create discussion", in the "Releases" category.
+9. Check pre-release if new version is an alpha or beta.
+
+[issues-tracker]: https://github.com/pelletier/go-toml/issues
+[bug-report]: https://github.com/pelletier/go-toml/issues/new?template=bug_report.md
+[pkg.go.dev]: https://pkg.go.dev/github.com/pelletier/go-toml
+[readme]: ./README.md
+[fork]: https://help.github.com/articles/fork-a-repo
+[pull-request]: https://help.github.com/en/articles/creating-a-pull-request
+[new-release]: https://github.com/pelletier/go-toml/releases/new
+[gh]: https://github.com/cli/cli
+[pr-labels]: https://github.com/pelletier/go-toml/blob/v2/.github/release.yml
diff --git a/vendor/github.com/pelletier/go-toml/v2/Dockerfile b/vendor/github.com/pelletier/go-toml/v2/Dockerfile
new file mode 100644
index 000000000..b9e933237
--- /dev/null
+++ b/vendor/github.com/pelletier/go-toml/v2/Dockerfile
@@ -0,0 +1,5 @@
+FROM scratch
+ENV PATH "$PATH:/bin"
+COPY tomll /bin/tomll
+COPY tomljson /bin/tomljson
+COPY jsontoml /bin/jsontoml
diff --git a/vendor/github.com/pelletier/go-toml/v2/LICENSE b/vendor/github.com/pelletier/go-toml/v2/LICENSE
new file mode 100644
index 000000000..6839d51cd
--- /dev/null
+++ b/vendor/github.com/pelletier/go-toml/v2/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2013 - 2022 Thomas Pelletier, Eric Anderton
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/vendor/github.com/pelletier/go-toml/v2/README.md b/vendor/github.com/pelletier/go-toml/v2/README.md
new file mode 100644
index 000000000..d53f43971
--- /dev/null
+++ b/vendor/github.com/pelletier/go-toml/v2/README.md
@@ -0,0 +1,563 @@
+# go-toml v2
+
+Go library for the [TOML](https://toml.io/en/) format.
+
+This library supports [TOML v1.0.0](https://toml.io/en/v1.0.0).
+
+[🐞 Bug Reports](https://github.com/pelletier/go-toml/issues)
+
+[💬 Anything else](https://github.com/pelletier/go-toml/discussions)
+
+## Documentation
+
+Full API, examples, and implementation notes are available in the Go
+documentation.
+
+[![Go Reference](https://pkg.go.dev/badge/github.com/pelletier/go-toml/v2.svg)](https://pkg.go.dev/github.com/pelletier/go-toml/v2)
+
+## Import
+
+```go
+import "github.com/pelletier/go-toml/v2"
+```
+
+See [Modules](#Modules).
+
+## Features
+
+### Stdlib behavior
+
+As much as possible, this library is designed to behave similarly as the
+standard library's `encoding/json`.
+
+### Performance
+
+While go-toml favors usability, it is written with performance in mind. Most
+operations should not be shockingly slow. See [benchmarks](#benchmarks).
+
+### Strict mode
+
+`Decoder` can be set to "strict mode", which makes it error when some parts of
+the TOML document was not present in the target structure. This is a great way
+to check for typos. [See example in the documentation][strict].
+
+[strict]: https://pkg.go.dev/github.com/pelletier/go-toml/v2#example-Decoder.DisallowUnknownFields
+
+### Contextualized errors
+
+When most decoding errors occur, go-toml returns [`DecodeError`][decode-err]),
+which contains a human readable contextualized version of the error. For
+example:
+
+```
+2| key1 = "value1"
+3| key2 = "missing2"
+ | ~~~~ missing field
+4| key3 = "missing3"
+5| key4 = "value4"
+```
+
+[decode-err]: https://pkg.go.dev/github.com/pelletier/go-toml/v2#DecodeError
+
+### Local date and time support
+
+TOML supports native [local date/times][ldt]. It allows to represent a given
+date, time, or date-time without relation to a timezone or offset. To support
+this use-case, go-toml provides [`LocalDate`][tld], [`LocalTime`][tlt], and
+[`LocalDateTime`][tldt]. Those types can be transformed to and from `time.Time`,
+making them convenient yet unambiguous structures for their respective TOML
+representation.
+
+[ldt]: https://toml.io/en/v1.0.0#local-date-time
+[tld]: https://pkg.go.dev/github.com/pelletier/go-toml/v2#LocalDate
+[tlt]: https://pkg.go.dev/github.com/pelletier/go-toml/v2#LocalTime
+[tldt]: https://pkg.go.dev/github.com/pelletier/go-toml/v2#LocalDateTime
+
+## Getting started
+
+Given the following struct, let's see how to read it and write it as TOML:
+
+```go
+type MyConfig struct {
+ Version int
+ Name string
+ Tags []string
+}
+```
+
+### Unmarshaling
+
+[`Unmarshal`][unmarshal] reads a TOML document and fills a Go structure with its
+content. For example:
+
+```go
+doc := `
+version = 2
+name = "go-toml"
+tags = ["go", "toml"]
+`
+
+var cfg MyConfig
+err := toml.Unmarshal([]byte(doc), &cfg)
+if err != nil {
+ panic(err)
+}
+fmt.Println("version:", cfg.Version)
+fmt.Println("name:", cfg.Name)
+fmt.Println("tags:", cfg.Tags)
+
+// Output:
+// version: 2
+// name: go-toml
+// tags: [go toml]
+```
+
+[unmarshal]: https://pkg.go.dev/github.com/pelletier/go-toml/v2#Unmarshal
+
+### Marshaling
+
+[`Marshal`][marshal] is the opposite of Unmarshal: it represents a Go structure
+as a TOML document:
+
+```go
+cfg := MyConfig{
+ Version: 2,
+ Name: "go-toml",
+ Tags: []string{"go", "toml"},
+}
+
+b, err := toml.Marshal(cfg)
+if err != nil {
+ panic(err)
+}
+fmt.Println(string(b))
+
+// Output:
+// Version = 2
+// Name = 'go-toml'
+// Tags = ['go', 'toml']
+```
+
+[marshal]: https://pkg.go.dev/github.com/pelletier/go-toml/v2#Marshal
+
+## Unstable API
+
+This API does not yet follow the backward compatibility guarantees of this
+library. They provide early access to features that may have rough edges or an
+API subject to change.
+
+### Parser
+
+Parser is the unstable API that allows iterative parsing of a TOML document at
+the AST level. See https://pkg.go.dev/github.com/pelletier/go-toml/v2/unstable.
+
+## Benchmarks
+
+Execution time speedup compared to other Go TOML libraries:
+
+
+
+ Benchmark | go-toml v1 | BurntSushi/toml |
+
+
+ Marshal/HugoFrontMatter-2 | 1.9x | 1.9x |
+ Marshal/ReferenceFile/map-2 | 1.7x | 1.8x |
+ Marshal/ReferenceFile/struct-2 | 2.2x | 2.5x |
+ Unmarshal/HugoFrontMatter-2 | 2.9x | 2.9x |
+ Unmarshal/ReferenceFile/map-2 | 2.6x | 2.9x |
+ Unmarshal/ReferenceFile/struct-2 | 4.4x | 5.3x |
+
+
+See more
+The table above has the results of the most common use-cases. The table below
+contains the results of all benchmarks, including unrealistic ones. It is
+provided for completeness.
+
+
+
+ Benchmark | go-toml v1 | BurntSushi/toml |
+
+
+ Marshal/SimpleDocument/map-2 | 1.8x | 2.9x |
+ Marshal/SimpleDocument/struct-2 | 2.7x | 4.2x |
+ Unmarshal/SimpleDocument/map-2 | 4.5x | 3.1x |
+ Unmarshal/SimpleDocument/struct-2 | 6.2x | 3.9x |
+ UnmarshalDataset/example-2 | 3.1x | 3.5x |
+ UnmarshalDataset/code-2 | 2.3x | 3.1x |
+ UnmarshalDataset/twitter-2 | 2.5x | 2.6x |
+ UnmarshalDataset/citm_catalog-2 | 2.1x | 2.2x |
+ UnmarshalDataset/canada-2 | 1.6x | 1.3x |
+ UnmarshalDataset/config-2 | 4.3x | 3.2x |
+ [Geo mean] | 2.7x | 2.8x |
+
+
+This table can be generated with ./ci.sh benchmark -a -html
.
+
+
+## Modules
+
+go-toml uses Go's standard modules system.
+
+Installation instructions:
+
+- Go ≥ 1.16: Nothing to do. Use the import in your code. The `go` command deals
+ with it automatically.
+- Go ≥ 1.13: `GO111MODULE=on go get github.com/pelletier/go-toml/v2`.
+
+In case of trouble: [Go Modules FAQ][mod-faq].
+
+[mod-faq]: https://github.com/golang/go/wiki/Modules#why-does-installing-a-tool-via-go-get-fail-with-error-cannot-find-main-module
+
+## Tools
+
+Go-toml provides three handy command line tools:
+
+ * `tomljson`: Reads a TOML file and outputs its JSON representation.
+
+ ```
+ $ go install github.com/pelletier/go-toml/v2/cmd/tomljson@latest
+ $ tomljson --help
+ ```
+
+ * `jsontoml`: Reads a JSON file and outputs a TOML representation.
+
+ ```
+ $ go install github.com/pelletier/go-toml/v2/cmd/jsontoml@latest
+ $ jsontoml --help
+ ```
+
+ * `tomll`: Lints and reformats a TOML file.
+
+ ```
+ $ go install github.com/pelletier/go-toml/v2/cmd/tomll@latest
+ $ tomll --help
+ ```
+
+### Docker image
+
+Those tools are also available as a [Docker image][docker]. For example, to use
+`tomljson`:
+
+```
+docker run -i ghcr.io/pelletier/go-toml:v2 tomljson < example.toml
+```
+
+Multiple versions are availble on [ghcr.io][docker].
+
+[docker]: https://github.com/pelletier/go-toml/pkgs/container/go-toml
+
+## Migrating from v1
+
+This section describes the differences between v1 and v2, with some pointers on
+how to get the original behavior when possible.
+
+### Decoding / Unmarshal
+
+#### Automatic field name guessing
+
+When unmarshaling to a struct, if a key in the TOML document does not exactly
+match the name of a struct field or any of the `toml`-tagged field, v1 tries
+multiple variations of the key ([code][v1-keys]).
+
+V2 instead does a case-insensitive matching, like `encoding/json`.
+
+This could impact you if you are relying on casing to differentiate two fields,
+and one of them is a not using the `toml` struct tag. The recommended solution
+is to be specific about tag names for those fields using the `toml` struct tag.
+
+[v1-keys]: https://github.com/pelletier/go-toml/blob/a2e52561804c6cd9392ebf0048ca64fe4af67a43/marshal.go#L775-L781
+
+#### Ignore preexisting value in interface
+
+When decoding into a non-nil `interface{}`, go-toml v1 uses the type of the
+element in the interface to decode the object. For example:
+
+```go
+type inner struct {
+ B interface{}
+}
+type doc struct {
+ A interface{}
+}
+
+d := doc{
+ A: inner{
+ B: "Before",
+ },
+}
+
+data := `
+[A]
+B = "After"
+`
+
+toml.Unmarshal([]byte(data), &d)
+fmt.Printf("toml v1: %#v\n", d)
+
+// toml v1: main.doc{A:main.inner{B:"After"}}
+```
+
+In this case, field `A` is of type `interface{}`, containing a `inner` struct.
+V1 sees that type and uses it when decoding the object.
+
+When decoding an object into an `interface{}`, V2 instead disregards whatever
+value the `interface{}` may contain and replaces it with a
+`map[string]interface{}`. With the same data structure as above, here is what
+the result looks like:
+
+```go
+toml.Unmarshal([]byte(data), &d)
+fmt.Printf("toml v2: %#v\n", d)
+
+// toml v2: main.doc{A:map[string]interface {}{"B":"After"}}
+```
+
+This is to match `encoding/json`'s behavior. There is no way to make the v2
+decoder behave like v1.
+
+#### Values out of array bounds ignored
+
+When decoding into an array, v1 returns an error when the number of elements
+contained in the doc is superior to the capacity of the array. For example:
+
+```go
+type doc struct {
+ A [2]string
+}
+d := doc{}
+err := toml.Unmarshal([]byte(`A = ["one", "two", "many"]`), &d)
+fmt.Println(err)
+
+// (1, 1): unmarshal: TOML array length (3) exceeds destination array length (2)
+```
+
+In the same situation, v2 ignores the last value:
+
+```go
+err := toml.Unmarshal([]byte(`A = ["one", "two", "many"]`), &d)
+fmt.Println("err:", err, "d:", d)
+// err: d: {[one two]}
+```
+
+This is to match `encoding/json`'s behavior. There is no way to make the v2
+decoder behave like v1.
+
+#### Support for `toml.Unmarshaler` has been dropped
+
+This method was not widely used, poorly defined, and added a lot of complexity.
+A similar effect can be achieved by implementing the `encoding.TextUnmarshaler`
+interface and use strings.
+
+#### Support for `default` struct tag has been dropped
+
+This feature adds complexity and a poorly defined API for an effect that can be
+accomplished outside of the library.
+
+It does not seem like other format parsers in Go support that feature (the
+project referenced in the original ticket #202 has not been updated since 2017).
+Given that go-toml v2 should not touch values not in the document, the same
+effect can be achieved by pre-filling the struct with defaults (libraries like
+[go-defaults][go-defaults] can help). Also, string representation is not well
+defined for all types: it creates issues like #278.
+
+The recommended replacement is pre-filling the struct before unmarshaling.
+
+[go-defaults]: https://github.com/mcuadros/go-defaults
+
+#### `toml.Tree` replacement
+
+This structure was the initial attempt at providing a document model for
+go-toml. It allows manipulating the structure of any document, encoding and
+decoding from their TOML representation. While a more robust feature was
+initially planned in go-toml v2, this has been ultimately [removed from
+scope][nodoc] of this library, with no plan to add it back at the moment. The
+closest equivalent at the moment would be to unmarshal into an `interface{}` and
+use type assertions and/or reflection to manipulate the arbitrary
+structure. However this would fall short of providing all of the TOML features
+such as adding comments and be specific about whitespace.
+
+
+#### `toml.Position` are not retrievable anymore
+
+The API for retrieving the position (line, column) of a specific TOML element do
+not exist anymore. This was done to minimize the amount of concepts introduced
+by the library (query path), and avoid the performance hit related to storing
+positions in the absence of a document model, for a feature that seemed to have
+little use. Errors however have gained more detailed position
+information. Position retrieval seems better fitted for a document model, which
+has been [removed from the scope][nodoc] of go-toml v2 at the moment.
+
+### Encoding / Marshal
+
+#### Default struct fields order
+
+V1 emits struct fields order alphabetically by default. V2 struct fields are
+emitted in order they are defined. For example:
+
+```go
+type S struct {
+ B string
+ A string
+}
+
+data := S{
+ B: "B",
+ A: "A",
+}
+
+b, _ := tomlv1.Marshal(data)
+fmt.Println("v1:\n" + string(b))
+
+b, _ = tomlv2.Marshal(data)
+fmt.Println("v2:\n" + string(b))
+
+// Output:
+// v1:
+// A = "A"
+// B = "B"
+
+// v2:
+// B = 'B'
+// A = 'A'
+```
+
+There is no way to make v2 encoder behave like v1. A workaround could be to
+manually sort the fields alphabetically in the struct definition, or generate
+struct types using `reflect.StructOf`.
+
+#### No indentation by default
+
+V1 automatically indents content of tables by default. V2 does not. However the
+same behavior can be obtained using [`Encoder.SetIndentTables`][sit]. For example:
+
+```go
+data := map[string]interface{}{
+ "table": map[string]string{
+ "key": "value",
+ },
+}
+
+b, _ := tomlv1.Marshal(data)
+fmt.Println("v1:\n" + string(b))
+
+b, _ = tomlv2.Marshal(data)
+fmt.Println("v2:\n" + string(b))
+
+buf := bytes.Buffer{}
+enc := tomlv2.NewEncoder(&buf)
+enc.SetIndentTables(true)
+enc.Encode(data)
+fmt.Println("v2 Encoder:\n" + string(buf.Bytes()))
+
+// Output:
+// v1:
+//
+// [table]
+// key = "value"
+//
+// v2:
+// [table]
+// key = 'value'
+//
+//
+// v2 Encoder:
+// [table]
+// key = 'value'
+```
+
+[sit]: https://pkg.go.dev/github.com/pelletier/go-toml/v2#Encoder.SetIndentTables
+
+#### Keys and strings are single quoted
+
+V1 always uses double quotes (`"`) around strings and keys that cannot be
+represented bare (unquoted). V2 uses single quotes instead by default (`'`),
+unless a character cannot be represented, then falls back to double quotes. As a
+result of this change, `Encoder.QuoteMapKeys` has been removed, as it is not
+useful anymore.
+
+There is no way to make v2 encoder behave like v1.
+
+#### `TextMarshaler` emits as a string, not TOML
+
+Types that implement [`encoding.TextMarshaler`][tm] can emit arbitrary TOML in
+v1. The encoder would append the result to the output directly. In v2 the result
+is wrapped in a string. As a result, this interface cannot be implemented by the
+root object.
+
+There is no way to make v2 encoder behave like v1.
+
+[tm]: https://golang.org/pkg/encoding/#TextMarshaler
+
+#### `Encoder.CompactComments` has been removed
+
+Emitting compact comments is now the default behavior of go-toml. This option
+is not necessary anymore.
+
+#### Struct tags have been merged
+
+V1 used to provide multiple struct tags: `comment`, `commented`, `multiline`,
+`toml`, and `omitempty`. To behave more like the standard library, v2 has merged
+`toml`, `multiline`, and `omitempty`. For example:
+
+```go
+type doc struct {
+ // v1
+ F string `toml:"field" multiline:"true" omitempty:"true"`
+ // v2
+ F string `toml:"field,multiline,omitempty"`
+}
+```
+
+Has a result, the `Encoder.SetTag*` methods have been removed, as there is just
+one tag now.
+
+
+#### `commented` tag has been removed
+
+There is no replacement for the `commented` tag. This feature would be better
+suited in a proper document model for go-toml v2, which has been [cut from
+scope][nodoc] at the moment.
+
+#### `Encoder.ArraysWithOneElementPerLine` has been renamed
+
+The new name is `Encoder.SetArraysMultiline`. The behavior should be the same.
+
+#### `Encoder.Indentation` has been renamed
+
+The new name is `Encoder.SetIndentSymbol`. The behavior should be the same.
+
+
+#### Embedded structs behave like stdlib
+
+V1 defaults to merging embedded struct fields into the embedding struct. This
+behavior was unexpected because it does not follow the standard library. To
+avoid breaking backward compatibility, the `Encoder.PromoteAnonymous` method was
+added to make the encoder behave correctly. Given backward compatibility is not
+a problem anymore, v2 does the right thing by default: it follows the behavior
+of `encoding/json`. `Encoder.PromoteAnonymous` has been removed.
+
+[nodoc]: https://github.com/pelletier/go-toml/discussions/506#discussioncomment-1526038
+
+### `query`
+
+go-toml v1 provided the [`go-toml/query`][query] package. It allowed to run
+JSONPath-style queries on TOML files. This feature is not available in v2. For a
+replacement, check out [dasel][dasel].
+
+This package has been removed because it was essentially not supported anymore
+(last commit May 2020), increased the complexity of the code base, and more
+complete solutions exist out there.
+
+[query]: https://github.com/pelletier/go-toml/tree/f99d6bbca119636aeafcf351ee52b3d202782627/query
+[dasel]: https://github.com/TomWright/dasel
+
+## Versioning
+
+Go-toml follows [Semantic Versioning](https://semver.org). The supported version
+of [TOML](https://github.com/toml-lang/toml) is indicated at the beginning of
+this document. The last two major versions of Go are supported
+(see [Go Release Policy](https://golang.org/doc/devel/release.html#policy)).
+
+## License
+
+The MIT License (MIT). Read [LICENSE](LICENSE).
diff --git a/vendor/github.com/pelletier/go-toml/v2/SECURITY.md b/vendor/github.com/pelletier/go-toml/v2/SECURITY.md
new file mode 100644
index 000000000..b2f21cfc9
--- /dev/null
+++ b/vendor/github.com/pelletier/go-toml/v2/SECURITY.md
@@ -0,0 +1,19 @@
+# Security Policy
+
+## Supported Versions
+
+Use this section to tell people about which versions of your project are
+currently being supported with security updates.
+
+| Version | Supported |
+| ---------- | ------------------ |
+| Latest 2.x | :white_check_mark: |
+| All 1.x | :x: |
+| All 0.x | :x: |
+
+## Reporting a Vulnerability
+
+Email a vulnerability report to `security@pelletier.codes`. Make sure to include
+as many details as possible to reproduce the vulnerability. This is a
+side-project: I will try to get back to you as quickly as possible, time
+permitting in my personal life. Providing a working patch helps very much!
diff --git a/vendor/github.com/pelletier/go-toml/v2/ci.sh b/vendor/github.com/pelletier/go-toml/v2/ci.sh
new file mode 100644
index 000000000..05c76f297
--- /dev/null
+++ b/vendor/github.com/pelletier/go-toml/v2/ci.sh
@@ -0,0 +1,279 @@
+#!/usr/bin/env bash
+
+
+stderr() {
+ echo "$@" 1>&2
+}
+
+usage() {
+ b=$(basename "$0")
+ echo $b: ERROR: "$@" 1>&2
+
+ cat 1>&2 < coverage.out
+ go tool cover -func=coverage.out
+ popd
+
+ if [ "${branch}" != "HEAD" ]; then
+ git worktree remove --force "$dir"
+ fi
+}
+
+coverage() {
+ case "$1" in
+ -d)
+ shift
+ target="${1?Need to provide a target branch argument}"
+
+ output_dir="$(mktemp -d)"
+ target_out="${output_dir}/target.txt"
+ head_out="${output_dir}/head.txt"
+
+ cover "${target}" > "${target_out}"
+ cover "HEAD" > "${head_out}"
+
+ cat "${target_out}"
+ cat "${head_out}"
+
+ echo ""
+
+ target_pct="$(tail -n2 ${target_out} | head -n1 | sed -E 's/.*total.*\t([0-9.]+)%.*/\1/')"
+ head_pct="$(tail -n2 ${head_out} | head -n1 | sed -E 's/.*total.*\t([0-9.]+)%/\1/')"
+ echo "Results: ${target} ${target_pct}% HEAD ${head_pct}%"
+
+ delta_pct=$(echo "$head_pct - $target_pct" | bc -l)
+ echo "Delta: ${delta_pct}"
+
+ if [[ $delta_pct = \-* ]]; then
+ echo "Regression!";
+
+ target_diff="${output_dir}/target.diff.txt"
+ head_diff="${output_dir}/head.diff.txt"
+ cat "${target_out}" | grep -E '^github.com/pelletier/go-toml' | tr -s "\t " | cut -f 2,3 | sort > "${target_diff}"
+ cat "${head_out}" | grep -E '^github.com/pelletier/go-toml' | tr -s "\t " | cut -f 2,3 | sort > "${head_diff}"
+
+ diff --side-by-side --suppress-common-lines "${target_diff}" "${head_diff}"
+ return 1
+ fi
+ return 0
+ ;;
+ esac
+
+ cover "${1-HEAD}"
+}
+
+bench() {
+ branch="${1}"
+ out="${2}"
+ replace="${3}"
+ dir="$(mktemp -d)"
+
+ stderr "Executing benchmark for ${branch} at ${dir}"
+
+ if [ "${branch}" = "HEAD" ]; then
+ cp -r . "${dir}/"
+ else
+ git worktree add "$dir" "$branch"
+ fi
+
+ pushd "$dir"
+
+ if [ "${replace}" != "" ]; then
+ find ./benchmark/ -iname '*.go' -exec sed -i -E "s|github.com/pelletier/go-toml/v2|${replace}|g" {} \;
+ go get "${replace}"
+ fi
+
+ export GOMAXPROCS=2
+ nice -n -19 taskset --cpu-list 0,1 go test '-bench=^Benchmark(Un)?[mM]arshal' -count=5 -run=Nothing ./... | tee "${out}"
+ popd
+
+ if [ "${branch}" != "HEAD" ]; then
+ git worktree remove --force "$dir"
+ fi
+}
+
+fmktemp() {
+ if mktemp --version|grep GNU >/dev/null; then
+ mktemp --suffix=-$1;
+ else
+ mktemp -t $1;
+ fi
+}
+
+benchstathtml() {
+python3 - $1 <<'EOF'
+import sys
+
+lines = []
+stop = False
+
+with open(sys.argv[1]) as f:
+ for line in f.readlines():
+ line = line.strip()
+ if line == "":
+ stop = True
+ if not stop:
+ lines.append(line.split(','))
+
+results = []
+for line in reversed(lines[1:]):
+ v2 = float(line[1])
+ results.append([
+ line[0].replace("-32", ""),
+ "%.1fx" % (float(line[3])/v2), # v1
+ "%.1fx" % (float(line[5])/v2), # bs
+ ])
+# move geomean to the end
+results.append(results[0])
+del results[0]
+
+
+def printtable(data):
+ print("""
+
+
+ Benchmark | go-toml v1 | BurntSushi/toml |
+
+ """)
+
+ for r in data:
+ print(" {} | {} | {} |
".format(*r))
+
+ print("""
+
""")
+
+
+def match(x):
+ return "ReferenceFile" in x[0] or "HugoFrontMatter" in x[0]
+
+above = [x for x in results if match(x)]
+below = [x for x in results if not match(x)]
+
+printtable(above)
+print("See more
")
+print("""The table above has the results of the most common use-cases. The table below
+contains the results of all benchmarks, including unrealistic ones. It is
+provided for completeness.
""")
+printtable(below)
+print('This table can be generated with ./ci.sh benchmark -a -html
.
')
+print(" ")
+
+EOF
+}
+
+benchmark() {
+ case "$1" in
+ -d)
+ shift
+ target="${1?Need to provide a target branch argument}"
+
+ old=`fmktemp ${target}`
+ bench "${target}" "${old}"
+
+ new=`fmktemp HEAD`
+ bench HEAD "${new}"
+
+ benchstat "${old}" "${new}"
+ return 0
+ ;;
+ -a)
+ shift
+
+ v2stats=`fmktemp go-toml-v2`
+ bench HEAD "${v2stats}" "github.com/pelletier/go-toml/v2"
+ v1stats=`fmktemp go-toml-v1`
+ bench HEAD "${v1stats}" "github.com/pelletier/go-toml"
+ bsstats=`fmktemp bs-toml`
+ bench HEAD "${bsstats}" "github.com/BurntSushi/toml"
+
+ cp "${v2stats}" go-toml-v2.txt
+ cp "${v1stats}" go-toml-v1.txt
+ cp "${bsstats}" bs-toml.txt
+
+ if [ "$1" = "-html" ]; then
+ tmpcsv=`fmktemp csv`
+ benchstat -csv -geomean go-toml-v2.txt go-toml-v1.txt bs-toml.txt > $tmpcsv
+ benchstathtml $tmpcsv
+ else
+ benchstat -geomean go-toml-v2.txt go-toml-v1.txt bs-toml.txt
+ fi
+
+ rm -f go-toml-v2.txt go-toml-v1.txt bs-toml.txt
+ return $?
+ esac
+
+ bench "${1-HEAD}" `mktemp`
+}
+
+case "$1" in
+ coverage) shift; coverage $@;;
+ benchmark) shift; benchmark $@;;
+ *) usage "bad argument $1";;
+esac
diff --git a/vendor/github.com/pelletier/go-toml/v2/decode.go b/vendor/github.com/pelletier/go-toml/v2/decode.go
new file mode 100644
index 000000000..3a860d0f6
--- /dev/null
+++ b/vendor/github.com/pelletier/go-toml/v2/decode.go
@@ -0,0 +1,550 @@
+package toml
+
+import (
+ "fmt"
+ "math"
+ "strconv"
+ "time"
+
+ "github.com/pelletier/go-toml/v2/unstable"
+)
+
+func parseInteger(b []byte) (int64, error) {
+ if len(b) > 2 && b[0] == '0' {
+ switch b[1] {
+ case 'x':
+ return parseIntHex(b)
+ case 'b':
+ return parseIntBin(b)
+ case 'o':
+ return parseIntOct(b)
+ default:
+ panic(fmt.Errorf("invalid base '%c', should have been checked by scanIntOrFloat", b[1]))
+ }
+ }
+
+ return parseIntDec(b)
+}
+
+func parseLocalDate(b []byte) (LocalDate, error) {
+ // full-date = date-fullyear "-" date-month "-" date-mday
+ // date-fullyear = 4DIGIT
+ // date-month = 2DIGIT ; 01-12
+ // date-mday = 2DIGIT ; 01-28, 01-29, 01-30, 01-31 based on month/year
+ var date LocalDate
+
+ if len(b) != 10 || b[4] != '-' || b[7] != '-' {
+ return date, unstable.NewParserError(b, "dates are expected to have the format YYYY-MM-DD")
+ }
+
+ var err error
+
+ date.Year, err = parseDecimalDigits(b[0:4])
+ if err != nil {
+ return LocalDate{}, err
+ }
+
+ date.Month, err = parseDecimalDigits(b[5:7])
+ if err != nil {
+ return LocalDate{}, err
+ }
+
+ date.Day, err = parseDecimalDigits(b[8:10])
+ if err != nil {
+ return LocalDate{}, err
+ }
+
+ if !isValidDate(date.Year, date.Month, date.Day) {
+ return LocalDate{}, unstable.NewParserError(b, "impossible date")
+ }
+
+ return date, nil
+}
+
+func parseDecimalDigits(b []byte) (int, error) {
+ v := 0
+
+ for i, c := range b {
+ if c < '0' || c > '9' {
+ return 0, unstable.NewParserError(b[i:i+1], "expected digit (0-9)")
+ }
+ v *= 10
+ v += int(c - '0')
+ }
+
+ return v, nil
+}
+
+func parseDateTime(b []byte) (time.Time, error) {
+ // offset-date-time = full-date time-delim full-time
+ // full-time = partial-time time-offset
+ // time-offset = "Z" / time-numoffset
+ // time-numoffset = ( "+" / "-" ) time-hour ":" time-minute
+
+ dt, b, err := parseLocalDateTime(b)
+ if err != nil {
+ return time.Time{}, err
+ }
+
+ var zone *time.Location
+
+ if len(b) == 0 {
+ // parser should have checked that when assigning the date time node
+ panic("date time should have a timezone")
+ }
+
+ if b[0] == 'Z' || b[0] == 'z' {
+ b = b[1:]
+ zone = time.UTC
+ } else {
+ const dateTimeByteLen = 6
+ if len(b) != dateTimeByteLen {
+ return time.Time{}, unstable.NewParserError(b, "invalid date-time timezone")
+ }
+ var direction int
+ switch b[0] {
+ case '-':
+ direction = -1
+ case '+':
+ direction = +1
+ default:
+ return time.Time{}, unstable.NewParserError(b[:1], "invalid timezone offset character")
+ }
+
+ if b[3] != ':' {
+ return time.Time{}, unstable.NewParserError(b[3:4], "expected a : separator")
+ }
+
+ hours, err := parseDecimalDigits(b[1:3])
+ if err != nil {
+ return time.Time{}, err
+ }
+ if hours > 23 {
+ return time.Time{}, unstable.NewParserError(b[:1], "invalid timezone offset hours")
+ }
+
+ minutes, err := parseDecimalDigits(b[4:6])
+ if err != nil {
+ return time.Time{}, err
+ }
+ if minutes > 59 {
+ return time.Time{}, unstable.NewParserError(b[:1], "invalid timezone offset minutes")
+ }
+
+ seconds := direction * (hours*3600 + minutes*60)
+ if seconds == 0 {
+ zone = time.UTC
+ } else {
+ zone = time.FixedZone("", seconds)
+ }
+ b = b[dateTimeByteLen:]
+ }
+
+ if len(b) > 0 {
+ return time.Time{}, unstable.NewParserError(b, "extra bytes at the end of the timezone")
+ }
+
+ t := time.Date(
+ dt.Year,
+ time.Month(dt.Month),
+ dt.Day,
+ dt.Hour,
+ dt.Minute,
+ dt.Second,
+ dt.Nanosecond,
+ zone)
+
+ return t, nil
+}
+
+func parseLocalDateTime(b []byte) (LocalDateTime, []byte, error) {
+ var dt LocalDateTime
+
+ const localDateTimeByteMinLen = 11
+ if len(b) < localDateTimeByteMinLen {
+ return dt, nil, unstable.NewParserError(b, "local datetimes are expected to have the format YYYY-MM-DDTHH:MM:SS[.NNNNNNNNN]")
+ }
+
+ date, err := parseLocalDate(b[:10])
+ if err != nil {
+ return dt, nil, err
+ }
+ dt.LocalDate = date
+
+ sep := b[10]
+ if sep != 'T' && sep != ' ' && sep != 't' {
+ return dt, nil, unstable.NewParserError(b[10:11], "datetime separator is expected to be T or a space")
+ }
+
+ t, rest, err := parseLocalTime(b[11:])
+ if err != nil {
+ return dt, nil, err
+ }
+ dt.LocalTime = t
+
+ return dt, rest, nil
+}
+
+// parseLocalTime is a bit different because it also returns the remaining
+// []byte that is didn't need. This is to allow parseDateTime to parse those
+// remaining bytes as a timezone.
+func parseLocalTime(b []byte) (LocalTime, []byte, error) {
+ var (
+ nspow = [10]int{0, 1e8, 1e7, 1e6, 1e5, 1e4, 1e3, 1e2, 1e1, 1e0}
+ t LocalTime
+ )
+
+ // check if b matches to have expected format HH:MM:SS[.NNNNNN]
+ const localTimeByteLen = 8
+ if len(b) < localTimeByteLen {
+ return t, nil, unstable.NewParserError(b, "times are expected to have the format HH:MM:SS[.NNNNNN]")
+ }
+
+ var err error
+
+ t.Hour, err = parseDecimalDigits(b[0:2])
+ if err != nil {
+ return t, nil, err
+ }
+
+ if t.Hour > 23 {
+ return t, nil, unstable.NewParserError(b[0:2], "hour cannot be greater 23")
+ }
+ if b[2] != ':' {
+ return t, nil, unstable.NewParserError(b[2:3], "expecting colon between hours and minutes")
+ }
+
+ t.Minute, err = parseDecimalDigits(b[3:5])
+ if err != nil {
+ return t, nil, err
+ }
+ if t.Minute > 59 {
+ return t, nil, unstable.NewParserError(b[3:5], "minutes cannot be greater 59")
+ }
+ if b[5] != ':' {
+ return t, nil, unstable.NewParserError(b[5:6], "expecting colon between minutes and seconds")
+ }
+
+ t.Second, err = parseDecimalDigits(b[6:8])
+ if err != nil {
+ return t, nil, err
+ }
+
+ if t.Second > 60 {
+ return t, nil, unstable.NewParserError(b[6:8], "seconds cannot be greater 60")
+ }
+
+ b = b[8:]
+
+ if len(b) >= 1 && b[0] == '.' {
+ frac := 0
+ precision := 0
+ digits := 0
+
+ for i, c := range b[1:] {
+ if !isDigit(c) {
+ if i == 0 {
+ return t, nil, unstable.NewParserError(b[0:1], "need at least one digit after fraction point")
+ }
+ break
+ }
+ digits++
+
+ const maxFracPrecision = 9
+ if i >= maxFracPrecision {
+ // go-toml allows decoding fractional seconds
+ // beyond the supported precision of 9
+ // digits. It truncates the fractional component
+ // to the supported precision and ignores the
+ // remaining digits.
+ //
+ // https://github.com/pelletier/go-toml/discussions/707
+ continue
+ }
+
+ frac *= 10
+ frac += int(c - '0')
+ precision++
+ }
+
+ if precision == 0 {
+ return t, nil, unstable.NewParserError(b[:1], "nanoseconds need at least one digit")
+ }
+
+ t.Nanosecond = frac * nspow[precision]
+ t.Precision = precision
+
+ return t, b[1+digits:], nil
+ }
+ return t, b, nil
+}
+
+//nolint:cyclop
+func parseFloat(b []byte) (float64, error) {
+ if len(b) == 4 && (b[0] == '+' || b[0] == '-') && b[1] == 'n' && b[2] == 'a' && b[3] == 'n' {
+ return math.NaN(), nil
+ }
+
+ cleaned, err := checkAndRemoveUnderscoresFloats(b)
+ if err != nil {
+ return 0, err
+ }
+
+ if cleaned[0] == '.' {
+ return 0, unstable.NewParserError(b, "float cannot start with a dot")
+ }
+
+ if cleaned[len(cleaned)-1] == '.' {
+ return 0, unstable.NewParserError(b, "float cannot end with a dot")
+ }
+
+ dotAlreadySeen := false
+ for i, c := range cleaned {
+ if c == '.' {
+ if dotAlreadySeen {
+ return 0, unstable.NewParserError(b[i:i+1], "float can have at most one decimal point")
+ }
+ if !isDigit(cleaned[i-1]) {
+ return 0, unstable.NewParserError(b[i-1:i+1], "float decimal point must be preceded by a digit")
+ }
+ if !isDigit(cleaned[i+1]) {
+ return 0, unstable.NewParserError(b[i:i+2], "float decimal point must be followed by a digit")
+ }
+ dotAlreadySeen = true
+ }
+ }
+
+ start := 0
+ if cleaned[0] == '+' || cleaned[0] == '-' {
+ start = 1
+ }
+ if cleaned[start] == '0' && isDigit(cleaned[start+1]) {
+ return 0, unstable.NewParserError(b, "float integer part cannot have leading zeroes")
+ }
+
+ f, err := strconv.ParseFloat(string(cleaned), 64)
+ if err != nil {
+ return 0, unstable.NewParserError(b, "unable to parse float: %w", err)
+ }
+
+ return f, nil
+}
+
+func parseIntHex(b []byte) (int64, error) {
+ cleaned, err := checkAndRemoveUnderscoresIntegers(b[2:])
+ if err != nil {
+ return 0, err
+ }
+
+ i, err := strconv.ParseInt(string(cleaned), 16, 64)
+ if err != nil {
+ return 0, unstable.NewParserError(b, "couldn't parse hexadecimal number: %w", err)
+ }
+
+ return i, nil
+}
+
+func parseIntOct(b []byte) (int64, error) {
+ cleaned, err := checkAndRemoveUnderscoresIntegers(b[2:])
+ if err != nil {
+ return 0, err
+ }
+
+ i, err := strconv.ParseInt(string(cleaned), 8, 64)
+ if err != nil {
+ return 0, unstable.NewParserError(b, "couldn't parse octal number: %w", err)
+ }
+
+ return i, nil
+}
+
+func parseIntBin(b []byte) (int64, error) {
+ cleaned, err := checkAndRemoveUnderscoresIntegers(b[2:])
+ if err != nil {
+ return 0, err
+ }
+
+ i, err := strconv.ParseInt(string(cleaned), 2, 64)
+ if err != nil {
+ return 0, unstable.NewParserError(b, "couldn't parse binary number: %w", err)
+ }
+
+ return i, nil
+}
+
+func isSign(b byte) bool {
+ return b == '+' || b == '-'
+}
+
+func parseIntDec(b []byte) (int64, error) {
+ cleaned, err := checkAndRemoveUnderscoresIntegers(b)
+ if err != nil {
+ return 0, err
+ }
+
+ startIdx := 0
+
+ if isSign(cleaned[0]) {
+ startIdx++
+ }
+
+ if len(cleaned) > startIdx+1 && cleaned[startIdx] == '0' {
+ return 0, unstable.NewParserError(b, "leading zero not allowed on decimal number")
+ }
+
+ i, err := strconv.ParseInt(string(cleaned), 10, 64)
+ if err != nil {
+ return 0, unstable.NewParserError(b, "couldn't parse decimal number: %w", err)
+ }
+
+ return i, nil
+}
+
+func checkAndRemoveUnderscoresIntegers(b []byte) ([]byte, error) {
+ start := 0
+ if b[start] == '+' || b[start] == '-' {
+ start++
+ }
+
+ if len(b) == start {
+ return b, nil
+ }
+
+ if b[start] == '_' {
+ return nil, unstable.NewParserError(b[start:start+1], "number cannot start with underscore")
+ }
+
+ if b[len(b)-1] == '_' {
+ return nil, unstable.NewParserError(b[len(b)-1:], "number cannot end with underscore")
+ }
+
+ // fast path
+ i := 0
+ for ; i < len(b); i++ {
+ if b[i] == '_' {
+ break
+ }
+ }
+ if i == len(b) {
+ return b, nil
+ }
+
+ before := false
+ cleaned := make([]byte, i, len(b))
+ copy(cleaned, b)
+
+ for i++; i < len(b); i++ {
+ c := b[i]
+ if c == '_' {
+ if !before {
+ return nil, unstable.NewParserError(b[i-1:i+1], "number must have at least one digit between underscores")
+ }
+ before = false
+ } else {
+ before = true
+ cleaned = append(cleaned, c)
+ }
+ }
+
+ return cleaned, nil
+}
+
+func checkAndRemoveUnderscoresFloats(b []byte) ([]byte, error) {
+ if b[0] == '_' {
+ return nil, unstable.NewParserError(b[0:1], "number cannot start with underscore")
+ }
+
+ if b[len(b)-1] == '_' {
+ return nil, unstable.NewParserError(b[len(b)-1:], "number cannot end with underscore")
+ }
+
+ // fast path
+ i := 0
+ for ; i < len(b); i++ {
+ if b[i] == '_' {
+ break
+ }
+ }
+ if i == len(b) {
+ return b, nil
+ }
+
+ before := false
+ cleaned := make([]byte, 0, len(b))
+
+ for i := 0; i < len(b); i++ {
+ c := b[i]
+
+ switch c {
+ case '_':
+ if !before {
+ return nil, unstable.NewParserError(b[i-1:i+1], "number must have at least one digit between underscores")
+ }
+ if i < len(b)-1 && (b[i+1] == 'e' || b[i+1] == 'E') {
+ return nil, unstable.NewParserError(b[i+1:i+2], "cannot have underscore before exponent")
+ }
+ before = false
+ case '+', '-':
+ // signed exponents
+ cleaned = append(cleaned, c)
+ before = false
+ case 'e', 'E':
+ if i < len(b)-1 && b[i+1] == '_' {
+ return nil, unstable.NewParserError(b[i+1:i+2], "cannot have underscore after exponent")
+ }
+ cleaned = append(cleaned, c)
+ case '.':
+ if i < len(b)-1 && b[i+1] == '_' {
+ return nil, unstable.NewParserError(b[i+1:i+2], "cannot have underscore after decimal point")
+ }
+ if i > 0 && b[i-1] == '_' {
+ return nil, unstable.NewParserError(b[i-1:i], "cannot have underscore before decimal point")
+ }
+ cleaned = append(cleaned, c)
+ default:
+ before = true
+ cleaned = append(cleaned, c)
+ }
+ }
+
+ return cleaned, nil
+}
+
+// isValidDate checks if a provided date is a date that exists.
+func isValidDate(year int, month int, day int) bool {
+ return month > 0 && month < 13 && day > 0 && day <= daysIn(month, year)
+}
+
+// daysBefore[m] counts the number of days in a non-leap year
+// before month m begins. There is an entry for m=12, counting
+// the number of days before January of next year (365).
+var daysBefore = [...]int32{
+ 0,
+ 31,
+ 31 + 28,
+ 31 + 28 + 31,
+ 31 + 28 + 31 + 30,
+ 31 + 28 + 31 + 30 + 31,
+ 31 + 28 + 31 + 30 + 31 + 30,
+ 31 + 28 + 31 + 30 + 31 + 30 + 31,
+ 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31,
+ 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
+ 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
+ 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30,
+ 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31,
+}
+
+func daysIn(m int, year int) int {
+ if m == 2 && isLeap(year) {
+ return 29
+ }
+ return int(daysBefore[m] - daysBefore[m-1])
+}
+
+func isLeap(year int) bool {
+ return year%4 == 0 && (year%100 != 0 || year%400 == 0)
+}
+
+func isDigit(r byte) bool {
+ return r >= '0' && r <= '9'
+}
diff --git a/vendor/github.com/pelletier/go-toml/v2/doc.go b/vendor/github.com/pelletier/go-toml/v2/doc.go
new file mode 100644
index 000000000..b7bc599bd
--- /dev/null
+++ b/vendor/github.com/pelletier/go-toml/v2/doc.go
@@ -0,0 +1,2 @@
+// Package toml is a library to read and write TOML documents.
+package toml
diff --git a/vendor/github.com/pelletier/go-toml/v2/errors.go b/vendor/github.com/pelletier/go-toml/v2/errors.go
new file mode 100644
index 000000000..309733f1f
--- /dev/null
+++ b/vendor/github.com/pelletier/go-toml/v2/errors.go
@@ -0,0 +1,252 @@
+package toml
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+
+ "github.com/pelletier/go-toml/v2/internal/danger"
+ "github.com/pelletier/go-toml/v2/unstable"
+)
+
+// DecodeError represents an error encountered during the parsing or decoding
+// of a TOML document.
+//
+// In addition to the error message, it contains the position in the document
+// where it happened, as well as a human-readable representation that shows
+// where the error occurred in the document.
+type DecodeError struct {
+ message string
+ line int
+ column int
+ key Key
+
+ human string
+}
+
+// StrictMissingError occurs in a TOML document that does not have a
+// corresponding field in the target value. It contains all the missing fields
+// in Errors.
+//
+// Emitted by Decoder when DisallowUnknownFields() was called.
+type StrictMissingError struct {
+ // One error per field that could not be found.
+ Errors []DecodeError
+}
+
+// Error returns the canonical string for this error.
+func (s *StrictMissingError) Error() string {
+ return "strict mode: fields in the document are missing in the target struct"
+}
+
+// String returns a human readable description of all errors.
+func (s *StrictMissingError) String() string {
+ var buf strings.Builder
+
+ for i, e := range s.Errors {
+ if i > 0 {
+ buf.WriteString("\n---\n")
+ }
+
+ buf.WriteString(e.String())
+ }
+
+ return buf.String()
+}
+
+type Key []string
+
+// Error returns the error message contained in the DecodeError.
+func (e *DecodeError) Error() string {
+ return "toml: " + e.message
+}
+
+// String returns the human-readable contextualized error. This string is multi-line.
+func (e *DecodeError) String() string {
+ return e.human
+}
+
+// Position returns the (line, column) pair indicating where the error
+// occurred in the document. Positions are 1-indexed.
+func (e *DecodeError) Position() (row int, column int) {
+ return e.line, e.column
+}
+
+// Key that was being processed when the error occurred. The key is present only
+// if this DecodeError is part of a StrictMissingError.
+func (e *DecodeError) Key() Key {
+ return e.key
+}
+
+// decodeErrorFromHighlight creates a DecodeError referencing a highlighted
+// range of bytes from document.
+//
+// highlight needs to be a sub-slice of document, or this function panics.
+//
+// The function copies all bytes used in DecodeError, so that document and
+// highlight can be freely deallocated.
+//
+//nolint:funlen
+func wrapDecodeError(document []byte, de *unstable.ParserError) *DecodeError {
+ offset := danger.SubsliceOffset(document, de.Highlight)
+
+ errMessage := de.Error()
+ errLine, errColumn := positionAtEnd(document[:offset])
+ before, after := linesOfContext(document, de.Highlight, offset, 3)
+
+ var buf strings.Builder
+
+ maxLine := errLine + len(after) - 1
+ lineColumnWidth := len(strconv.Itoa(maxLine))
+
+ // Write the lines of context strictly before the error.
+ for i := len(before) - 1; i > 0; i-- {
+ line := errLine - i
+ buf.WriteString(formatLineNumber(line, lineColumnWidth))
+ buf.WriteString("|")
+
+ if len(before[i]) > 0 {
+ buf.WriteString(" ")
+ buf.Write(before[i])
+ }
+
+ buf.WriteRune('\n')
+ }
+
+ // Write the document line that contains the error.
+
+ buf.WriteString(formatLineNumber(errLine, lineColumnWidth))
+ buf.WriteString("| ")
+
+ if len(before) > 0 {
+ buf.Write(before[0])
+ }
+
+ buf.Write(de.Highlight)
+
+ if len(after) > 0 {
+ buf.Write(after[0])
+ }
+
+ buf.WriteRune('\n')
+
+ // Write the line with the error message itself (so it does not have a line
+ // number).
+
+ buf.WriteString(strings.Repeat(" ", lineColumnWidth))
+ buf.WriteString("| ")
+
+ if len(before) > 0 {
+ buf.WriteString(strings.Repeat(" ", len(before[0])))
+ }
+
+ buf.WriteString(strings.Repeat("~", len(de.Highlight)))
+
+ if len(errMessage) > 0 {
+ buf.WriteString(" ")
+ buf.WriteString(errMessage)
+ }
+
+ // Write the lines of context strictly after the error.
+
+ for i := 1; i < len(after); i++ {
+ buf.WriteRune('\n')
+ line := errLine + i
+ buf.WriteString(formatLineNumber(line, lineColumnWidth))
+ buf.WriteString("|")
+
+ if len(after[i]) > 0 {
+ buf.WriteString(" ")
+ buf.Write(after[i])
+ }
+ }
+
+ return &DecodeError{
+ message: errMessage,
+ line: errLine,
+ column: errColumn,
+ key: de.Key,
+ human: buf.String(),
+ }
+}
+
+func formatLineNumber(line int, width int) string {
+ format := "%" + strconv.Itoa(width) + "d"
+
+ return fmt.Sprintf(format, line)
+}
+
+func linesOfContext(document []byte, highlight []byte, offset int, linesAround int) ([][]byte, [][]byte) {
+ return beforeLines(document, offset, linesAround), afterLines(document, highlight, offset, linesAround)
+}
+
+func beforeLines(document []byte, offset int, linesAround int) [][]byte {
+ var beforeLines [][]byte
+
+ // Walk the document backward from the highlight to find previous lines
+ // of context.
+ rest := document[:offset]
+backward:
+ for o := len(rest) - 1; o >= 0 && len(beforeLines) <= linesAround && len(rest) > 0; {
+ switch {
+ case rest[o] == '\n':
+ // handle individual lines
+ beforeLines = append(beforeLines, rest[o+1:])
+ rest = rest[:o]
+ o = len(rest) - 1
+ case o == 0:
+ // add the first line only if it's non-empty
+ beforeLines = append(beforeLines, rest)
+
+ break backward
+ default:
+ o--
+ }
+ }
+
+ return beforeLines
+}
+
+func afterLines(document []byte, highlight []byte, offset int, linesAround int) [][]byte {
+ var afterLines [][]byte
+
+ // Walk the document forward from the highlight to find the following
+ // lines of context.
+ rest := document[offset+len(highlight):]
+forward:
+ for o := 0; o < len(rest) && len(afterLines) <= linesAround; {
+ switch {
+ case rest[o] == '\n':
+ // handle individual lines
+ afterLines = append(afterLines, rest[:o])
+ rest = rest[o+1:]
+ o = 0
+
+ case o == len(rest)-1:
+ // add last line only if it's non-empty
+ afterLines = append(afterLines, rest)
+
+ break forward
+ default:
+ o++
+ }
+ }
+
+ return afterLines
+}
+
+func positionAtEnd(b []byte) (row int, column int) {
+ row = 1
+ column = 1
+
+ for _, c := range b {
+ if c == '\n' {
+ row++
+ column = 1
+ } else {
+ column++
+ }
+ }
+
+ return
+}
diff --git a/vendor/github.com/pelletier/go-toml/v2/internal/characters/ascii.go b/vendor/github.com/pelletier/go-toml/v2/internal/characters/ascii.go
new file mode 100644
index 000000000..80f698db4
--- /dev/null
+++ b/vendor/github.com/pelletier/go-toml/v2/internal/characters/ascii.go
@@ -0,0 +1,42 @@
+package characters
+
+var invalidAsciiTable = [256]bool{
+ 0x00: true,
+ 0x01: true,
+ 0x02: true,
+ 0x03: true,
+ 0x04: true,
+ 0x05: true,
+ 0x06: true,
+ 0x07: true,
+ 0x08: true,
+ // 0x09 TAB
+ // 0x0A LF
+ 0x0B: true,
+ 0x0C: true,
+ // 0x0D CR
+ 0x0E: true,
+ 0x0F: true,
+ 0x10: true,
+ 0x11: true,
+ 0x12: true,
+ 0x13: true,
+ 0x14: true,
+ 0x15: true,
+ 0x16: true,
+ 0x17: true,
+ 0x18: true,
+ 0x19: true,
+ 0x1A: true,
+ 0x1B: true,
+ 0x1C: true,
+ 0x1D: true,
+ 0x1E: true,
+ 0x1F: true,
+ // 0x20 - 0x7E Printable ASCII characters
+ 0x7F: true,
+}
+
+func InvalidAscii(b byte) bool {
+ return invalidAsciiTable[b]
+}
diff --git a/vendor/github.com/pelletier/go-toml/v2/internal/characters/utf8.go b/vendor/github.com/pelletier/go-toml/v2/internal/characters/utf8.go
new file mode 100644
index 000000000..db4f45acb
--- /dev/null
+++ b/vendor/github.com/pelletier/go-toml/v2/internal/characters/utf8.go
@@ -0,0 +1,199 @@
+package characters
+
+import (
+ "unicode/utf8"
+)
+
+type utf8Err struct {
+ Index int
+ Size int
+}
+
+func (u utf8Err) Zero() bool {
+ return u.Size == 0
+}
+
+// Verified that a given string is only made of valid UTF-8 characters allowed
+// by the TOML spec:
+//
+// Any Unicode character may be used except those that must be escaped:
+// quotation mark, backslash, and the control characters other than tab (U+0000
+// to U+0008, U+000A to U+001F, U+007F).
+//
+// It is a copy of the Go 1.17 utf8.Valid implementation, tweaked to exit early
+// when a character is not allowed.
+//
+// The returned utf8Err is Zero() if the string is valid, or contains the byte
+// index and size of the invalid character.
+//
+// quotation mark => already checked
+// backslash => already checked
+// 0-0x8 => invalid
+// 0x9 => tab, ok
+// 0xA - 0x1F => invalid
+// 0x7F => invalid
+func Utf8TomlValidAlreadyEscaped(p []byte) (err utf8Err) {
+ // Fast path. Check for and skip 8 bytes of ASCII characters per iteration.
+ offset := 0
+ for len(p) >= 8 {
+ // Combining two 32 bit loads allows the same code to be used
+ // for 32 and 64 bit platforms.
+ // The compiler can generate a 32bit load for first32 and second32
+ // on many platforms. See test/codegen/memcombine.go.
+ first32 := uint32(p[0]) | uint32(p[1])<<8 | uint32(p[2])<<16 | uint32(p[3])<<24
+ second32 := uint32(p[4]) | uint32(p[5])<<8 | uint32(p[6])<<16 | uint32(p[7])<<24
+ if (first32|second32)&0x80808080 != 0 {
+ // Found a non ASCII byte (>= RuneSelf).
+ break
+ }
+
+ for i, b := range p[:8] {
+ if InvalidAscii(b) {
+ err.Index = offset + i
+ err.Size = 1
+ return
+ }
+ }
+
+ p = p[8:]
+ offset += 8
+ }
+ n := len(p)
+ for i := 0; i < n; {
+ pi := p[i]
+ if pi < utf8.RuneSelf {
+ if InvalidAscii(pi) {
+ err.Index = offset + i
+ err.Size = 1
+ return
+ }
+ i++
+ continue
+ }
+ x := first[pi]
+ if x == xx {
+ // Illegal starter byte.
+ err.Index = offset + i
+ err.Size = 1
+ return
+ }
+ size := int(x & 7)
+ if i+size > n {
+ // Short or invalid.
+ err.Index = offset + i
+ err.Size = n - i
+ return
+ }
+ accept := acceptRanges[x>>4]
+ if c := p[i+1]; c < accept.lo || accept.hi < c {
+ err.Index = offset + i
+ err.Size = 2
+ return
+ } else if size == 2 {
+ } else if c := p[i+2]; c < locb || hicb < c {
+ err.Index = offset + i
+ err.Size = 3
+ return
+ } else if size == 3 {
+ } else if c := p[i+3]; c < locb || hicb < c {
+ err.Index = offset + i
+ err.Size = 4
+ return
+ }
+ i += size
+ }
+ return
+}
+
+// Return the size of the next rune if valid, 0 otherwise.
+func Utf8ValidNext(p []byte) int {
+ c := p[0]
+
+ if c < utf8.RuneSelf {
+ if InvalidAscii(c) {
+ return 0
+ }
+ return 1
+ }
+
+ x := first[c]
+ if x == xx {
+ // Illegal starter byte.
+ return 0
+ }
+ size := int(x & 7)
+ if size > len(p) {
+ // Short or invalid.
+ return 0
+ }
+ accept := acceptRanges[x>>4]
+ if c := p[1]; c < accept.lo || accept.hi < c {
+ return 0
+ } else if size == 2 {
+ } else if c := p[2]; c < locb || hicb < c {
+ return 0
+ } else if size == 3 {
+ } else if c := p[3]; c < locb || hicb < c {
+ return 0
+ }
+
+ return size
+}
+
+// acceptRange gives the range of valid values for the second byte in a UTF-8
+// sequence.
+type acceptRange struct {
+ lo uint8 // lowest value for second byte.
+ hi uint8 // highest value for second byte.
+}
+
+// acceptRanges has size 16 to avoid bounds checks in the code that uses it.
+var acceptRanges = [16]acceptRange{
+ 0: {locb, hicb},
+ 1: {0xA0, hicb},
+ 2: {locb, 0x9F},
+ 3: {0x90, hicb},
+ 4: {locb, 0x8F},
+}
+
+// first is information about the first byte in a UTF-8 sequence.
+var first = [256]uint8{
+ // 1 2 3 4 5 6 7 8 9 A B C D E F
+ as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x00-0x0F
+ as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x10-0x1F
+ as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x20-0x2F
+ as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x30-0x3F
+ as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x40-0x4F
+ as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x50-0x5F
+ as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x60-0x6F
+ as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, as, // 0x70-0x7F
+ // 1 2 3 4 5 6 7 8 9 A B C D E F
+ xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, // 0x80-0x8F
+ xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, // 0x90-0x9F
+ xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, // 0xA0-0xAF
+ xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, // 0xB0-0xBF
+ xx, xx, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, // 0xC0-0xCF
+ s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, s1, // 0xD0-0xDF
+ s2, s3, s3, s3, s3, s3, s3, s3, s3, s3, s3, s3, s3, s4, s3, s3, // 0xE0-0xEF
+ s5, s6, s6, s6, s7, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, xx, // 0xF0-0xFF
+}
+
+const (
+ // The default lowest and highest continuation byte.
+ locb = 0b10000000
+ hicb = 0b10111111
+
+ // These names of these constants are chosen to give nice alignment in the
+ // table below. The first nibble is an index into acceptRanges or F for
+ // special one-byte cases. The second nibble is the Rune length or the
+ // Status for the special one-byte case.
+ xx = 0xF1 // invalid: size 1
+ as = 0xF0 // ASCII: size 1
+ s1 = 0x02 // accept 0, size 2
+ s2 = 0x13 // accept 1, size 3
+ s3 = 0x03 // accept 0, size 3
+ s4 = 0x23 // accept 2, size 3
+ s5 = 0x34 // accept 3, size 4
+ s6 = 0x04 // accept 0, size 4
+ s7 = 0x44 // accept 4, size 4
+)
diff --git a/vendor/github.com/pelletier/go-toml/v2/internal/danger/danger.go b/vendor/github.com/pelletier/go-toml/v2/internal/danger/danger.go
new file mode 100644
index 000000000..e38e1131b
--- /dev/null
+++ b/vendor/github.com/pelletier/go-toml/v2/internal/danger/danger.go
@@ -0,0 +1,65 @@
+package danger
+
+import (
+ "fmt"
+ "reflect"
+ "unsafe"
+)
+
+const maxInt = uintptr(int(^uint(0) >> 1))
+
+func SubsliceOffset(data []byte, subslice []byte) int {
+ datap := (*reflect.SliceHeader)(unsafe.Pointer(&data))
+ hlp := (*reflect.SliceHeader)(unsafe.Pointer(&subslice))
+
+ if hlp.Data < datap.Data {
+ panic(fmt.Errorf("subslice address (%d) is before data address (%d)", hlp.Data, datap.Data))
+ }
+ offset := hlp.Data - datap.Data
+
+ if offset > maxInt {
+ panic(fmt.Errorf("slice offset larger than int (%d)", offset))
+ }
+
+ intoffset := int(offset)
+
+ if intoffset > datap.Len {
+ panic(fmt.Errorf("slice offset (%d) is farther than data length (%d)", intoffset, datap.Len))
+ }
+
+ if intoffset+hlp.Len > datap.Len {
+ panic(fmt.Errorf("slice ends (%d+%d) is farther than data length (%d)", intoffset, hlp.Len, datap.Len))
+ }
+
+ return intoffset
+}
+
+func BytesRange(start []byte, end []byte) []byte {
+ if start == nil || end == nil {
+ panic("cannot call BytesRange with nil")
+ }
+ startp := (*reflect.SliceHeader)(unsafe.Pointer(&start))
+ endp := (*reflect.SliceHeader)(unsafe.Pointer(&end))
+
+ if startp.Data > endp.Data {
+ panic(fmt.Errorf("start pointer address (%d) is after end pointer address (%d)", startp.Data, endp.Data))
+ }
+
+ l := startp.Len
+ endLen := int(endp.Data-startp.Data) + endp.Len
+ if endLen > l {
+ l = endLen
+ }
+
+ if l > startp.Cap {
+ panic(fmt.Errorf("range length is larger than capacity"))
+ }
+
+ return start[:l]
+}
+
+func Stride(ptr unsafe.Pointer, size uintptr, offset int) unsafe.Pointer {
+ // TODO: replace with unsafe.Add when Go 1.17 is released
+ // https://github.com/golang/go/issues/40481
+ return unsafe.Pointer(uintptr(ptr) + uintptr(int(size)*offset))
+}
diff --git a/vendor/github.com/pelletier/go-toml/v2/internal/danger/typeid.go b/vendor/github.com/pelletier/go-toml/v2/internal/danger/typeid.go
new file mode 100644
index 000000000..9d41c28a2
--- /dev/null
+++ b/vendor/github.com/pelletier/go-toml/v2/internal/danger/typeid.go
@@ -0,0 +1,23 @@
+package danger
+
+import (
+ "reflect"
+ "unsafe"
+)
+
+// typeID is used as key in encoder and decoder caches to enable using
+// the optimize runtime.mapaccess2_fast64 function instead of the more
+// expensive lookup if we were to use reflect.Type as map key.
+//
+// typeID holds the pointer to the reflect.Type value, which is unique
+// in the program.
+//
+// https://github.com/segmentio/encoding/blob/master/json/codec.go#L59-L61
+type TypeID unsafe.Pointer
+
+func MakeTypeID(t reflect.Type) TypeID {
+ // reflect.Type has the fields:
+ // typ unsafe.Pointer
+ // ptr unsafe.Pointer
+ return TypeID((*[2]unsafe.Pointer)(unsafe.Pointer(&t))[1])
+}
diff --git a/vendor/github.com/pelletier/go-toml/v2/internal/tracker/key.go b/vendor/github.com/pelletier/go-toml/v2/internal/tracker/key.go
new file mode 100644
index 000000000..149b17f53
--- /dev/null
+++ b/vendor/github.com/pelletier/go-toml/v2/internal/tracker/key.go
@@ -0,0 +1,48 @@
+package tracker
+
+import "github.com/pelletier/go-toml/v2/unstable"
+
+// KeyTracker is a tracker that keeps track of the current Key as the AST is
+// walked.
+type KeyTracker struct {
+ k []string
+}
+
+// UpdateTable sets the state of the tracker with the AST table node.
+func (t *KeyTracker) UpdateTable(node *unstable.Node) {
+ t.reset()
+ t.Push(node)
+}
+
+// UpdateArrayTable sets the state of the tracker with the AST array table node.
+func (t *KeyTracker) UpdateArrayTable(node *unstable.Node) {
+ t.reset()
+ t.Push(node)
+}
+
+// Push the given key on the stack.
+func (t *KeyTracker) Push(node *unstable.Node) {
+ it := node.Key()
+ for it.Next() {
+ t.k = append(t.k, string(it.Node().Data))
+ }
+}
+
+// Pop key from stack.
+func (t *KeyTracker) Pop(node *unstable.Node) {
+ it := node.Key()
+ for it.Next() {
+ t.k = t.k[:len(t.k)-1]
+ }
+}
+
+// Key returns the current key
+func (t *KeyTracker) Key() []string {
+ k := make([]string, len(t.k))
+ copy(k, t.k)
+ return k
+}
+
+func (t *KeyTracker) reset() {
+ t.k = t.k[:0]
+}
diff --git a/vendor/github.com/pelletier/go-toml/v2/internal/tracker/seen.go b/vendor/github.com/pelletier/go-toml/v2/internal/tracker/seen.go
new file mode 100644
index 000000000..40e23f830
--- /dev/null
+++ b/vendor/github.com/pelletier/go-toml/v2/internal/tracker/seen.go
@@ -0,0 +1,356 @@
+package tracker
+
+import (
+ "bytes"
+ "fmt"
+ "sync"
+
+ "github.com/pelletier/go-toml/v2/unstable"
+)
+
+type keyKind uint8
+
+const (
+ invalidKind keyKind = iota
+ valueKind
+ tableKind
+ arrayTableKind
+)
+
+func (k keyKind) String() string {
+ switch k {
+ case invalidKind:
+ return "invalid"
+ case valueKind:
+ return "value"
+ case tableKind:
+ return "table"
+ case arrayTableKind:
+ return "array table"
+ }
+ panic("missing keyKind string mapping")
+}
+
+// SeenTracker tracks which keys have been seen with which TOML type to flag
+// duplicates and mismatches according to the spec.
+//
+// Each node in the visited tree is represented by an entry. Each entry has an
+// identifier, which is provided by a counter. Entries are stored in the array
+// entries. As new nodes are discovered (referenced for the first time in the
+// TOML document), entries are created and appended to the array. An entry
+// points to its parent using its id.
+//
+// To find whether a given key (sequence of []byte) has already been visited,
+// the entries are linearly searched, looking for one with the right name and
+// parent id.
+//
+// Given that all keys appear in the document after their parent, it is
+// guaranteed that all descendants of a node are stored after the node, this
+// speeds up the search process.
+//
+// When encountering [[array tables]], the descendants of that node are removed
+// to allow that branch of the tree to be "rediscovered". To maintain the
+// invariant above, the deletion process needs to keep the order of entries.
+// This results in more copies in that case.
+type SeenTracker struct {
+ entries []entry
+ currentIdx int
+}
+
+var pool sync.Pool
+
+func (s *SeenTracker) reset() {
+ // Always contains a root element at index 0.
+ s.currentIdx = 0
+ if len(s.entries) == 0 {
+ s.entries = make([]entry, 1, 2)
+ } else {
+ s.entries = s.entries[:1]
+ }
+ s.entries[0].child = -1
+ s.entries[0].next = -1
+}
+
+type entry struct {
+ // Use -1 to indicate no child or no sibling.
+ child int
+ next int
+
+ name []byte
+ kind keyKind
+ explicit bool
+ kv bool
+}
+
+// Find the index of the child of parentIdx with key k. Returns -1 if
+// it does not exist.
+func (s *SeenTracker) find(parentIdx int, k []byte) int {
+ for i := s.entries[parentIdx].child; i >= 0; i = s.entries[i].next {
+ if bytes.Equal(s.entries[i].name, k) {
+ return i
+ }
+ }
+ return -1
+}
+
+// Remove all descendants of node at position idx.
+func (s *SeenTracker) clear(idx int) {
+ if idx >= len(s.entries) {
+ return
+ }
+
+ for i := s.entries[idx].child; i >= 0; {
+ next := s.entries[i].next
+ n := s.entries[0].next
+ s.entries[0].next = i
+ s.entries[i].next = n
+ s.entries[i].name = nil
+ s.clear(i)
+ i = next
+ }
+
+ s.entries[idx].child = -1
+}
+
+func (s *SeenTracker) create(parentIdx int, name []byte, kind keyKind, explicit bool, kv bool) int {
+ e := entry{
+ child: -1,
+ next: s.entries[parentIdx].child,
+
+ name: name,
+ kind: kind,
+ explicit: explicit,
+ kv: kv,
+ }
+ var idx int
+ if s.entries[0].next >= 0 {
+ idx = s.entries[0].next
+ s.entries[0].next = s.entries[idx].next
+ s.entries[idx] = e
+ } else {
+ idx = len(s.entries)
+ s.entries = append(s.entries, e)
+ }
+
+ s.entries[parentIdx].child = idx
+
+ return idx
+}
+
+func (s *SeenTracker) setExplicitFlag(parentIdx int) {
+ for i := s.entries[parentIdx].child; i >= 0; i = s.entries[i].next {
+ if s.entries[i].kv {
+ s.entries[i].explicit = true
+ s.entries[i].kv = false
+ }
+ s.setExplicitFlag(i)
+ }
+}
+
+// CheckExpression takes a top-level node and checks that it does not contain
+// keys that have been seen in previous calls, and validates that types are
+// consistent.
+func (s *SeenTracker) CheckExpression(node *unstable.Node) error {
+ if s.entries == nil {
+ s.reset()
+ }
+ switch node.Kind {
+ case unstable.KeyValue:
+ return s.checkKeyValue(node)
+ case unstable.Table:
+ return s.checkTable(node)
+ case unstable.ArrayTable:
+ return s.checkArrayTable(node)
+ default:
+ panic(fmt.Errorf("this should not be a top level node type: %s", node.Kind))
+ }
+}
+
+func (s *SeenTracker) checkTable(node *unstable.Node) error {
+ if s.currentIdx >= 0 {
+ s.setExplicitFlag(s.currentIdx)
+ }
+
+ it := node.Key()
+
+ parentIdx := 0
+
+ // This code is duplicated in checkArrayTable. This is because factoring
+ // it in a function requires to copy the iterator, or allocate it to the
+ // heap, which is not cheap.
+ for it.Next() {
+ if it.IsLast() {
+ break
+ }
+
+ k := it.Node().Data
+
+ idx := s.find(parentIdx, k)
+
+ if idx < 0 {
+ idx = s.create(parentIdx, k, tableKind, false, false)
+ } else {
+ entry := s.entries[idx]
+ if entry.kind == valueKind {
+ return fmt.Errorf("toml: expected %s to be a table, not a %s", string(k), entry.kind)
+ }
+ }
+ parentIdx = idx
+ }
+
+ k := it.Node().Data
+ idx := s.find(parentIdx, k)
+
+ if idx >= 0 {
+ kind := s.entries[idx].kind
+ if kind != tableKind {
+ return fmt.Errorf("toml: key %s should be a table, not a %s", string(k), kind)
+ }
+ if s.entries[idx].explicit {
+ return fmt.Errorf("toml: table %s already exists", string(k))
+ }
+ s.entries[idx].explicit = true
+ } else {
+ idx = s.create(parentIdx, k, tableKind, true, false)
+ }
+
+ s.currentIdx = idx
+
+ return nil
+}
+
+func (s *SeenTracker) checkArrayTable(node *unstable.Node) error {
+ if s.currentIdx >= 0 {
+ s.setExplicitFlag(s.currentIdx)
+ }
+
+ it := node.Key()
+
+ parentIdx := 0
+
+ for it.Next() {
+ if it.IsLast() {
+ break
+ }
+
+ k := it.Node().Data
+
+ idx := s.find(parentIdx, k)
+
+ if idx < 0 {
+ idx = s.create(parentIdx, k, tableKind, false, false)
+ } else {
+ entry := s.entries[idx]
+ if entry.kind == valueKind {
+ return fmt.Errorf("toml: expected %s to be a table, not a %s", string(k), entry.kind)
+ }
+ }
+
+ parentIdx = idx
+ }
+
+ k := it.Node().Data
+ idx := s.find(parentIdx, k)
+
+ if idx >= 0 {
+ kind := s.entries[idx].kind
+ if kind != arrayTableKind {
+ return fmt.Errorf("toml: key %s already exists as a %s, but should be an array table", kind, string(k))
+ }
+ s.clear(idx)
+ } else {
+ idx = s.create(parentIdx, k, arrayTableKind, true, false)
+ }
+
+ s.currentIdx = idx
+
+ return nil
+}
+
+func (s *SeenTracker) checkKeyValue(node *unstable.Node) error {
+ parentIdx := s.currentIdx
+ it := node.Key()
+
+ for it.Next() {
+ k := it.Node().Data
+
+ idx := s.find(parentIdx, k)
+
+ if idx < 0 {
+ idx = s.create(parentIdx, k, tableKind, false, true)
+ } else {
+ entry := s.entries[idx]
+ if it.IsLast() {
+ return fmt.Errorf("toml: key %s is already defined", string(k))
+ } else if entry.kind != tableKind {
+ return fmt.Errorf("toml: expected %s to be a table, not a %s", string(k), entry.kind)
+ } else if entry.explicit {
+ return fmt.Errorf("toml: cannot redefine table %s that has already been explicitly defined", string(k))
+ }
+ }
+
+ parentIdx = idx
+ }
+
+ s.entries[parentIdx].kind = valueKind
+
+ value := node.Value()
+
+ switch value.Kind {
+ case unstable.InlineTable:
+ return s.checkInlineTable(value)
+ case unstable.Array:
+ return s.checkArray(value)
+ }
+
+ return nil
+}
+
+func (s *SeenTracker) checkArray(node *unstable.Node) error {
+ it := node.Children()
+ for it.Next() {
+ n := it.Node()
+ switch n.Kind {
+ case unstable.InlineTable:
+ err := s.checkInlineTable(n)
+ if err != nil {
+ return err
+ }
+ case unstable.Array:
+ err := s.checkArray(n)
+ if err != nil {
+ return err
+ }
+ }
+ }
+ return nil
+}
+
+func (s *SeenTracker) checkInlineTable(node *unstable.Node) error {
+ if pool.New == nil {
+ pool.New = func() interface{} {
+ return &SeenTracker{}
+ }
+ }
+
+ s = pool.Get().(*SeenTracker)
+ s.reset()
+
+ it := node.Children()
+ for it.Next() {
+ n := it.Node()
+ err := s.checkKeyValue(n)
+ if err != nil {
+ return err
+ }
+ }
+
+ // As inline tables are self-contained, the tracker does not
+ // need to retain the details of what they contain. The
+ // keyValue element that creates the inline table is kept to
+ // mark the presence of the inline table and prevent
+ // redefinition of its keys: check* functions cannot walk into
+ // a value.
+ pool.Put(s)
+ return nil
+}
diff --git a/vendor/github.com/pelletier/go-toml/v2/internal/tracker/tracker.go b/vendor/github.com/pelletier/go-toml/v2/internal/tracker/tracker.go
new file mode 100644
index 000000000..bf0317392
--- /dev/null
+++ b/vendor/github.com/pelletier/go-toml/v2/internal/tracker/tracker.go
@@ -0,0 +1 @@
+package tracker
diff --git a/vendor/github.com/pelletier/go-toml/v2/localtime.go b/vendor/github.com/pelletier/go-toml/v2/localtime.go
new file mode 100644
index 000000000..a856bfdb0
--- /dev/null
+++ b/vendor/github.com/pelletier/go-toml/v2/localtime.go
@@ -0,0 +1,122 @@
+package toml
+
+import (
+ "fmt"
+ "strings"
+ "time"
+
+ "github.com/pelletier/go-toml/v2/unstable"
+)
+
+// LocalDate represents a calendar day in no specific timezone.
+type LocalDate struct {
+ Year int
+ Month int
+ Day int
+}
+
+// AsTime converts d into a specific time instance at midnight in zone.
+func (d LocalDate) AsTime(zone *time.Location) time.Time {
+ return time.Date(d.Year, time.Month(d.Month), d.Day, 0, 0, 0, 0, zone)
+}
+
+// String returns RFC 3339 representation of d.
+func (d LocalDate) String() string {
+ return fmt.Sprintf("%04d-%02d-%02d", d.Year, d.Month, d.Day)
+}
+
+// MarshalText returns RFC 3339 representation of d.
+func (d LocalDate) MarshalText() ([]byte, error) {
+ return []byte(d.String()), nil
+}
+
+// UnmarshalText parses b using RFC 3339 to fill d.
+func (d *LocalDate) UnmarshalText(b []byte) error {
+ res, err := parseLocalDate(b)
+ if err != nil {
+ return err
+ }
+ *d = res
+ return nil
+}
+
+// LocalTime represents a time of day of no specific day in no specific
+// timezone.
+type LocalTime struct {
+ Hour int // Hour of the day: [0; 24[
+ Minute int // Minute of the hour: [0; 60[
+ Second int // Second of the minute: [0; 60[
+ Nanosecond int // Nanoseconds within the second: [0, 1000000000[
+ Precision int // Number of digits to display for Nanosecond.
+}
+
+// String returns RFC 3339 representation of d.
+// If d.Nanosecond and d.Precision are zero, the time won't have a nanosecond
+// component. If d.Nanosecond > 0 but d.Precision = 0, then the minimum number
+// of digits for nanoseconds is provided.
+func (d LocalTime) String() string {
+ s := fmt.Sprintf("%02d:%02d:%02d", d.Hour, d.Minute, d.Second)
+
+ if d.Precision > 0 {
+ s += fmt.Sprintf(".%09d", d.Nanosecond)[:d.Precision+1]
+ } else if d.Nanosecond > 0 {
+ // Nanoseconds are specified, but precision is not provided. Use the
+ // minimum.
+ s += strings.Trim(fmt.Sprintf(".%09d", d.Nanosecond), "0")
+ }
+
+ return s
+}
+
+// MarshalText returns RFC 3339 representation of d.
+func (d LocalTime) MarshalText() ([]byte, error) {
+ return []byte(d.String()), nil
+}
+
+// UnmarshalText parses b using RFC 3339 to fill d.
+func (d *LocalTime) UnmarshalText(b []byte) error {
+ res, left, err := parseLocalTime(b)
+ if err == nil && len(left) != 0 {
+ err = unstable.NewParserError(left, "extra characters")
+ }
+ if err != nil {
+ return err
+ }
+ *d = res
+ return nil
+}
+
+// LocalDateTime represents a time of a specific day in no specific timezone.
+type LocalDateTime struct {
+ LocalDate
+ LocalTime
+}
+
+// AsTime converts d into a specific time instance in zone.
+func (d LocalDateTime) AsTime(zone *time.Location) time.Time {
+ return time.Date(d.Year, time.Month(d.Month), d.Day, d.Hour, d.Minute, d.Second, d.Nanosecond, zone)
+}
+
+// String returns RFC 3339 representation of d.
+func (d LocalDateTime) String() string {
+ return d.LocalDate.String() + "T" + d.LocalTime.String()
+}
+
+// MarshalText returns RFC 3339 representation of d.
+func (d LocalDateTime) MarshalText() ([]byte, error) {
+ return []byte(d.String()), nil
+}
+
+// UnmarshalText parses b using RFC 3339 to fill d.
+func (d *LocalDateTime) UnmarshalText(data []byte) error {
+ res, left, err := parseLocalDateTime(data)
+ if err == nil && len(left) != 0 {
+ err = unstable.NewParserError(left, "extra characters")
+ }
+ if err != nil {
+ return err
+ }
+
+ *d = res
+ return nil
+}
diff --git a/vendor/github.com/pelletier/go-toml/v2/marshaler.go b/vendor/github.com/pelletier/go-toml/v2/marshaler.go
new file mode 100644
index 000000000..6ab1d8238
--- /dev/null
+++ b/vendor/github.com/pelletier/go-toml/v2/marshaler.go
@@ -0,0 +1,1058 @@
+package toml
+
+import (
+ "bytes"
+ "encoding"
+ "fmt"
+ "io"
+ "math"
+ "reflect"
+ "sort"
+ "strconv"
+ "strings"
+ "time"
+ "unicode"
+
+ "github.com/pelletier/go-toml/v2/internal/characters"
+)
+
+// Marshal serializes a Go value as a TOML document.
+//
+// It is a shortcut for Encoder.Encode() with the default options.
+func Marshal(v interface{}) ([]byte, error) {
+ var buf bytes.Buffer
+ enc := NewEncoder(&buf)
+
+ err := enc.Encode(v)
+ if err != nil {
+ return nil, err
+ }
+
+ return buf.Bytes(), nil
+}
+
+// Encoder writes a TOML document to an output stream.
+type Encoder struct {
+ // output
+ w io.Writer
+
+ // global settings
+ tablesInline bool
+ arraysMultiline bool
+ indentSymbol string
+ indentTables bool
+}
+
+// NewEncoder returns a new Encoder that writes to w.
+func NewEncoder(w io.Writer) *Encoder {
+ return &Encoder{
+ w: w,
+ indentSymbol: " ",
+ }
+}
+
+// SetTablesInline forces the encoder to emit all tables inline.
+//
+// This behavior can be controlled on an individual struct field basis with the
+// inline tag:
+//
+// MyField `toml:",inline"`
+func (enc *Encoder) SetTablesInline(inline bool) *Encoder {
+ enc.tablesInline = inline
+ return enc
+}
+
+// SetArraysMultiline forces the encoder to emit all arrays with one element per
+// line.
+//
+// This behavior can be controlled on an individual struct field basis with the multiline tag:
+//
+// MyField `multiline:"true"`
+func (enc *Encoder) SetArraysMultiline(multiline bool) *Encoder {
+ enc.arraysMultiline = multiline
+ return enc
+}
+
+// SetIndentSymbol defines the string that should be used for indentation. The
+// provided string is repeated for each indentation level. Defaults to two
+// spaces.
+func (enc *Encoder) SetIndentSymbol(s string) *Encoder {
+ enc.indentSymbol = s
+ return enc
+}
+
+// SetIndentTables forces the encoder to intent tables and array tables.
+func (enc *Encoder) SetIndentTables(indent bool) *Encoder {
+ enc.indentTables = indent
+ return enc
+}
+
+// Encode writes a TOML representation of v to the stream.
+//
+// If v cannot be represented to TOML it returns an error.
+//
+// # Encoding rules
+//
+// A top level slice containing only maps or structs is encoded as [[table
+// array]].
+//
+// All slices not matching rule 1 are encoded as [array]. As a result, any map
+// or struct they contain is encoded as an {inline table}.
+//
+// Nil interfaces and nil pointers are not supported.
+//
+// Keys in key-values always have one part.
+//
+// Intermediate tables are always printed.
+//
+// By default, strings are encoded as literal string, unless they contain either
+// a newline character or a single quote. In that case they are emitted as
+// quoted strings.
+//
+// Unsigned integers larger than math.MaxInt64 cannot be encoded. Doing so
+// results in an error. This rule exists because the TOML specification only
+// requires parsers to support at least the 64 bits integer range. Allowing
+// larger numbers would create non-standard TOML documents, which may not be
+// readable (at best) by other implementations. To encode such numbers, a
+// solution is a custom type that implements encoding.TextMarshaler.
+//
+// When encoding structs, fields are encoded in order of definition, with their
+// exact name.
+//
+// Tables and array tables are separated by empty lines. However, consecutive
+// subtables definitions are not. For example:
+//
+// [top1]
+//
+// [top2]
+// [top2.child1]
+//
+// [[array]]
+//
+// [[array]]
+// [array.child2]
+//
+// # Struct tags
+//
+// The encoding of each public struct field can be customized by the format
+// string in the "toml" key of the struct field's tag. This follows
+// encoding/json's convention. The format string starts with the name of the
+// field, optionally followed by a comma-separated list of options. The name may
+// be empty in order to provide options without overriding the default name.
+//
+// The "multiline" option emits strings as quoted multi-line TOML strings. It
+// has no effect on fields that would not be encoded as strings.
+//
+// The "inline" option turns fields that would be emitted as tables into inline
+// tables instead. It has no effect on other fields.
+//
+// The "omitempty" option prevents empty values or groups from being emitted.
+//
+// In addition to the "toml" tag struct tag, a "comment" tag can be used to emit
+// a TOML comment before the value being annotated. Comments are ignored inside
+// inline tables. For array tables, the comment is only present before the first
+// element of the array.
+func (enc *Encoder) Encode(v interface{}) error {
+ var (
+ b []byte
+ ctx encoderCtx
+ )
+
+ ctx.inline = enc.tablesInline
+
+ if v == nil {
+ return fmt.Errorf("toml: cannot encode a nil interface")
+ }
+
+ b, err := enc.encode(b, ctx, reflect.ValueOf(v))
+ if err != nil {
+ return err
+ }
+
+ _, err = enc.w.Write(b)
+ if err != nil {
+ return fmt.Errorf("toml: cannot write: %w", err)
+ }
+
+ return nil
+}
+
+type valueOptions struct {
+ multiline bool
+ omitempty bool
+ comment string
+}
+
+type encoderCtx struct {
+ // Current top-level key.
+ parentKey []string
+
+ // Key that should be used for a KV.
+ key string
+ // Extra flag to account for the empty string
+ hasKey bool
+
+ // Set to true to indicate that the encoder is inside a KV, so that all
+ // tables need to be inlined.
+ insideKv bool
+
+ // Set to true to skip the first table header in an array table.
+ skipTableHeader bool
+
+ // Should the next table be encoded as inline
+ inline bool
+
+ // Indentation level
+ indent int
+
+ // Options coming from struct tags
+ options valueOptions
+}
+
+func (ctx *encoderCtx) shiftKey() {
+ if ctx.hasKey {
+ ctx.parentKey = append(ctx.parentKey, ctx.key)
+ ctx.clearKey()
+ }
+}
+
+func (ctx *encoderCtx) setKey(k string) {
+ ctx.key = k
+ ctx.hasKey = true
+}
+
+func (ctx *encoderCtx) clearKey() {
+ ctx.key = ""
+ ctx.hasKey = false
+}
+
+func (ctx *encoderCtx) isRoot() bool {
+ return len(ctx.parentKey) == 0 && !ctx.hasKey
+}
+
+func (enc *Encoder) encode(b []byte, ctx encoderCtx, v reflect.Value) ([]byte, error) {
+ i := v.Interface()
+
+ switch x := i.(type) {
+ case time.Time:
+ if x.Nanosecond() > 0 {
+ return x.AppendFormat(b, time.RFC3339Nano), nil
+ }
+ return x.AppendFormat(b, time.RFC3339), nil
+ case LocalTime:
+ return append(b, x.String()...), nil
+ case LocalDate:
+ return append(b, x.String()...), nil
+ case LocalDateTime:
+ return append(b, x.String()...), nil
+ }
+
+ hasTextMarshaler := v.Type().Implements(textMarshalerType)
+ if hasTextMarshaler || (v.CanAddr() && reflect.PtrTo(v.Type()).Implements(textMarshalerType)) {
+ if !hasTextMarshaler {
+ v = v.Addr()
+ }
+
+ if ctx.isRoot() {
+ return nil, fmt.Errorf("toml: type %s implementing the TextMarshaler interface cannot be a root element", v.Type())
+ }
+
+ text, err := v.Interface().(encoding.TextMarshaler).MarshalText()
+ if err != nil {
+ return nil, err
+ }
+
+ b = enc.encodeString(b, string(text), ctx.options)
+
+ return b, nil
+ }
+
+ switch v.Kind() {
+ // containers
+ case reflect.Map:
+ return enc.encodeMap(b, ctx, v)
+ case reflect.Struct:
+ return enc.encodeStruct(b, ctx, v)
+ case reflect.Slice:
+ return enc.encodeSlice(b, ctx, v)
+ case reflect.Interface:
+ if v.IsNil() {
+ return nil, fmt.Errorf("toml: encoding a nil interface is not supported")
+ }
+
+ return enc.encode(b, ctx, v.Elem())
+ case reflect.Ptr:
+ if v.IsNil() {
+ return enc.encode(b, ctx, reflect.Zero(v.Type().Elem()))
+ }
+
+ return enc.encode(b, ctx, v.Elem())
+
+ // values
+ case reflect.String:
+ b = enc.encodeString(b, v.String(), ctx.options)
+ case reflect.Float32:
+ f := v.Float()
+
+ if math.IsNaN(f) {
+ b = append(b, "nan"...)
+ } else if f > math.MaxFloat32 {
+ b = append(b, "inf"...)
+ } else if f < -math.MaxFloat32 {
+ b = append(b, "-inf"...)
+ } else if math.Trunc(f) == f {
+ b = strconv.AppendFloat(b, f, 'f', 1, 32)
+ } else {
+ b = strconv.AppendFloat(b, f, 'f', -1, 32)
+ }
+ case reflect.Float64:
+ f := v.Float()
+ if math.IsNaN(f) {
+ b = append(b, "nan"...)
+ } else if f > math.MaxFloat64 {
+ b = append(b, "inf"...)
+ } else if f < -math.MaxFloat64 {
+ b = append(b, "-inf"...)
+ } else if math.Trunc(f) == f {
+ b = strconv.AppendFloat(b, f, 'f', 1, 64)
+ } else {
+ b = strconv.AppendFloat(b, f, 'f', -1, 64)
+ }
+ case reflect.Bool:
+ if v.Bool() {
+ b = append(b, "true"...)
+ } else {
+ b = append(b, "false"...)
+ }
+ case reflect.Uint64, reflect.Uint32, reflect.Uint16, reflect.Uint8, reflect.Uint:
+ x := v.Uint()
+ if x > uint64(math.MaxInt64) {
+ return nil, fmt.Errorf("toml: not encoding uint (%d) greater than max int64 (%d)", x, int64(math.MaxInt64))
+ }
+ b = strconv.AppendUint(b, x, 10)
+ case reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8, reflect.Int:
+ b = strconv.AppendInt(b, v.Int(), 10)
+ default:
+ return nil, fmt.Errorf("toml: cannot encode value of type %s", v.Kind())
+ }
+
+ return b, nil
+}
+
+func isNil(v reflect.Value) bool {
+ switch v.Kind() {
+ case reflect.Ptr, reflect.Interface, reflect.Map:
+ return v.IsNil()
+ default:
+ return false
+ }
+}
+
+func shouldOmitEmpty(options valueOptions, v reflect.Value) bool {
+ return options.omitempty && isEmptyValue(v)
+}
+
+func (enc *Encoder) encodeKv(b []byte, ctx encoderCtx, options valueOptions, v reflect.Value) ([]byte, error) {
+ var err error
+
+ if !ctx.inline {
+ b = enc.encodeComment(ctx.indent, options.comment, b)
+ b = enc.indent(ctx.indent, b)
+ }
+
+ b = enc.encodeKey(b, ctx.key)
+ b = append(b, " = "...)
+
+ // create a copy of the context because the value of a KV shouldn't
+ // modify the global context.
+ subctx := ctx
+ subctx.insideKv = true
+ subctx.shiftKey()
+ subctx.options = options
+
+ b, err = enc.encode(b, subctx, v)
+ if err != nil {
+ return nil, err
+ }
+
+ return b, nil
+}
+
+func isEmptyValue(v reflect.Value) bool {
+ switch v.Kind() {
+ case reflect.Struct:
+ return isEmptyStruct(v)
+ case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
+ return v.Len() == 0
+ case reflect.Bool:
+ return !v.Bool()
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return v.Int() == 0
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ return v.Uint() == 0
+ case reflect.Float32, reflect.Float64:
+ return v.Float() == 0
+ case reflect.Interface, reflect.Ptr:
+ return v.IsNil()
+ }
+ return false
+}
+
+func isEmptyStruct(v reflect.Value) bool {
+ // TODO: merge with walkStruct and cache.
+ typ := v.Type()
+ for i := 0; i < typ.NumField(); i++ {
+ fieldType := typ.Field(i)
+
+ // only consider exported fields
+ if fieldType.PkgPath != "" {
+ continue
+ }
+
+ tag := fieldType.Tag.Get("toml")
+
+ // special field name to skip field
+ if tag == "-" {
+ continue
+ }
+
+ f := v.Field(i)
+
+ if !isEmptyValue(f) {
+ return false
+ }
+ }
+
+ return true
+}
+
+const literalQuote = '\''
+
+func (enc *Encoder) encodeString(b []byte, v string, options valueOptions) []byte {
+ if needsQuoting(v) {
+ return enc.encodeQuotedString(options.multiline, b, v)
+ }
+
+ return enc.encodeLiteralString(b, v)
+}
+
+func needsQuoting(v string) bool {
+ // TODO: vectorize
+ for _, b := range []byte(v) {
+ if b == '\'' || b == '\r' || b == '\n' || characters.InvalidAscii(b) {
+ return true
+ }
+ }
+ return false
+}
+
+// caller should have checked that the string does not contain new lines or ' .
+func (enc *Encoder) encodeLiteralString(b []byte, v string) []byte {
+ b = append(b, literalQuote)
+ b = append(b, v...)
+ b = append(b, literalQuote)
+
+ return b
+}
+
+func (enc *Encoder) encodeQuotedString(multiline bool, b []byte, v string) []byte {
+ stringQuote := `"`
+
+ if multiline {
+ stringQuote = `"""`
+ }
+
+ b = append(b, stringQuote...)
+ if multiline {
+ b = append(b, '\n')
+ }
+
+ const (
+ hextable = "0123456789ABCDEF"
+ // U+0000 to U+0008, U+000A to U+001F, U+007F
+ nul = 0x0
+ bs = 0x8
+ lf = 0xa
+ us = 0x1f
+ del = 0x7f
+ )
+
+ for _, r := range []byte(v) {
+ switch r {
+ case '\\':
+ b = append(b, `\\`...)
+ case '"':
+ b = append(b, `\"`...)
+ case '\b':
+ b = append(b, `\b`...)
+ case '\f':
+ b = append(b, `\f`...)
+ case '\n':
+ if multiline {
+ b = append(b, r)
+ } else {
+ b = append(b, `\n`...)
+ }
+ case '\r':
+ b = append(b, `\r`...)
+ case '\t':
+ b = append(b, `\t`...)
+ default:
+ switch {
+ case r >= nul && r <= bs, r >= lf && r <= us, r == del:
+ b = append(b, `\u00`...)
+ b = append(b, hextable[r>>4])
+ b = append(b, hextable[r&0x0f])
+ default:
+ b = append(b, r)
+ }
+ }
+ }
+
+ b = append(b, stringQuote...)
+
+ return b
+}
+
+// caller should have checked that the string is in A-Z / a-z / 0-9 / - / _ .
+func (enc *Encoder) encodeUnquotedKey(b []byte, v string) []byte {
+ return append(b, v...)
+}
+
+func (enc *Encoder) encodeTableHeader(ctx encoderCtx, b []byte) ([]byte, error) {
+ if len(ctx.parentKey) == 0 {
+ return b, nil
+ }
+
+ b = enc.encodeComment(ctx.indent, ctx.options.comment, b)
+
+ b = enc.indent(ctx.indent, b)
+
+ b = append(b, '[')
+
+ b = enc.encodeKey(b, ctx.parentKey[0])
+
+ for _, k := range ctx.parentKey[1:] {
+ b = append(b, '.')
+ b = enc.encodeKey(b, k)
+ }
+
+ b = append(b, "]\n"...)
+
+ return b, nil
+}
+
+//nolint:cyclop
+func (enc *Encoder) encodeKey(b []byte, k string) []byte {
+ needsQuotation := false
+ cannotUseLiteral := false
+
+ if len(k) == 0 {
+ return append(b, "''"...)
+ }
+
+ for _, c := range k {
+ if (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '-' || c == '_' {
+ continue
+ }
+
+ if c == literalQuote {
+ cannotUseLiteral = true
+ }
+
+ needsQuotation = true
+ }
+
+ if needsQuotation && needsQuoting(k) {
+ cannotUseLiteral = true
+ }
+
+ switch {
+ case cannotUseLiteral:
+ return enc.encodeQuotedString(false, b, k)
+ case needsQuotation:
+ return enc.encodeLiteralString(b, k)
+ default:
+ return enc.encodeUnquotedKey(b, k)
+ }
+}
+
+func (enc *Encoder) keyToString(k reflect.Value) (string, error) {
+ keyType := k.Type()
+ switch {
+ case keyType.Kind() == reflect.String:
+ return k.String(), nil
+
+ case keyType.Implements(textMarshalerType):
+ keyB, err := k.Interface().(encoding.TextMarshaler).MarshalText()
+ if err != nil {
+ return "", fmt.Errorf("toml: error marshalling key %v from text: %w", k, err)
+ }
+ return string(keyB), nil
+ }
+ return "", fmt.Errorf("toml: type %s is not supported as a map key", keyType.Kind())
+}
+
+func (enc *Encoder) encodeMap(b []byte, ctx encoderCtx, v reflect.Value) ([]byte, error) {
+ var (
+ t table
+ emptyValueOptions valueOptions
+ )
+
+ iter := v.MapRange()
+ for iter.Next() {
+ v := iter.Value()
+
+ if isNil(v) {
+ continue
+ }
+
+ k, err := enc.keyToString(iter.Key())
+ if err != nil {
+ return nil, err
+ }
+
+ if willConvertToTableOrArrayTable(ctx, v) {
+ t.pushTable(k, v, emptyValueOptions)
+ } else {
+ t.pushKV(k, v, emptyValueOptions)
+ }
+ }
+
+ sortEntriesByKey(t.kvs)
+ sortEntriesByKey(t.tables)
+
+ return enc.encodeTable(b, ctx, t)
+}
+
+func sortEntriesByKey(e []entry) {
+ sort.Slice(e, func(i, j int) bool {
+ return e[i].Key < e[j].Key
+ })
+}
+
+type entry struct {
+ Key string
+ Value reflect.Value
+ Options valueOptions
+}
+
+type table struct {
+ kvs []entry
+ tables []entry
+}
+
+func (t *table) pushKV(k string, v reflect.Value, options valueOptions) {
+ for _, e := range t.kvs {
+ if e.Key == k {
+ return
+ }
+ }
+
+ t.kvs = append(t.kvs, entry{Key: k, Value: v, Options: options})
+}
+
+func (t *table) pushTable(k string, v reflect.Value, options valueOptions) {
+ for _, e := range t.tables {
+ if e.Key == k {
+ return
+ }
+ }
+ t.tables = append(t.tables, entry{Key: k, Value: v, Options: options})
+}
+
+func walkStruct(ctx encoderCtx, t *table, v reflect.Value) {
+ // TODO: cache this
+ typ := v.Type()
+ for i := 0; i < typ.NumField(); i++ {
+ fieldType := typ.Field(i)
+
+ // only consider exported fields
+ if fieldType.PkgPath != "" {
+ continue
+ }
+
+ tag := fieldType.Tag.Get("toml")
+
+ // special field name to skip field
+ if tag == "-" {
+ continue
+ }
+
+ k, opts := parseTag(tag)
+ if !isValidName(k) {
+ k = ""
+ }
+
+ f := v.Field(i)
+
+ if k == "" {
+ if fieldType.Anonymous {
+ if fieldType.Type.Kind() == reflect.Struct {
+ walkStruct(ctx, t, f)
+ }
+ continue
+ } else {
+ k = fieldType.Name
+ }
+ }
+
+ if isNil(f) {
+ continue
+ }
+
+ options := valueOptions{
+ multiline: opts.multiline,
+ omitempty: opts.omitempty,
+ comment: fieldType.Tag.Get("comment"),
+ }
+
+ if opts.inline || !willConvertToTableOrArrayTable(ctx, f) {
+ t.pushKV(k, f, options)
+ } else {
+ t.pushTable(k, f, options)
+ }
+ }
+}
+
+func (enc *Encoder) encodeStruct(b []byte, ctx encoderCtx, v reflect.Value) ([]byte, error) {
+ var t table
+
+ walkStruct(ctx, &t, v)
+
+ return enc.encodeTable(b, ctx, t)
+}
+
+func (enc *Encoder) encodeComment(indent int, comment string, b []byte) []byte {
+ for len(comment) > 0 {
+ var line string
+ idx := strings.IndexByte(comment, '\n')
+ if idx >= 0 {
+ line = comment[:idx]
+ comment = comment[idx+1:]
+ } else {
+ line = comment
+ comment = ""
+ }
+ b = enc.indent(indent, b)
+ b = append(b, "# "...)
+ b = append(b, line...)
+ b = append(b, '\n')
+ }
+ return b
+}
+
+func isValidName(s string) bool {
+ if s == "" {
+ return false
+ }
+ for _, c := range s {
+ switch {
+ case strings.ContainsRune("!#$%&()*+-./:;<=>?@[]^_{|}~ ", c):
+ // Backslash and quote chars are reserved, but
+ // otherwise any punctuation chars are allowed
+ // in a tag name.
+ case !unicode.IsLetter(c) && !unicode.IsDigit(c):
+ return false
+ }
+ }
+ return true
+}
+
+type tagOptions struct {
+ multiline bool
+ inline bool
+ omitempty bool
+}
+
+func parseTag(tag string) (string, tagOptions) {
+ opts := tagOptions{}
+
+ idx := strings.Index(tag, ",")
+ if idx == -1 {
+ return tag, opts
+ }
+
+ raw := tag[idx+1:]
+ tag = string(tag[:idx])
+ for raw != "" {
+ var o string
+ i := strings.Index(raw, ",")
+ if i >= 0 {
+ o, raw = raw[:i], raw[i+1:]
+ } else {
+ o, raw = raw, ""
+ }
+ switch o {
+ case "multiline":
+ opts.multiline = true
+ case "inline":
+ opts.inline = true
+ case "omitempty":
+ opts.omitempty = true
+ }
+ }
+
+ return tag, opts
+}
+
+func (enc *Encoder) encodeTable(b []byte, ctx encoderCtx, t table) ([]byte, error) {
+ var err error
+
+ ctx.shiftKey()
+
+ if ctx.insideKv || (ctx.inline && !ctx.isRoot()) {
+ return enc.encodeTableInline(b, ctx, t)
+ }
+
+ if !ctx.skipTableHeader {
+ b, err = enc.encodeTableHeader(ctx, b)
+ if err != nil {
+ return nil, err
+ }
+
+ if enc.indentTables && len(ctx.parentKey) > 0 {
+ ctx.indent++
+ }
+ }
+ ctx.skipTableHeader = false
+
+ hasNonEmptyKV := false
+ for _, kv := range t.kvs {
+ if shouldOmitEmpty(kv.Options, kv.Value) {
+ continue
+ }
+ hasNonEmptyKV = true
+
+ ctx.setKey(kv.Key)
+
+ b, err = enc.encodeKv(b, ctx, kv.Options, kv.Value)
+ if err != nil {
+ return nil, err
+ }
+
+ b = append(b, '\n')
+ }
+
+ first := true
+ for _, table := range t.tables {
+ if shouldOmitEmpty(table.Options, table.Value) {
+ continue
+ }
+ if first {
+ first = false
+ if hasNonEmptyKV {
+ b = append(b, '\n')
+ }
+ } else {
+ b = append(b, "\n"...)
+ }
+
+ ctx.setKey(table.Key)
+
+ ctx.options = table.Options
+
+ b, err = enc.encode(b, ctx, table.Value)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ return b, nil
+}
+
+func (enc *Encoder) encodeTableInline(b []byte, ctx encoderCtx, t table) ([]byte, error) {
+ var err error
+
+ b = append(b, '{')
+
+ first := true
+ for _, kv := range t.kvs {
+ if shouldOmitEmpty(kv.Options, kv.Value) {
+ continue
+ }
+
+ if first {
+ first = false
+ } else {
+ b = append(b, `, `...)
+ }
+
+ ctx.setKey(kv.Key)
+
+ b, err = enc.encodeKv(b, ctx, kv.Options, kv.Value)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ if len(t.tables) > 0 {
+ panic("inline table cannot contain nested tables, only key-values")
+ }
+
+ b = append(b, "}"...)
+
+ return b, nil
+}
+
+func willConvertToTable(ctx encoderCtx, v reflect.Value) bool {
+ if !v.IsValid() {
+ return false
+ }
+ if v.Type() == timeType || v.Type().Implements(textMarshalerType) || (v.Kind() != reflect.Ptr && v.CanAddr() && reflect.PtrTo(v.Type()).Implements(textMarshalerType)) {
+ return false
+ }
+
+ t := v.Type()
+ switch t.Kind() {
+ case reflect.Map, reflect.Struct:
+ return !ctx.inline
+ case reflect.Interface:
+ return willConvertToTable(ctx, v.Elem())
+ case reflect.Ptr:
+ if v.IsNil() {
+ return false
+ }
+
+ return willConvertToTable(ctx, v.Elem())
+ default:
+ return false
+ }
+}
+
+func willConvertToTableOrArrayTable(ctx encoderCtx, v reflect.Value) bool {
+ if ctx.insideKv {
+ return false
+ }
+ t := v.Type()
+
+ if t.Kind() == reflect.Interface {
+ return willConvertToTableOrArrayTable(ctx, v.Elem())
+ }
+
+ if t.Kind() == reflect.Slice {
+ if v.Len() == 0 {
+ // An empty slice should be a kv = [].
+ return false
+ }
+
+ for i := 0; i < v.Len(); i++ {
+ t := willConvertToTable(ctx, v.Index(i))
+
+ if !t {
+ return false
+ }
+ }
+
+ return true
+ }
+
+ return willConvertToTable(ctx, v)
+}
+
+func (enc *Encoder) encodeSlice(b []byte, ctx encoderCtx, v reflect.Value) ([]byte, error) {
+ if v.Len() == 0 {
+ b = append(b, "[]"...)
+
+ return b, nil
+ }
+
+ if willConvertToTableOrArrayTable(ctx, v) {
+ return enc.encodeSliceAsArrayTable(b, ctx, v)
+ }
+
+ return enc.encodeSliceAsArray(b, ctx, v)
+}
+
+// caller should have checked that v is a slice that only contains values that
+// encode into tables.
+func (enc *Encoder) encodeSliceAsArrayTable(b []byte, ctx encoderCtx, v reflect.Value) ([]byte, error) {
+ ctx.shiftKey()
+
+ scratch := make([]byte, 0, 64)
+ scratch = append(scratch, "[["...)
+
+ for i, k := range ctx.parentKey {
+ if i > 0 {
+ scratch = append(scratch, '.')
+ }
+
+ scratch = enc.encodeKey(scratch, k)
+ }
+
+ scratch = append(scratch, "]]\n"...)
+ ctx.skipTableHeader = true
+
+ b = enc.encodeComment(ctx.indent, ctx.options.comment, b)
+
+ for i := 0; i < v.Len(); i++ {
+ if i != 0 {
+ b = append(b, "\n"...)
+ }
+
+ b = append(b, scratch...)
+
+ var err error
+ b, err = enc.encode(b, ctx, v.Index(i))
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ return b, nil
+}
+
+func (enc *Encoder) encodeSliceAsArray(b []byte, ctx encoderCtx, v reflect.Value) ([]byte, error) {
+ multiline := ctx.options.multiline || enc.arraysMultiline
+ separator := ", "
+
+ b = append(b, '[')
+
+ subCtx := ctx
+ subCtx.options = valueOptions{}
+
+ if multiline {
+ separator = ",\n"
+
+ b = append(b, '\n')
+
+ subCtx.indent++
+ }
+
+ var err error
+ first := true
+
+ for i := 0; i < v.Len(); i++ {
+ if first {
+ first = false
+ } else {
+ b = append(b, separator...)
+ }
+
+ if multiline {
+ b = enc.indent(subCtx.indent, b)
+ }
+
+ b, err = enc.encode(b, subCtx, v.Index(i))
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ if multiline {
+ b = append(b, '\n')
+ b = enc.indent(ctx.indent, b)
+ }
+
+ b = append(b, ']')
+
+ return b, nil
+}
+
+func (enc *Encoder) indent(level int, b []byte) []byte {
+ for i := 0; i < level; i++ {
+ b = append(b, enc.indentSymbol...)
+ }
+
+ return b
+}
diff --git a/vendor/github.com/pelletier/go-toml/v2/strict.go b/vendor/github.com/pelletier/go-toml/v2/strict.go
new file mode 100644
index 000000000..802e7e4d1
--- /dev/null
+++ b/vendor/github.com/pelletier/go-toml/v2/strict.go
@@ -0,0 +1,107 @@
+package toml
+
+import (
+ "github.com/pelletier/go-toml/v2/internal/danger"
+ "github.com/pelletier/go-toml/v2/internal/tracker"
+ "github.com/pelletier/go-toml/v2/unstable"
+)
+
+type strict struct {
+ Enabled bool
+
+ // Tracks the current key being processed.
+ key tracker.KeyTracker
+
+ missing []unstable.ParserError
+}
+
+func (s *strict) EnterTable(node *unstable.Node) {
+ if !s.Enabled {
+ return
+ }
+
+ s.key.UpdateTable(node)
+}
+
+func (s *strict) EnterArrayTable(node *unstable.Node) {
+ if !s.Enabled {
+ return
+ }
+
+ s.key.UpdateArrayTable(node)
+}
+
+func (s *strict) EnterKeyValue(node *unstable.Node) {
+ if !s.Enabled {
+ return
+ }
+
+ s.key.Push(node)
+}
+
+func (s *strict) ExitKeyValue(node *unstable.Node) {
+ if !s.Enabled {
+ return
+ }
+
+ s.key.Pop(node)
+}
+
+func (s *strict) MissingTable(node *unstable.Node) {
+ if !s.Enabled {
+ return
+ }
+
+ s.missing = append(s.missing, unstable.ParserError{
+ Highlight: keyLocation(node),
+ Message: "missing table",
+ Key: s.key.Key(),
+ })
+}
+
+func (s *strict) MissingField(node *unstable.Node) {
+ if !s.Enabled {
+ return
+ }
+
+ s.missing = append(s.missing, unstable.ParserError{
+ Highlight: keyLocation(node),
+ Message: "missing field",
+ Key: s.key.Key(),
+ })
+}
+
+func (s *strict) Error(doc []byte) error {
+ if !s.Enabled || len(s.missing) == 0 {
+ return nil
+ }
+
+ err := &StrictMissingError{
+ Errors: make([]DecodeError, 0, len(s.missing)),
+ }
+
+ for _, derr := range s.missing {
+ derr := derr
+ err.Errors = append(err.Errors, *wrapDecodeError(doc, &derr))
+ }
+
+ return err
+}
+
+func keyLocation(node *unstable.Node) []byte {
+ k := node.Key()
+
+ hasOne := k.Next()
+ if !hasOne {
+ panic("should not be called with empty key")
+ }
+
+ start := k.Node().Data
+ end := k.Node().Data
+
+ for k.Next() {
+ end = k.Node().Data
+ }
+
+ return danger.BytesRange(start, end)
+}
diff --git a/vendor/github.com/pelletier/go-toml/v2/toml.abnf b/vendor/github.com/pelletier/go-toml/v2/toml.abnf
new file mode 100644
index 000000000..473f3749e
--- /dev/null
+++ b/vendor/github.com/pelletier/go-toml/v2/toml.abnf
@@ -0,0 +1,243 @@
+;; This document describes TOML's syntax, using the ABNF format (defined in
+;; RFC 5234 -- https://www.ietf.org/rfc/rfc5234.txt).
+;;
+;; All valid TOML documents will match this description, however certain
+;; invalid documents would need to be rejected as per the semantics described
+;; in the supporting text description.
+
+;; It is possible to try this grammar interactively, using instaparse.
+;; http://instaparse.mojombo.com/
+;;
+;; To do so, in the lower right, click on Options and change `:input-format` to
+;; ':abnf'. Then paste this entire ABNF document into the grammar entry box
+;; (above the options). Then you can type or paste a sample TOML document into
+;; the beige box on the left. Tada!
+
+;; Overall Structure
+
+toml = expression *( newline expression )
+
+expression = ws [ comment ]
+expression =/ ws keyval ws [ comment ]
+expression =/ ws table ws [ comment ]
+
+;; Whitespace
+
+ws = *wschar
+wschar = %x20 ; Space
+wschar =/ %x09 ; Horizontal tab
+
+;; Newline
+
+newline = %x0A ; LF
+newline =/ %x0D.0A ; CRLF
+
+;; Comment
+
+comment-start-symbol = %x23 ; #
+non-ascii = %x80-D7FF / %xE000-10FFFF
+non-eol = %x09 / %x20-7F / non-ascii
+
+comment = comment-start-symbol *non-eol
+
+;; Key-Value pairs
+
+keyval = key keyval-sep val
+
+key = simple-key / dotted-key
+simple-key = quoted-key / unquoted-key
+
+unquoted-key = 1*( ALPHA / DIGIT / %x2D / %x5F ) ; A-Z / a-z / 0-9 / - / _
+quoted-key = basic-string / literal-string
+dotted-key = simple-key 1*( dot-sep simple-key )
+
+dot-sep = ws %x2E ws ; . Period
+keyval-sep = ws %x3D ws ; =
+
+val = string / boolean / array / inline-table / date-time / float / integer
+
+;; String
+
+string = ml-basic-string / basic-string / ml-literal-string / literal-string
+
+;; Basic String
+
+basic-string = quotation-mark *basic-char quotation-mark
+
+quotation-mark = %x22 ; "
+
+basic-char = basic-unescaped / escaped
+basic-unescaped = wschar / %x21 / %x23-5B / %x5D-7E / non-ascii
+escaped = escape escape-seq-char
+
+escape = %x5C ; \
+escape-seq-char = %x22 ; " quotation mark U+0022
+escape-seq-char =/ %x5C ; \ reverse solidus U+005C
+escape-seq-char =/ %x62 ; b backspace U+0008
+escape-seq-char =/ %x66 ; f form feed U+000C
+escape-seq-char =/ %x6E ; n line feed U+000A
+escape-seq-char =/ %x72 ; r carriage return U+000D
+escape-seq-char =/ %x74 ; t tab U+0009
+escape-seq-char =/ %x75 4HEXDIG ; uXXXX U+XXXX
+escape-seq-char =/ %x55 8HEXDIG ; UXXXXXXXX U+XXXXXXXX
+
+;; Multiline Basic String
+
+ml-basic-string = ml-basic-string-delim [ newline ] ml-basic-body
+ ml-basic-string-delim
+ml-basic-string-delim = 3quotation-mark
+ml-basic-body = *mlb-content *( mlb-quotes 1*mlb-content ) [ mlb-quotes ]
+
+mlb-content = mlb-char / newline / mlb-escaped-nl
+mlb-char = mlb-unescaped / escaped
+mlb-quotes = 1*2quotation-mark
+mlb-unescaped = wschar / %x21 / %x23-5B / %x5D-7E / non-ascii
+mlb-escaped-nl = escape ws newline *( wschar / newline )
+
+;; Literal String
+
+literal-string = apostrophe *literal-char apostrophe
+
+apostrophe = %x27 ; ' apostrophe
+
+literal-char = %x09 / %x20-26 / %x28-7E / non-ascii
+
+;; Multiline Literal String
+
+ml-literal-string = ml-literal-string-delim [ newline ] ml-literal-body
+ ml-literal-string-delim
+ml-literal-string-delim = 3apostrophe
+ml-literal-body = *mll-content *( mll-quotes 1*mll-content ) [ mll-quotes ]
+
+mll-content = mll-char / newline
+mll-char = %x09 / %x20-26 / %x28-7E / non-ascii
+mll-quotes = 1*2apostrophe
+
+;; Integer
+
+integer = dec-int / hex-int / oct-int / bin-int
+
+minus = %x2D ; -
+plus = %x2B ; +
+underscore = %x5F ; _
+digit1-9 = %x31-39 ; 1-9
+digit0-7 = %x30-37 ; 0-7
+digit0-1 = %x30-31 ; 0-1
+
+hex-prefix = %x30.78 ; 0x
+oct-prefix = %x30.6F ; 0o
+bin-prefix = %x30.62 ; 0b
+
+dec-int = [ minus / plus ] unsigned-dec-int
+unsigned-dec-int = DIGIT / digit1-9 1*( DIGIT / underscore DIGIT )
+
+hex-int = hex-prefix HEXDIG *( HEXDIG / underscore HEXDIG )
+oct-int = oct-prefix digit0-7 *( digit0-7 / underscore digit0-7 )
+bin-int = bin-prefix digit0-1 *( digit0-1 / underscore digit0-1 )
+
+;; Float
+
+float = float-int-part ( exp / frac [ exp ] )
+float =/ special-float
+
+float-int-part = dec-int
+frac = decimal-point zero-prefixable-int
+decimal-point = %x2E ; .
+zero-prefixable-int = DIGIT *( DIGIT / underscore DIGIT )
+
+exp = "e" float-exp-part
+float-exp-part = [ minus / plus ] zero-prefixable-int
+
+special-float = [ minus / plus ] ( inf / nan )
+inf = %x69.6e.66 ; inf
+nan = %x6e.61.6e ; nan
+
+;; Boolean
+
+boolean = true / false
+
+true = %x74.72.75.65 ; true
+false = %x66.61.6C.73.65 ; false
+
+;; Date and Time (as defined in RFC 3339)
+
+date-time = offset-date-time / local-date-time / local-date / local-time
+
+date-fullyear = 4DIGIT
+date-month = 2DIGIT ; 01-12
+date-mday = 2DIGIT ; 01-28, 01-29, 01-30, 01-31 based on month/year
+time-delim = "T" / %x20 ; T, t, or space
+time-hour = 2DIGIT ; 00-23
+time-minute = 2DIGIT ; 00-59
+time-second = 2DIGIT ; 00-58, 00-59, 00-60 based on leap second rules
+time-secfrac = "." 1*DIGIT
+time-numoffset = ( "+" / "-" ) time-hour ":" time-minute
+time-offset = "Z" / time-numoffset
+
+partial-time = time-hour ":" time-minute ":" time-second [ time-secfrac ]
+full-date = date-fullyear "-" date-month "-" date-mday
+full-time = partial-time time-offset
+
+;; Offset Date-Time
+
+offset-date-time = full-date time-delim full-time
+
+;; Local Date-Time
+
+local-date-time = full-date time-delim partial-time
+
+;; Local Date
+
+local-date = full-date
+
+;; Local Time
+
+local-time = partial-time
+
+;; Array
+
+array = array-open [ array-values ] ws-comment-newline array-close
+
+array-open = %x5B ; [
+array-close = %x5D ; ]
+
+array-values = ws-comment-newline val ws-comment-newline array-sep array-values
+array-values =/ ws-comment-newline val ws-comment-newline [ array-sep ]
+
+array-sep = %x2C ; , Comma
+
+ws-comment-newline = *( wschar / [ comment ] newline )
+
+;; Table
+
+table = std-table / array-table
+
+;; Standard Table
+
+std-table = std-table-open key std-table-close
+
+std-table-open = %x5B ws ; [ Left square bracket
+std-table-close = ws %x5D ; ] Right square bracket
+
+;; Inline Table
+
+inline-table = inline-table-open [ inline-table-keyvals ] inline-table-close
+
+inline-table-open = %x7B ws ; {
+inline-table-close = ws %x7D ; }
+inline-table-sep = ws %x2C ws ; , Comma
+
+inline-table-keyvals = keyval [ inline-table-sep inline-table-keyvals ]
+
+;; Array Table
+
+array-table = array-table-open key array-table-close
+
+array-table-open = %x5B.5B ws ; [[ Double left square bracket
+array-table-close = ws %x5D.5D ; ]] Double right square bracket
+
+;; Built-in ABNF terms, reproduced here for clarity
+
+ALPHA = %x41-5A / %x61-7A ; A-Z / a-z
+DIGIT = %x30-39 ; 0-9
+HEXDIG = DIGIT / "A" / "B" / "C" / "D" / "E" / "F"
diff --git a/vendor/github.com/pelletier/go-toml/v2/types.go b/vendor/github.com/pelletier/go-toml/v2/types.go
new file mode 100644
index 000000000..3c6b8fe57
--- /dev/null
+++ b/vendor/github.com/pelletier/go-toml/v2/types.go
@@ -0,0 +1,14 @@
+package toml
+
+import (
+ "encoding"
+ "reflect"
+ "time"
+)
+
+var timeType = reflect.TypeOf((*time.Time)(nil)).Elem()
+var textMarshalerType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem()
+var textUnmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem()
+var mapStringInterfaceType = reflect.TypeOf(map[string]interface{}(nil))
+var sliceInterfaceType = reflect.TypeOf([]interface{}(nil))
+var stringType = reflect.TypeOf("")
diff --git a/vendor/github.com/pelletier/go-toml/v2/unmarshaler.go b/vendor/github.com/pelletier/go-toml/v2/unmarshaler.go
new file mode 100644
index 000000000..393503431
--- /dev/null
+++ b/vendor/github.com/pelletier/go-toml/v2/unmarshaler.go
@@ -0,0 +1,1260 @@
+package toml
+
+import (
+ "encoding"
+ "errors"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "math"
+ "reflect"
+ "strings"
+ "sync/atomic"
+ "time"
+
+ "github.com/pelletier/go-toml/v2/internal/danger"
+ "github.com/pelletier/go-toml/v2/internal/tracker"
+ "github.com/pelletier/go-toml/v2/unstable"
+)
+
+// Unmarshal deserializes a TOML document into a Go value.
+//
+// It is a shortcut for Decoder.Decode() with the default options.
+func Unmarshal(data []byte, v interface{}) error {
+ p := unstable.Parser{}
+ p.Reset(data)
+ d := decoder{p: &p}
+
+ return d.FromParser(v)
+}
+
+// Decoder reads and decode a TOML document from an input stream.
+type Decoder struct {
+ // input
+ r io.Reader
+
+ // global settings
+ strict bool
+}
+
+// NewDecoder creates a new Decoder that will read from r.
+func NewDecoder(r io.Reader) *Decoder {
+ return &Decoder{r: r}
+}
+
+// DisallowUnknownFields causes the Decoder to return an error when the
+// destination is a struct and the input contains a key that does not match a
+// non-ignored field.
+//
+// In that case, the Decoder returns a StrictMissingError that can be used to
+// retrieve the individual errors as well as generate a human readable
+// description of the missing fields.
+func (d *Decoder) DisallowUnknownFields() *Decoder {
+ d.strict = true
+ return d
+}
+
+// Decode the whole content of r into v.
+//
+// By default, values in the document that don't exist in the target Go value
+// are ignored. See Decoder.DisallowUnknownFields() to change this behavior.
+//
+// When a TOML local date, time, or date-time is decoded into a time.Time, its
+// value is represented in time.Local timezone. Otherwise the appropriate Local*
+// structure is used. For time values, precision up to the nanosecond is
+// supported by truncating extra digits.
+//
+// Empty tables decoded in an interface{} create an empty initialized
+// map[string]interface{}.
+//
+// Types implementing the encoding.TextUnmarshaler interface are decoded from a
+// TOML string.
+//
+// When decoding a number, go-toml will return an error if the number is out of
+// bounds for the target type (which includes negative numbers when decoding
+// into an unsigned int).
+//
+// If an error occurs while decoding the content of the document, this function
+// returns a toml.DecodeError, providing context about the issue. When using
+// strict mode and a field is missing, a `toml.StrictMissingError` is
+// returned. In any other case, this function returns a standard Go error.
+//
+// # Type mapping
+//
+// List of supported TOML types and their associated accepted Go types:
+//
+// String -> string
+// Integer -> uint*, int*, depending on size
+// Float -> float*, depending on size
+// Boolean -> bool
+// Offset Date-Time -> time.Time
+// Local Date-time -> LocalDateTime, time.Time
+// Local Date -> LocalDate, time.Time
+// Local Time -> LocalTime, time.Time
+// Array -> slice and array, depending on elements types
+// Table -> map and struct
+// Inline Table -> same as Table
+// Array of Tables -> same as Array and Table
+func (d *Decoder) Decode(v interface{}) error {
+ b, err := ioutil.ReadAll(d.r)
+ if err != nil {
+ return fmt.Errorf("toml: %w", err)
+ }
+
+ p := unstable.Parser{}
+ p.Reset(b)
+ dec := decoder{
+ p: &p,
+ strict: strict{
+ Enabled: d.strict,
+ },
+ }
+
+ return dec.FromParser(v)
+}
+
+type decoder struct {
+ // Which parser instance in use for this decoding session.
+ p *unstable.Parser
+
+ // Flag indicating that the current expression is stashed.
+ // If set to true, calling nextExpr will not actually pull a new expression
+ // but turn off the flag instead.
+ stashedExpr bool
+
+ // Skip expressions until a table is found. This is set to true when a
+ // table could not be created (missing field in map), so all KV expressions
+ // need to be skipped.
+ skipUntilTable bool
+
+ // Tracks position in Go arrays.
+ // This is used when decoding [[array tables]] into Go arrays. Given array
+ // tables are separate TOML expression, we need to keep track of where we
+ // are at in the Go array, as we can't just introspect its size.
+ arrayIndexes map[reflect.Value]int
+
+ // Tracks keys that have been seen, with which type.
+ seen tracker.SeenTracker
+
+ // Strict mode
+ strict strict
+
+ // Current context for the error.
+ errorContext *errorContext
+}
+
+type errorContext struct {
+ Struct reflect.Type
+ Field []int
+}
+
+func (d *decoder) typeMismatchError(toml string, target reflect.Type) error {
+ if d.errorContext != nil && d.errorContext.Struct != nil {
+ ctx := d.errorContext
+ f := ctx.Struct.FieldByIndex(ctx.Field)
+ return fmt.Errorf("toml: cannot decode TOML %s into struct field %s.%s of type %s", toml, ctx.Struct, f.Name, f.Type)
+ }
+ return fmt.Errorf("toml: cannot decode TOML %s into a Go value of type %s", toml, target)
+}
+
+func (d *decoder) expr() *unstable.Node {
+ return d.p.Expression()
+}
+
+func (d *decoder) nextExpr() bool {
+ if d.stashedExpr {
+ d.stashedExpr = false
+ return true
+ }
+ return d.p.NextExpression()
+}
+
+func (d *decoder) stashExpr() {
+ d.stashedExpr = true
+}
+
+func (d *decoder) arrayIndex(shouldAppend bool, v reflect.Value) int {
+ if d.arrayIndexes == nil {
+ d.arrayIndexes = make(map[reflect.Value]int, 1)
+ }
+
+ idx, ok := d.arrayIndexes[v]
+
+ if !ok {
+ d.arrayIndexes[v] = 0
+ } else if shouldAppend {
+ idx++
+ d.arrayIndexes[v] = idx
+ }
+
+ return idx
+}
+
+func (d *decoder) FromParser(v interface{}) error {
+ r := reflect.ValueOf(v)
+ if r.Kind() != reflect.Ptr {
+ return fmt.Errorf("toml: decoding can only be performed into a pointer, not %s", r.Kind())
+ }
+
+ if r.IsNil() {
+ return fmt.Errorf("toml: decoding pointer target cannot be nil")
+ }
+
+ r = r.Elem()
+ if r.Kind() == reflect.Interface && r.IsNil() {
+ newMap := map[string]interface{}{}
+ r.Set(reflect.ValueOf(newMap))
+ }
+
+ err := d.fromParser(r)
+ if err == nil {
+ return d.strict.Error(d.p.Data())
+ }
+
+ var e *unstable.ParserError
+ if errors.As(err, &e) {
+ return wrapDecodeError(d.p.Data(), e)
+ }
+
+ return err
+}
+
+func (d *decoder) fromParser(root reflect.Value) error {
+ for d.nextExpr() {
+ err := d.handleRootExpression(d.expr(), root)
+ if err != nil {
+ return err
+ }
+ }
+
+ return d.p.Error()
+}
+
+/*
+Rules for the unmarshal code:
+
+- The stack is used to keep track of which values need to be set where.
+- handle* functions <=> switch on a given unstable.Kind.
+- unmarshalX* functions need to unmarshal a node of kind X.
+- An "object" is either a struct or a map.
+*/
+
+func (d *decoder) handleRootExpression(expr *unstable.Node, v reflect.Value) error {
+ var x reflect.Value
+ var err error
+
+ if !(d.skipUntilTable && expr.Kind == unstable.KeyValue) {
+ err = d.seen.CheckExpression(expr)
+ if err != nil {
+ return err
+ }
+ }
+
+ switch expr.Kind {
+ case unstable.KeyValue:
+ if d.skipUntilTable {
+ return nil
+ }
+ x, err = d.handleKeyValue(expr, v)
+ case unstable.Table:
+ d.skipUntilTable = false
+ d.strict.EnterTable(expr)
+ x, err = d.handleTable(expr.Key(), v)
+ case unstable.ArrayTable:
+ d.skipUntilTable = false
+ d.strict.EnterArrayTable(expr)
+ x, err = d.handleArrayTable(expr.Key(), v)
+ default:
+ panic(fmt.Errorf("parser should not permit expression of kind %s at document root", expr.Kind))
+ }
+
+ if d.skipUntilTable {
+ if expr.Kind == unstable.Table || expr.Kind == unstable.ArrayTable {
+ d.strict.MissingTable(expr)
+ }
+ } else if err == nil && x.IsValid() {
+ v.Set(x)
+ }
+
+ return err
+}
+
+func (d *decoder) handleArrayTable(key unstable.Iterator, v reflect.Value) (reflect.Value, error) {
+ if key.Next() {
+ return d.handleArrayTablePart(key, v)
+ }
+ return d.handleKeyValues(v)
+}
+
+func (d *decoder) handleArrayTableCollectionLast(key unstable.Iterator, v reflect.Value) (reflect.Value, error) {
+ switch v.Kind() {
+ case reflect.Interface:
+ elem := v.Elem()
+ if !elem.IsValid() {
+ elem = reflect.New(sliceInterfaceType).Elem()
+ elem.Set(reflect.MakeSlice(sliceInterfaceType, 0, 16))
+ } else if elem.Kind() == reflect.Slice {
+ if elem.Type() != sliceInterfaceType {
+ elem = reflect.New(sliceInterfaceType).Elem()
+ elem.Set(reflect.MakeSlice(sliceInterfaceType, 0, 16))
+ } else if !elem.CanSet() {
+ nelem := reflect.New(sliceInterfaceType).Elem()
+ nelem.Set(reflect.MakeSlice(sliceInterfaceType, elem.Len(), elem.Cap()))
+ reflect.Copy(nelem, elem)
+ elem = nelem
+ }
+ }
+ return d.handleArrayTableCollectionLast(key, elem)
+ case reflect.Ptr:
+ elem := v.Elem()
+ if !elem.IsValid() {
+ ptr := reflect.New(v.Type().Elem())
+ v.Set(ptr)
+ elem = ptr.Elem()
+ }
+
+ elem, err := d.handleArrayTableCollectionLast(key, elem)
+ if err != nil {
+ return reflect.Value{}, err
+ }
+ v.Elem().Set(elem)
+
+ return v, nil
+ case reflect.Slice:
+ elemType := v.Type().Elem()
+ var elem reflect.Value
+ if elemType.Kind() == reflect.Interface {
+ elem = makeMapStringInterface()
+ } else {
+ elem = reflect.New(elemType).Elem()
+ }
+ elem2, err := d.handleArrayTable(key, elem)
+ if err != nil {
+ return reflect.Value{}, err
+ }
+ if elem2.IsValid() {
+ elem = elem2
+ }
+ return reflect.Append(v, elem), nil
+ case reflect.Array:
+ idx := d.arrayIndex(true, v)
+ if idx >= v.Len() {
+ return v, fmt.Errorf("%s at position %d", d.typeMismatchError("array table", v.Type()), idx)
+ }
+ elem := v.Index(idx)
+ _, err := d.handleArrayTable(key, elem)
+ return v, err
+ default:
+ return reflect.Value{}, d.typeMismatchError("array table", v.Type())
+ }
+}
+
+// When parsing an array table expression, each part of the key needs to be
+// evaluated like a normal key, but if it returns a collection, it also needs to
+// point to the last element of the collection. Unless it is the last part of
+// the key, then it needs to create a new element at the end.
+func (d *decoder) handleArrayTableCollection(key unstable.Iterator, v reflect.Value) (reflect.Value, error) {
+ if key.IsLast() {
+ return d.handleArrayTableCollectionLast(key, v)
+ }
+
+ switch v.Kind() {
+ case reflect.Ptr:
+ elem := v.Elem()
+ if !elem.IsValid() {
+ ptr := reflect.New(v.Type().Elem())
+ v.Set(ptr)
+ elem = ptr.Elem()
+ }
+
+ elem, err := d.handleArrayTableCollection(key, elem)
+ if err != nil {
+ return reflect.Value{}, err
+ }
+ if elem.IsValid() {
+ v.Elem().Set(elem)
+ }
+
+ return v, nil
+ case reflect.Slice:
+ elem := v.Index(v.Len() - 1)
+ x, err := d.handleArrayTable(key, elem)
+ if err != nil || d.skipUntilTable {
+ return reflect.Value{}, err
+ }
+ if x.IsValid() {
+ elem.Set(x)
+ }
+
+ return v, err
+ case reflect.Array:
+ idx := d.arrayIndex(false, v)
+ if idx >= v.Len() {
+ return v, fmt.Errorf("%s at position %d", d.typeMismatchError("array table", v.Type()), idx)
+ }
+ elem := v.Index(idx)
+ _, err := d.handleArrayTable(key, elem)
+ return v, err
+ }
+
+ return d.handleArrayTable(key, v)
+}
+
+func (d *decoder) handleKeyPart(key unstable.Iterator, v reflect.Value, nextFn handlerFn, makeFn valueMakerFn) (reflect.Value, error) {
+ var rv reflect.Value
+
+ // First, dispatch over v to make sure it is a valid object.
+ // There is no guarantee over what it could be.
+ switch v.Kind() {
+ case reflect.Ptr:
+ elem := v.Elem()
+ if !elem.IsValid() {
+ v.Set(reflect.New(v.Type().Elem()))
+ }
+ elem = v.Elem()
+ return d.handleKeyPart(key, elem, nextFn, makeFn)
+ case reflect.Map:
+ vt := v.Type()
+
+ // Create the key for the map element. Convert to key type.
+ mk, err := d.keyFromData(vt.Key(), key.Node().Data)
+ if err != nil {
+ return reflect.Value{}, err
+ }
+
+ // If the map does not exist, create it.
+ if v.IsNil() {
+ vt := v.Type()
+ v = reflect.MakeMap(vt)
+ rv = v
+ }
+
+ mv := v.MapIndex(mk)
+ set := false
+ if !mv.IsValid() {
+ // If there is no value in the map, create a new one according to
+ // the map type. If the element type is interface, create either a
+ // map[string]interface{} or a []interface{} depending on whether
+ // this is the last part of the array table key.
+
+ t := vt.Elem()
+ if t.Kind() == reflect.Interface {
+ mv = makeFn()
+ } else {
+ mv = reflect.New(t).Elem()
+ }
+ set = true
+ } else if mv.Kind() == reflect.Interface {
+ mv = mv.Elem()
+ if !mv.IsValid() {
+ mv = makeFn()
+ }
+ set = true
+ } else if !mv.CanAddr() {
+ vt := v.Type()
+ t := vt.Elem()
+ oldmv := mv
+ mv = reflect.New(t).Elem()
+ mv.Set(oldmv)
+ set = true
+ }
+
+ x, err := nextFn(key, mv)
+ if err != nil {
+ return reflect.Value{}, err
+ }
+
+ if x.IsValid() {
+ mv = x
+ set = true
+ }
+
+ if set {
+ v.SetMapIndex(mk, mv)
+ }
+ case reflect.Struct:
+ path, found := structFieldPath(v, string(key.Node().Data))
+ if !found {
+ d.skipUntilTable = true
+ return reflect.Value{}, nil
+ }
+
+ if d.errorContext == nil {
+ d.errorContext = new(errorContext)
+ }
+ t := v.Type()
+ d.errorContext.Struct = t
+ d.errorContext.Field = path
+
+ f := fieldByIndex(v, path)
+ x, err := nextFn(key, f)
+ if err != nil || d.skipUntilTable {
+ return reflect.Value{}, err
+ }
+ if x.IsValid() {
+ f.Set(x)
+ }
+ d.errorContext.Field = nil
+ d.errorContext.Struct = nil
+ case reflect.Interface:
+ if v.Elem().IsValid() {
+ v = v.Elem()
+ } else {
+ v = makeMapStringInterface()
+ }
+
+ x, err := d.handleKeyPart(key, v, nextFn, makeFn)
+ if err != nil {
+ return reflect.Value{}, err
+ }
+ if x.IsValid() {
+ v = x
+ }
+ rv = v
+ default:
+ panic(fmt.Errorf("unhandled part: %s", v.Kind()))
+ }
+
+ return rv, nil
+}
+
+// HandleArrayTablePart navigates the Go structure v using the key v. It is
+// only used for the prefix (non-last) parts of an array-table. When
+// encountering a collection, it should go to the last element.
+func (d *decoder) handleArrayTablePart(key unstable.Iterator, v reflect.Value) (reflect.Value, error) {
+ var makeFn valueMakerFn
+ if key.IsLast() {
+ makeFn = makeSliceInterface
+ } else {
+ makeFn = makeMapStringInterface
+ }
+ return d.handleKeyPart(key, v, d.handleArrayTableCollection, makeFn)
+}
+
+// HandleTable returns a reference when it has checked the next expression but
+// cannot handle it.
+func (d *decoder) handleTable(key unstable.Iterator, v reflect.Value) (reflect.Value, error) {
+ if v.Kind() == reflect.Slice {
+ if v.Len() == 0 {
+ return reflect.Value{}, unstable.NewParserError(key.Node().Data, "cannot store a table in a slice")
+ }
+ elem := v.Index(v.Len() - 1)
+ x, err := d.handleTable(key, elem)
+ if err != nil {
+ return reflect.Value{}, err
+ }
+ if x.IsValid() {
+ elem.Set(x)
+ }
+ return reflect.Value{}, nil
+ }
+ if key.Next() {
+ // Still scoping the key
+ return d.handleTablePart(key, v)
+ }
+ // Done scoping the key.
+ // Now handle all the key-value expressions in this table.
+ return d.handleKeyValues(v)
+}
+
+// Handle root expressions until the end of the document or the next
+// non-key-value.
+func (d *decoder) handleKeyValues(v reflect.Value) (reflect.Value, error) {
+ var rv reflect.Value
+ for d.nextExpr() {
+ expr := d.expr()
+ if expr.Kind != unstable.KeyValue {
+ // Stash the expression so that fromParser can just loop and use
+ // the right handler.
+ // We could just recurse ourselves here, but at least this gives a
+ // chance to pop the stack a bit.
+ d.stashExpr()
+ break
+ }
+
+ err := d.seen.CheckExpression(expr)
+ if err != nil {
+ return reflect.Value{}, err
+ }
+
+ x, err := d.handleKeyValue(expr, v)
+ if err != nil {
+ return reflect.Value{}, err
+ }
+ if x.IsValid() {
+ v = x
+ rv = x
+ }
+ }
+ return rv, nil
+}
+
+type (
+ handlerFn func(key unstable.Iterator, v reflect.Value) (reflect.Value, error)
+ valueMakerFn func() reflect.Value
+)
+
+func makeMapStringInterface() reflect.Value {
+ return reflect.MakeMap(mapStringInterfaceType)
+}
+
+func makeSliceInterface() reflect.Value {
+ return reflect.MakeSlice(sliceInterfaceType, 0, 16)
+}
+
+func (d *decoder) handleTablePart(key unstable.Iterator, v reflect.Value) (reflect.Value, error) {
+ return d.handleKeyPart(key, v, d.handleTable, makeMapStringInterface)
+}
+
+func (d *decoder) tryTextUnmarshaler(node *unstable.Node, v reflect.Value) (bool, error) {
+ // Special case for time, because we allow to unmarshal to it from
+ // different kind of AST nodes.
+ if v.Type() == timeType {
+ return false, nil
+ }
+
+ if v.CanAddr() && v.Addr().Type().Implements(textUnmarshalerType) {
+ err := v.Addr().Interface().(encoding.TextUnmarshaler).UnmarshalText(node.Data)
+ if err != nil {
+ return false, unstable.NewParserError(d.p.Raw(node.Raw), "%w", err)
+ }
+
+ return true, nil
+ }
+
+ return false, nil
+}
+
+func (d *decoder) handleValue(value *unstable.Node, v reflect.Value) error {
+ for v.Kind() == reflect.Ptr {
+ v = initAndDereferencePointer(v)
+ }
+
+ ok, err := d.tryTextUnmarshaler(value, v)
+ if ok || err != nil {
+ return err
+ }
+
+ switch value.Kind {
+ case unstable.String:
+ return d.unmarshalString(value, v)
+ case unstable.Integer:
+ return d.unmarshalInteger(value, v)
+ case unstable.Float:
+ return d.unmarshalFloat(value, v)
+ case unstable.Bool:
+ return d.unmarshalBool(value, v)
+ case unstable.DateTime:
+ return d.unmarshalDateTime(value, v)
+ case unstable.LocalDate:
+ return d.unmarshalLocalDate(value, v)
+ case unstable.LocalTime:
+ return d.unmarshalLocalTime(value, v)
+ case unstable.LocalDateTime:
+ return d.unmarshalLocalDateTime(value, v)
+ case unstable.InlineTable:
+ return d.unmarshalInlineTable(value, v)
+ case unstable.Array:
+ return d.unmarshalArray(value, v)
+ default:
+ panic(fmt.Errorf("handleValue not implemented for %s", value.Kind))
+ }
+}
+
+func (d *decoder) unmarshalArray(array *unstable.Node, v reflect.Value) error {
+ switch v.Kind() {
+ case reflect.Slice:
+ if v.IsNil() {
+ v.Set(reflect.MakeSlice(v.Type(), 0, 16))
+ } else {
+ v.SetLen(0)
+ }
+ case reflect.Array:
+ // arrays are always initialized
+ case reflect.Interface:
+ elem := v.Elem()
+ if !elem.IsValid() {
+ elem = reflect.New(sliceInterfaceType).Elem()
+ elem.Set(reflect.MakeSlice(sliceInterfaceType, 0, 16))
+ } else if elem.Kind() == reflect.Slice {
+ if elem.Type() != sliceInterfaceType {
+ elem = reflect.New(sliceInterfaceType).Elem()
+ elem.Set(reflect.MakeSlice(sliceInterfaceType, 0, 16))
+ } else if !elem.CanSet() {
+ nelem := reflect.New(sliceInterfaceType).Elem()
+ nelem.Set(reflect.MakeSlice(sliceInterfaceType, elem.Len(), elem.Cap()))
+ reflect.Copy(nelem, elem)
+ elem = nelem
+ }
+ }
+ err := d.unmarshalArray(array, elem)
+ if err != nil {
+ return err
+ }
+ v.Set(elem)
+ return nil
+ default:
+ // TODO: use newDecodeError, but first the parser needs to fill
+ // array.Data.
+ return d.typeMismatchError("array", v.Type())
+ }
+
+ elemType := v.Type().Elem()
+
+ it := array.Children()
+ idx := 0
+ for it.Next() {
+ n := it.Node()
+
+ // TODO: optimize
+ if v.Kind() == reflect.Slice {
+ elem := reflect.New(elemType).Elem()
+
+ err := d.handleValue(n, elem)
+ if err != nil {
+ return err
+ }
+
+ v.Set(reflect.Append(v, elem))
+ } else { // array
+ if idx >= v.Len() {
+ return nil
+ }
+ elem := v.Index(idx)
+ err := d.handleValue(n, elem)
+ if err != nil {
+ return err
+ }
+ idx++
+ }
+ }
+
+ return nil
+}
+
+func (d *decoder) unmarshalInlineTable(itable *unstable.Node, v reflect.Value) error {
+ // Make sure v is an initialized object.
+ switch v.Kind() {
+ case reflect.Map:
+ if v.IsNil() {
+ v.Set(reflect.MakeMap(v.Type()))
+ }
+ case reflect.Struct:
+ // structs are always initialized.
+ case reflect.Interface:
+ elem := v.Elem()
+ if !elem.IsValid() {
+ elem = makeMapStringInterface()
+ v.Set(elem)
+ }
+ return d.unmarshalInlineTable(itable, elem)
+ default:
+ return unstable.NewParserError(d.p.Raw(itable.Raw), "cannot store inline table in Go type %s", v.Kind())
+ }
+
+ it := itable.Children()
+ for it.Next() {
+ n := it.Node()
+
+ x, err := d.handleKeyValue(n, v)
+ if err != nil {
+ return err
+ }
+ if x.IsValid() {
+ v = x
+ }
+ }
+
+ return nil
+}
+
+func (d *decoder) unmarshalDateTime(value *unstable.Node, v reflect.Value) error {
+ dt, err := parseDateTime(value.Data)
+ if err != nil {
+ return err
+ }
+
+ v.Set(reflect.ValueOf(dt))
+ return nil
+}
+
+func (d *decoder) unmarshalLocalDate(value *unstable.Node, v reflect.Value) error {
+ ld, err := parseLocalDate(value.Data)
+ if err != nil {
+ return err
+ }
+
+ if v.Type() == timeType {
+ cast := ld.AsTime(time.Local)
+ v.Set(reflect.ValueOf(cast))
+ return nil
+ }
+
+ v.Set(reflect.ValueOf(ld))
+
+ return nil
+}
+
+func (d *decoder) unmarshalLocalTime(value *unstable.Node, v reflect.Value) error {
+ lt, rest, err := parseLocalTime(value.Data)
+ if err != nil {
+ return err
+ }
+
+ if len(rest) > 0 {
+ return unstable.NewParserError(rest, "extra characters at the end of a local time")
+ }
+
+ v.Set(reflect.ValueOf(lt))
+ return nil
+}
+
+func (d *decoder) unmarshalLocalDateTime(value *unstable.Node, v reflect.Value) error {
+ ldt, rest, err := parseLocalDateTime(value.Data)
+ if err != nil {
+ return err
+ }
+
+ if len(rest) > 0 {
+ return unstable.NewParserError(rest, "extra characters at the end of a local date time")
+ }
+
+ if v.Type() == timeType {
+ cast := ldt.AsTime(time.Local)
+
+ v.Set(reflect.ValueOf(cast))
+ return nil
+ }
+
+ v.Set(reflect.ValueOf(ldt))
+
+ return nil
+}
+
+func (d *decoder) unmarshalBool(value *unstable.Node, v reflect.Value) error {
+ b := value.Data[0] == 't'
+
+ switch v.Kind() {
+ case reflect.Bool:
+ v.SetBool(b)
+ case reflect.Interface:
+ v.Set(reflect.ValueOf(b))
+ default:
+ return unstable.NewParserError(value.Data, "cannot assign boolean to a %t", b)
+ }
+
+ return nil
+}
+
+func (d *decoder) unmarshalFloat(value *unstable.Node, v reflect.Value) error {
+ f, err := parseFloat(value.Data)
+ if err != nil {
+ return err
+ }
+
+ switch v.Kind() {
+ case reflect.Float64:
+ v.SetFloat(f)
+ case reflect.Float32:
+ if f > math.MaxFloat32 {
+ return unstable.NewParserError(value.Data, "number %f does not fit in a float32", f)
+ }
+ v.SetFloat(f)
+ case reflect.Interface:
+ v.Set(reflect.ValueOf(f))
+ default:
+ return unstable.NewParserError(value.Data, "float cannot be assigned to %s", v.Kind())
+ }
+
+ return nil
+}
+
+const (
+ maxInt = int64(^uint(0) >> 1)
+ minInt = -maxInt - 1
+)
+
+// Maximum value of uint for decoding. Currently the decoder parses the integer
+// into an int64. As a result, on architectures where uint is 64 bits, the
+// effective maximum uint we can decode is the maximum of int64. On
+// architectures where uint is 32 bits, the maximum value we can decode is
+// lower: the maximum of uint32. I didn't find a way to figure out this value at
+// compile time, so it is computed during initialization.
+var maxUint int64 = math.MaxInt64
+
+func init() {
+ m := uint64(^uint(0))
+ if m < uint64(maxUint) {
+ maxUint = int64(m)
+ }
+}
+
+func (d *decoder) unmarshalInteger(value *unstable.Node, v reflect.Value) error {
+ kind := v.Kind()
+ if kind == reflect.Float32 || kind == reflect.Float64 {
+ return d.unmarshalFloat(value, v)
+ }
+
+ i, err := parseInteger(value.Data)
+ if err != nil {
+ return err
+ }
+
+ var r reflect.Value
+
+ switch kind {
+ case reflect.Int64:
+ v.SetInt(i)
+ return nil
+ case reflect.Int32:
+ if i < math.MinInt32 || i > math.MaxInt32 {
+ return fmt.Errorf("toml: number %d does not fit in an int32", i)
+ }
+
+ r = reflect.ValueOf(int32(i))
+ case reflect.Int16:
+ if i < math.MinInt16 || i > math.MaxInt16 {
+ return fmt.Errorf("toml: number %d does not fit in an int16", i)
+ }
+
+ r = reflect.ValueOf(int16(i))
+ case reflect.Int8:
+ if i < math.MinInt8 || i > math.MaxInt8 {
+ return fmt.Errorf("toml: number %d does not fit in an int8", i)
+ }
+
+ r = reflect.ValueOf(int8(i))
+ case reflect.Int:
+ if i < minInt || i > maxInt {
+ return fmt.Errorf("toml: number %d does not fit in an int", i)
+ }
+
+ r = reflect.ValueOf(int(i))
+ case reflect.Uint64:
+ if i < 0 {
+ return fmt.Errorf("toml: negative number %d does not fit in an uint64", i)
+ }
+
+ r = reflect.ValueOf(uint64(i))
+ case reflect.Uint32:
+ if i < 0 || i > math.MaxUint32 {
+ return fmt.Errorf("toml: negative number %d does not fit in an uint32", i)
+ }
+
+ r = reflect.ValueOf(uint32(i))
+ case reflect.Uint16:
+ if i < 0 || i > math.MaxUint16 {
+ return fmt.Errorf("toml: negative number %d does not fit in an uint16", i)
+ }
+
+ r = reflect.ValueOf(uint16(i))
+ case reflect.Uint8:
+ if i < 0 || i > math.MaxUint8 {
+ return fmt.Errorf("toml: negative number %d does not fit in an uint8", i)
+ }
+
+ r = reflect.ValueOf(uint8(i))
+ case reflect.Uint:
+ if i < 0 || i > maxUint {
+ return fmt.Errorf("toml: negative number %d does not fit in an uint", i)
+ }
+
+ r = reflect.ValueOf(uint(i))
+ case reflect.Interface:
+ r = reflect.ValueOf(i)
+ default:
+ return d.typeMismatchError("integer", v.Type())
+ }
+
+ if !r.Type().AssignableTo(v.Type()) {
+ r = r.Convert(v.Type())
+ }
+
+ v.Set(r)
+
+ return nil
+}
+
+func (d *decoder) unmarshalString(value *unstable.Node, v reflect.Value) error {
+ switch v.Kind() {
+ case reflect.String:
+ v.SetString(string(value.Data))
+ case reflect.Interface:
+ v.Set(reflect.ValueOf(string(value.Data)))
+ default:
+ return unstable.NewParserError(d.p.Raw(value.Raw), "cannot store TOML string into a Go %s", v.Kind())
+ }
+
+ return nil
+}
+
+func (d *decoder) handleKeyValue(expr *unstable.Node, v reflect.Value) (reflect.Value, error) {
+ d.strict.EnterKeyValue(expr)
+
+ v, err := d.handleKeyValueInner(expr.Key(), expr.Value(), v)
+ if d.skipUntilTable {
+ d.strict.MissingField(expr)
+ d.skipUntilTable = false
+ }
+
+ d.strict.ExitKeyValue(expr)
+
+ return v, err
+}
+
+func (d *decoder) handleKeyValueInner(key unstable.Iterator, value *unstable.Node, v reflect.Value) (reflect.Value, error) {
+ if key.Next() {
+ // Still scoping the key
+ return d.handleKeyValuePart(key, value, v)
+ }
+ // Done scoping the key.
+ // v is whatever Go value we need to fill.
+ return reflect.Value{}, d.handleValue(value, v)
+}
+
+func (d *decoder) keyFromData(keyType reflect.Type, data []byte) (reflect.Value, error) {
+ switch {
+ case stringType.AssignableTo(keyType):
+ return reflect.ValueOf(string(data)), nil
+
+ case stringType.ConvertibleTo(keyType):
+ return reflect.ValueOf(string(data)).Convert(keyType), nil
+
+ case keyType.Implements(textUnmarshalerType):
+ mk := reflect.New(keyType.Elem())
+ if err := mk.Interface().(encoding.TextUnmarshaler).UnmarshalText(data); err != nil {
+ return reflect.Value{}, fmt.Errorf("toml: error unmarshalling key type %s from text: %w", stringType, err)
+ }
+ return mk, nil
+
+ case reflect.PtrTo(keyType).Implements(textUnmarshalerType):
+ mk := reflect.New(keyType)
+ if err := mk.Interface().(encoding.TextUnmarshaler).UnmarshalText(data); err != nil {
+ return reflect.Value{}, fmt.Errorf("toml: error unmarshalling key type %s from text: %w", stringType, err)
+ }
+ return mk.Elem(), nil
+ }
+ return reflect.Value{}, fmt.Errorf("toml: cannot convert map key of type %s to expected type %s", stringType, keyType)
+}
+
+func (d *decoder) handleKeyValuePart(key unstable.Iterator, value *unstable.Node, v reflect.Value) (reflect.Value, error) {
+ // contains the replacement for v
+ var rv reflect.Value
+
+ // First, dispatch over v to make sure it is a valid object.
+ // There is no guarantee over what it could be.
+ switch v.Kind() {
+ case reflect.Map:
+ vt := v.Type()
+
+ mk, err := d.keyFromData(vt.Key(), key.Node().Data)
+ if err != nil {
+ return reflect.Value{}, err
+ }
+
+ // If the map does not exist, create it.
+ if v.IsNil() {
+ v = reflect.MakeMap(vt)
+ rv = v
+ }
+
+ mv := v.MapIndex(mk)
+ set := false
+ if !mv.IsValid() || key.IsLast() {
+ set = true
+ mv = reflect.New(v.Type().Elem()).Elem()
+ }
+
+ nv, err := d.handleKeyValueInner(key, value, mv)
+ if err != nil {
+ return reflect.Value{}, err
+ }
+ if nv.IsValid() {
+ mv = nv
+ set = true
+ }
+
+ if set {
+ v.SetMapIndex(mk, mv)
+ }
+ case reflect.Struct:
+ path, found := structFieldPath(v, string(key.Node().Data))
+ if !found {
+ d.skipUntilTable = true
+ break
+ }
+
+ if d.errorContext == nil {
+ d.errorContext = new(errorContext)
+ }
+ t := v.Type()
+ d.errorContext.Struct = t
+ d.errorContext.Field = path
+
+ f := fieldByIndex(v, path)
+
+ if !f.CanSet() {
+ // If the field is not settable, need to take a slower path and make a copy of
+ // the struct itself to a new location.
+ nvp := reflect.New(v.Type())
+ nvp.Elem().Set(v)
+ v = nvp.Elem()
+ _, err := d.handleKeyValuePart(key, value, v)
+ if err != nil {
+ return reflect.Value{}, err
+ }
+ return nvp.Elem(), nil
+ }
+ x, err := d.handleKeyValueInner(key, value, f)
+ if err != nil {
+ return reflect.Value{}, err
+ }
+
+ if x.IsValid() {
+ f.Set(x)
+ }
+ d.errorContext.Struct = nil
+ d.errorContext.Field = nil
+ case reflect.Interface:
+ v = v.Elem()
+
+ // Following encoding/json: decoding an object into an
+ // interface{}, it needs to always hold a
+ // map[string]interface{}. This is for the types to be
+ // consistent whether a previous value was set or not.
+ if !v.IsValid() || v.Type() != mapStringInterfaceType {
+ v = makeMapStringInterface()
+ }
+
+ x, err := d.handleKeyValuePart(key, value, v)
+ if err != nil {
+ return reflect.Value{}, err
+ }
+ if x.IsValid() {
+ v = x
+ }
+ rv = v
+ case reflect.Ptr:
+ elem := v.Elem()
+ if !elem.IsValid() {
+ ptr := reflect.New(v.Type().Elem())
+ v.Set(ptr)
+ rv = v
+ elem = ptr.Elem()
+ }
+
+ elem2, err := d.handleKeyValuePart(key, value, elem)
+ if err != nil {
+ return reflect.Value{}, err
+ }
+ if elem2.IsValid() {
+ elem = elem2
+ }
+ v.Elem().Set(elem)
+ default:
+ return reflect.Value{}, fmt.Errorf("unhandled kv part: %s", v.Kind())
+ }
+
+ return rv, nil
+}
+
+func initAndDereferencePointer(v reflect.Value) reflect.Value {
+ var elem reflect.Value
+ if v.IsNil() {
+ ptr := reflect.New(v.Type().Elem())
+ v.Set(ptr)
+ }
+ elem = v.Elem()
+ return elem
+}
+
+// Same as reflect.Value.FieldByIndex, but creates pointers if needed.
+func fieldByIndex(v reflect.Value, path []int) reflect.Value {
+ for i, x := range path {
+ v = v.Field(x)
+
+ if i < len(path)-1 && v.Kind() == reflect.Ptr {
+ if v.IsNil() {
+ v.Set(reflect.New(v.Type().Elem()))
+ }
+ v = v.Elem()
+ }
+ }
+ return v
+}
+
+type fieldPathsMap = map[string][]int
+
+var globalFieldPathsCache atomic.Value // map[danger.TypeID]fieldPathsMap
+
+func structFieldPath(v reflect.Value, name string) ([]int, bool) {
+ t := v.Type()
+
+ cache, _ := globalFieldPathsCache.Load().(map[danger.TypeID]fieldPathsMap)
+ fieldPaths, ok := cache[danger.MakeTypeID(t)]
+
+ if !ok {
+ fieldPaths = map[string][]int{}
+
+ forEachField(t, nil, func(name string, path []int) {
+ fieldPaths[name] = path
+ // extra copy for the case-insensitive match
+ fieldPaths[strings.ToLower(name)] = path
+ })
+
+ newCache := make(map[danger.TypeID]fieldPathsMap, len(cache)+1)
+ newCache[danger.MakeTypeID(t)] = fieldPaths
+ for k, v := range cache {
+ newCache[k] = v
+ }
+ globalFieldPathsCache.Store(newCache)
+ }
+
+ path, ok := fieldPaths[name]
+ if !ok {
+ path, ok = fieldPaths[strings.ToLower(name)]
+ }
+ return path, ok
+}
+
+func forEachField(t reflect.Type, path []int, do func(name string, path []int)) {
+ n := t.NumField()
+ for i := 0; i < n; i++ {
+ f := t.Field(i)
+
+ if !f.Anonymous && f.PkgPath != "" {
+ // only consider exported fields.
+ continue
+ }
+
+ fieldPath := append(path, i)
+ fieldPath = fieldPath[:len(fieldPath):len(fieldPath)]
+
+ name := f.Tag.Get("toml")
+ if name == "-" {
+ continue
+ }
+
+ if i := strings.IndexByte(name, ','); i >= 0 {
+ name = name[:i]
+ }
+
+ if f.Anonymous && name == "" {
+ t2 := f.Type
+ if t2.Kind() == reflect.Ptr {
+ t2 = t2.Elem()
+ }
+
+ if t2.Kind() == reflect.Struct {
+ forEachField(t2, fieldPath, do)
+ }
+ continue
+ }
+
+ if name == "" {
+ name = f.Name
+ }
+
+ do(name, fieldPath)
+ }
+}
diff --git a/vendor/github.com/pelletier/go-toml/v2/unstable/ast.go b/vendor/github.com/pelletier/go-toml/v2/unstable/ast.go
new file mode 100644
index 000000000..f526bf2c0
--- /dev/null
+++ b/vendor/github.com/pelletier/go-toml/v2/unstable/ast.go
@@ -0,0 +1,136 @@
+package unstable
+
+import (
+ "fmt"
+ "unsafe"
+
+ "github.com/pelletier/go-toml/v2/internal/danger"
+)
+
+// Iterator over a sequence of nodes.
+//
+// Starts uninitialized, you need to call Next() first.
+//
+// For example:
+//
+// it := n.Children()
+// for it.Next() {
+// n := it.Node()
+// // do something with n
+// }
+type Iterator struct {
+ started bool
+ node *Node
+}
+
+// Next moves the iterator forward and returns true if points to a
+// node, false otherwise.
+func (c *Iterator) Next() bool {
+ if !c.started {
+ c.started = true
+ } else if c.node.Valid() {
+ c.node = c.node.Next()
+ }
+ return c.node.Valid()
+}
+
+// IsLast returns true if the current node of the iterator is the last
+// one. Subsequent calls to Next() will return false.
+func (c *Iterator) IsLast() bool {
+ return c.node.next == 0
+}
+
+// Node returns a pointer to the node pointed at by the iterator.
+func (c *Iterator) Node() *Node {
+ return c.node
+}
+
+// Node in a TOML expression AST.
+//
+// Depending on Kind, its sequence of children should be interpreted
+// differently.
+//
+// - Array have one child per element in the array.
+// - InlineTable have one child per key-value in the table (each of kind
+// InlineTable).
+// - KeyValue have at least two children. The first one is the value. The rest
+// make a potentially dotted key.
+// - Table and ArrayTable's children represent a dotted key (same as
+// KeyValue, but without the first node being the value).
+//
+// When relevant, Raw describes the range of bytes this node is referring to in
+// the input document. Use Parser.Raw() to retrieve the actual bytes.
+type Node struct {
+ Kind Kind
+ Raw Range // Raw bytes from the input.
+ Data []byte // Node value (either allocated or referencing the input).
+
+ // References to other nodes, as offsets in the backing array
+ // from this node. References can go backward, so those can be
+ // negative.
+ next int // 0 if last element
+ child int // 0 if no child
+}
+
+// Range of bytes in the document.
+type Range struct {
+ Offset uint32
+ Length uint32
+}
+
+// Next returns a pointer to the next node, or nil if there is no next node.
+func (n *Node) Next() *Node {
+ if n.next == 0 {
+ return nil
+ }
+ ptr := unsafe.Pointer(n)
+ size := unsafe.Sizeof(Node{})
+ return (*Node)(danger.Stride(ptr, size, n.next))
+}
+
+// Child returns a pointer to the first child node of this node. Other children
+// can be accessed calling Next on the first child. Returns an nil if this Node
+// has no child.
+func (n *Node) Child() *Node {
+ if n.child == 0 {
+ return nil
+ }
+ ptr := unsafe.Pointer(n)
+ size := unsafe.Sizeof(Node{})
+ return (*Node)(danger.Stride(ptr, size, n.child))
+}
+
+// Valid returns true if the node's kind is set (not to Invalid).
+func (n *Node) Valid() bool {
+ return n != nil
+}
+
+// Key returns the children nodes making the Key on a supported node. Panics
+// otherwise. They are guaranteed to be all be of the Kind Key. A simple key
+// would return just one element.
+func (n *Node) Key() Iterator {
+ switch n.Kind {
+ case KeyValue:
+ value := n.Child()
+ if !value.Valid() {
+ panic(fmt.Errorf("KeyValue should have at least two children"))
+ }
+ return Iterator{node: value.Next()}
+ case Table, ArrayTable:
+ return Iterator{node: n.Child()}
+ default:
+ panic(fmt.Errorf("Key() is not supported on a %s", n.Kind))
+ }
+}
+
+// Value returns a pointer to the value node of a KeyValue.
+// Guaranteed to be non-nil. Panics if not called on a KeyValue node,
+// or if the Children are malformed.
+func (n *Node) Value() *Node {
+ return n.Child()
+}
+
+// Children returns an iterator over a node's children.
+func (n *Node) Children() Iterator {
+ return Iterator{node: n.Child()}
+}
diff --git a/vendor/github.com/pelletier/go-toml/v2/unstable/builder.go b/vendor/github.com/pelletier/go-toml/v2/unstable/builder.go
new file mode 100644
index 000000000..9538e30df
--- /dev/null
+++ b/vendor/github.com/pelletier/go-toml/v2/unstable/builder.go
@@ -0,0 +1,71 @@
+package unstable
+
+// root contains a full AST.
+//
+// It is immutable once constructed with Builder.
+type root struct {
+ nodes []Node
+}
+
+// Iterator over the top level nodes.
+func (r *root) Iterator() Iterator {
+ it := Iterator{}
+ if len(r.nodes) > 0 {
+ it.node = &r.nodes[0]
+ }
+ return it
+}
+
+func (r *root) at(idx reference) *Node {
+ return &r.nodes[idx]
+}
+
+type reference int
+
+const invalidReference reference = -1
+
+func (r reference) Valid() bool {
+ return r != invalidReference
+}
+
+type builder struct {
+ tree root
+ lastIdx int
+}
+
+func (b *builder) Tree() *root {
+ return &b.tree
+}
+
+func (b *builder) NodeAt(ref reference) *Node {
+ return b.tree.at(ref)
+}
+
+func (b *builder) Reset() {
+ b.tree.nodes = b.tree.nodes[:0]
+ b.lastIdx = 0
+}
+
+func (b *builder) Push(n Node) reference {
+ b.lastIdx = len(b.tree.nodes)
+ b.tree.nodes = append(b.tree.nodes, n)
+ return reference(b.lastIdx)
+}
+
+func (b *builder) PushAndChain(n Node) reference {
+ newIdx := len(b.tree.nodes)
+ b.tree.nodes = append(b.tree.nodes, n)
+ if b.lastIdx >= 0 {
+ b.tree.nodes[b.lastIdx].next = newIdx - b.lastIdx
+ }
+ b.lastIdx = newIdx
+ return reference(b.lastIdx)
+}
+
+func (b *builder) AttachChild(parent reference, child reference) {
+ b.tree.nodes[parent].child = int(child) - int(parent)
+}
+
+func (b *builder) Chain(from reference, to reference) {
+ b.tree.nodes[from].next = int(to) - int(from)
+}
diff --git a/vendor/github.com/pelletier/go-toml/v2/unstable/doc.go b/vendor/github.com/pelletier/go-toml/v2/unstable/doc.go
new file mode 100644
index 000000000..7ff26c53c
--- /dev/null
+++ b/vendor/github.com/pelletier/go-toml/v2/unstable/doc.go
@@ -0,0 +1,3 @@
+// Package unstable provides APIs that do not meet the backward compatibility
+// guarantees yet.
+package unstable
diff --git a/vendor/github.com/pelletier/go-toml/v2/unstable/kind.go b/vendor/github.com/pelletier/go-toml/v2/unstable/kind.go
new file mode 100644
index 000000000..ff9df1bef
--- /dev/null
+++ b/vendor/github.com/pelletier/go-toml/v2/unstable/kind.go
@@ -0,0 +1,71 @@
+package unstable
+
+import "fmt"
+
+// Kind represents the type of TOML structure contained in a given Node.
+type Kind int
+
+const (
+ // Meta
+ Invalid Kind = iota
+ Comment
+ Key
+
+ // Top level structures
+ Table
+ ArrayTable
+ KeyValue
+
+ // Containers values
+ Array
+ InlineTable
+
+ // Values
+ String
+ Bool
+ Float
+ Integer
+ LocalDate
+ LocalTime
+ LocalDateTime
+ DateTime
+)
+
+// String implementation of fmt.Stringer.
+func (k Kind) String() string {
+ switch k {
+ case Invalid:
+ return "Invalid"
+ case Comment:
+ return "Comment"
+ case Key:
+ return "Key"
+ case Table:
+ return "Table"
+ case ArrayTable:
+ return "ArrayTable"
+ case KeyValue:
+ return "KeyValue"
+ case Array:
+ return "Array"
+ case InlineTable:
+ return "InlineTable"
+ case String:
+ return "String"
+ case Bool:
+ return "Bool"
+ case Float:
+ return "Float"
+ case Integer:
+ return "Integer"
+ case LocalDate:
+ return "LocalDate"
+ case LocalTime:
+ return "LocalTime"
+ case LocalDateTime:
+ return "LocalDateTime"
+ case DateTime:
+ return "DateTime"
+ }
+ panic(fmt.Errorf("Kind.String() not implemented for '%d'", k))
+}
diff --git a/vendor/github.com/pelletier/go-toml/v2/unstable/parser.go b/vendor/github.com/pelletier/go-toml/v2/unstable/parser.go
new file mode 100644
index 000000000..a8eb05294
--- /dev/null
+++ b/vendor/github.com/pelletier/go-toml/v2/unstable/parser.go
@@ -0,0 +1,1239 @@
+package unstable
+
+import (
+ "bytes"
+ "fmt"
+ "unicode"
+
+ "github.com/pelletier/go-toml/v2/internal/characters"
+ "github.com/pelletier/go-toml/v2/internal/danger"
+)
+
+// ParserError describes an error relative to the content of the document.
+//
+// It cannot outlive the instance of Parser it refers to, and may cause panics
+// if the parser is reset.
+type ParserError struct {
+ Highlight []byte
+ Message string
+ Key []string // optional
+}
+
+// Error is the implementation of the error interface.
+func (e *ParserError) Error() string {
+ return e.Message
+}
+
+// NewParserError is a convenience function to create a ParserError
+//
+// Warning: Highlight needs to be a subslice of Parser.data, so only slices
+// returned by Parser.Raw are valid candidates.
+func NewParserError(highlight []byte, format string, args ...interface{}) error {
+ return &ParserError{
+ Highlight: highlight,
+ Message: fmt.Errorf(format, args...).Error(),
+ }
+}
+
+// Parser scans over a TOML-encoded document and generates an iterative AST.
+//
+// To prime the Parser, first reset it with the contents of a TOML document.
+// Then, process all top-level expressions sequentially. See Example.
+//
+// Don't forget to check Error() after you're done parsing.
+//
+// Each top-level expression needs to be fully processed before calling
+// NextExpression() again. Otherwise, calls to various Node methods may panic if
+// the parser has moved on the next expression.
+//
+// For performance reasons, go-toml doesn't make a copy of the input bytes to
+// the parser. Make sure to copy all the bytes you need to outlive the slice
+// given to the parser.
+type Parser struct {
+ data []byte
+ builder builder
+ ref reference
+ left []byte
+ err error
+ first bool
+
+ KeepComments bool
+}
+
+// Data returns the slice provided to the last call to Reset.
+func (p *Parser) Data() []byte {
+ return p.data
+}
+
+// Range returns a range description that corresponds to a given slice of the
+// input. If the argument is not a subslice of the parser input, this function
+// panics.
+func (p *Parser) Range(b []byte) Range {
+ return Range{
+ Offset: uint32(danger.SubsliceOffset(p.data, b)),
+ Length: uint32(len(b)),
+ }
+}
+
+// Raw returns the slice corresponding to the bytes in the given range.
+func (p *Parser) Raw(raw Range) []byte {
+ return p.data[raw.Offset : raw.Offset+raw.Length]
+}
+
+// Reset brings the parser to its initial state for a given input. It wipes an
+// reuses internal storage to reduce allocation.
+func (p *Parser) Reset(b []byte) {
+ p.builder.Reset()
+ p.ref = invalidReference
+ p.data = b
+ p.left = b
+ p.err = nil
+ p.first = true
+}
+
+// NextExpression parses the next top-level expression. If an expression was
+// successfully parsed, it returns true. If the parser is at the end of the
+// document or an error occurred, it returns false.
+//
+// Retrieve the parsed expression with Expression().
+func (p *Parser) NextExpression() bool {
+ if len(p.left) == 0 || p.err != nil {
+ return false
+ }
+
+ p.builder.Reset()
+ p.ref = invalidReference
+
+ for {
+ if len(p.left) == 0 || p.err != nil {
+ return false
+ }
+
+ if !p.first {
+ p.left, p.err = p.parseNewline(p.left)
+ }
+
+ if len(p.left) == 0 || p.err != nil {
+ return false
+ }
+
+ p.ref, p.left, p.err = p.parseExpression(p.left)
+
+ if p.err != nil {
+ return false
+ }
+
+ p.first = false
+
+ if p.ref.Valid() {
+ return true
+ }
+ }
+}
+
+// Expression returns a pointer to the node representing the last successfully
+// parsed expression.
+func (p *Parser) Expression() *Node {
+ return p.builder.NodeAt(p.ref)
+}
+
+// Error returns any error that has occurred during parsing.
+func (p *Parser) Error() error {
+ return p.err
+}
+
+// Position describes a position in the input.
+type Position struct {
+ // Number of bytes from the beginning of the input.
+ Offset int
+ // Line number, starting at 1.
+ Line int
+ // Column number, starting at 1.
+ Column int
+}
+
+// Shape describes the position of a range in the input.
+type Shape struct {
+ Start Position
+ End Position
+}
+
+func (p *Parser) position(b []byte) Position {
+ offset := danger.SubsliceOffset(p.data, b)
+
+ lead := p.data[:offset]
+
+ return Position{
+ Offset: offset,
+ Line: bytes.Count(lead, []byte{'\n'}) + 1,
+ Column: len(lead) - bytes.LastIndex(lead, []byte{'\n'}),
+ }
+}
+
+// Shape returns the shape of the given range in the input. Will
+// panic if the range is not a subslice of the input.
+func (p *Parser) Shape(r Range) Shape {
+ raw := p.Raw(r)
+ return Shape{
+ Start: p.position(raw),
+ End: p.position(raw[r.Length:]),
+ }
+}
+
+func (p *Parser) parseNewline(b []byte) ([]byte, error) {
+ if b[0] == '\n' {
+ return b[1:], nil
+ }
+
+ if b[0] == '\r' {
+ _, rest, err := scanWindowsNewline(b)
+ return rest, err
+ }
+
+ return nil, NewParserError(b[0:1], "expected newline but got %#U", b[0])
+}
+
+func (p *Parser) parseComment(b []byte) (reference, []byte, error) {
+ ref := invalidReference
+ data, rest, err := scanComment(b)
+ if p.KeepComments && err == nil {
+ ref = p.builder.Push(Node{
+ Kind: Comment,
+ Raw: p.Range(data),
+ Data: data,
+ })
+ }
+ return ref, rest, err
+}
+
+func (p *Parser) parseExpression(b []byte) (reference, []byte, error) {
+ // expression = ws [ comment ]
+ // expression =/ ws keyval ws [ comment ]
+ // expression =/ ws table ws [ comment ]
+ ref := invalidReference
+
+ b = p.parseWhitespace(b)
+
+ if len(b) == 0 {
+ return ref, b, nil
+ }
+
+ if b[0] == '#' {
+ ref, rest, err := p.parseComment(b)
+ return ref, rest, err
+ }
+
+ if b[0] == '\n' || b[0] == '\r' {
+ return ref, b, nil
+ }
+
+ var err error
+ if b[0] == '[' {
+ ref, b, err = p.parseTable(b)
+ } else {
+ ref, b, err = p.parseKeyval(b)
+ }
+
+ if err != nil {
+ return ref, nil, err
+ }
+
+ b = p.parseWhitespace(b)
+
+ if len(b) > 0 && b[0] == '#' {
+ cref, rest, err := p.parseComment(b)
+ if cref != invalidReference {
+ p.builder.Chain(ref, cref)
+ }
+ return ref, rest, err
+ }
+
+ return ref, b, nil
+}
+
+func (p *Parser) parseTable(b []byte) (reference, []byte, error) {
+ // table = std-table / array-table
+ if len(b) > 1 && b[1] == '[' {
+ return p.parseArrayTable(b)
+ }
+
+ return p.parseStdTable(b)
+}
+
+func (p *Parser) parseArrayTable(b []byte) (reference, []byte, error) {
+ // array-table = array-table-open key array-table-close
+ // array-table-open = %x5B.5B ws ; [[ Double left square bracket
+ // array-table-close = ws %x5D.5D ; ]] Double right square bracket
+ ref := p.builder.Push(Node{
+ Kind: ArrayTable,
+ })
+
+ b = b[2:]
+ b = p.parseWhitespace(b)
+
+ k, b, err := p.parseKey(b)
+ if err != nil {
+ return ref, nil, err
+ }
+
+ p.builder.AttachChild(ref, k)
+ b = p.parseWhitespace(b)
+
+ b, err = expect(']', b)
+ if err != nil {
+ return ref, nil, err
+ }
+
+ b, err = expect(']', b)
+
+ return ref, b, err
+}
+
+func (p *Parser) parseStdTable(b []byte) (reference, []byte, error) {
+ // std-table = std-table-open key std-table-close
+ // std-table-open = %x5B ws ; [ Left square bracket
+ // std-table-close = ws %x5D ; ] Right square bracket
+ ref := p.builder.Push(Node{
+ Kind: Table,
+ })
+
+ b = b[1:]
+ b = p.parseWhitespace(b)
+
+ key, b, err := p.parseKey(b)
+ if err != nil {
+ return ref, nil, err
+ }
+
+ p.builder.AttachChild(ref, key)
+
+ b = p.parseWhitespace(b)
+
+ b, err = expect(']', b)
+
+ return ref, b, err
+}
+
+func (p *Parser) parseKeyval(b []byte) (reference, []byte, error) {
+ // keyval = key keyval-sep val
+ ref := p.builder.Push(Node{
+ Kind: KeyValue,
+ })
+
+ key, b, err := p.parseKey(b)
+ if err != nil {
+ return invalidReference, nil, err
+ }
+
+ // keyval-sep = ws %x3D ws ; =
+
+ b = p.parseWhitespace(b)
+
+ if len(b) == 0 {
+ return invalidReference, nil, NewParserError(b, "expected = after a key, but the document ends there")
+ }
+
+ b, err = expect('=', b)
+ if err != nil {
+ return invalidReference, nil, err
+ }
+
+ b = p.parseWhitespace(b)
+
+ valRef, b, err := p.parseVal(b)
+ if err != nil {
+ return ref, b, err
+ }
+
+ p.builder.Chain(valRef, key)
+ p.builder.AttachChild(ref, valRef)
+
+ return ref, b, err
+}
+
+//nolint:cyclop,funlen
+func (p *Parser) parseVal(b []byte) (reference, []byte, error) {
+ // val = string / boolean / array / inline-table / date-time / float / integer
+ ref := invalidReference
+
+ if len(b) == 0 {
+ return ref, nil, NewParserError(b, "expected value, not eof")
+ }
+
+ var err error
+ c := b[0]
+
+ switch c {
+ case '"':
+ var raw []byte
+ var v []byte
+ if scanFollowsMultilineBasicStringDelimiter(b) {
+ raw, v, b, err = p.parseMultilineBasicString(b)
+ } else {
+ raw, v, b, err = p.parseBasicString(b)
+ }
+
+ if err == nil {
+ ref = p.builder.Push(Node{
+ Kind: String,
+ Raw: p.Range(raw),
+ Data: v,
+ })
+ }
+
+ return ref, b, err
+ case '\'':
+ var raw []byte
+ var v []byte
+ if scanFollowsMultilineLiteralStringDelimiter(b) {
+ raw, v, b, err = p.parseMultilineLiteralString(b)
+ } else {
+ raw, v, b, err = p.parseLiteralString(b)
+ }
+
+ if err == nil {
+ ref = p.builder.Push(Node{
+ Kind: String,
+ Raw: p.Range(raw),
+ Data: v,
+ })
+ }
+
+ return ref, b, err
+ case 't':
+ if !scanFollowsTrue(b) {
+ return ref, nil, NewParserError(atmost(b, 4), "expected 'true'")
+ }
+
+ ref = p.builder.Push(Node{
+ Kind: Bool,
+ Data: b[:4],
+ })
+
+ return ref, b[4:], nil
+ case 'f':
+ if !scanFollowsFalse(b) {
+ return ref, nil, NewParserError(atmost(b, 5), "expected 'false'")
+ }
+
+ ref = p.builder.Push(Node{
+ Kind: Bool,
+ Data: b[:5],
+ })
+
+ return ref, b[5:], nil
+ case '[':
+ return p.parseValArray(b)
+ case '{':
+ return p.parseInlineTable(b)
+ default:
+ return p.parseIntOrFloatOrDateTime(b)
+ }
+}
+
+func atmost(b []byte, n int) []byte {
+ if n >= len(b) {
+ return b
+ }
+
+ return b[:n]
+}
+
+func (p *Parser) parseLiteralString(b []byte) ([]byte, []byte, []byte, error) {
+ v, rest, err := scanLiteralString(b)
+ if err != nil {
+ return nil, nil, nil, err
+ }
+
+ return v, v[1 : len(v)-1], rest, nil
+}
+
+func (p *Parser) parseInlineTable(b []byte) (reference, []byte, error) {
+ // inline-table = inline-table-open [ inline-table-keyvals ] inline-table-close
+ // inline-table-open = %x7B ws ; {
+ // inline-table-close = ws %x7D ; }
+ // inline-table-sep = ws %x2C ws ; , Comma
+ // inline-table-keyvals = keyval [ inline-table-sep inline-table-keyvals ]
+ parent := p.builder.Push(Node{
+ Kind: InlineTable,
+ Raw: p.Range(b[:1]),
+ })
+
+ first := true
+
+ var child reference
+
+ b = b[1:]
+
+ var err error
+
+ for len(b) > 0 {
+ previousB := b
+ b = p.parseWhitespace(b)
+
+ if len(b) == 0 {
+ return parent, nil, NewParserError(previousB[:1], "inline table is incomplete")
+ }
+
+ if b[0] == '}' {
+ break
+ }
+
+ if !first {
+ b, err = expect(',', b)
+ if err != nil {
+ return parent, nil, err
+ }
+ b = p.parseWhitespace(b)
+ }
+
+ var kv reference
+
+ kv, b, err = p.parseKeyval(b)
+ if err != nil {
+ return parent, nil, err
+ }
+
+ if first {
+ p.builder.AttachChild(parent, kv)
+ } else {
+ p.builder.Chain(child, kv)
+ }
+ child = kv
+
+ first = false
+ }
+
+ rest, err := expect('}', b)
+
+ return parent, rest, err
+}
+
+//nolint:funlen,cyclop
+func (p *Parser) parseValArray(b []byte) (reference, []byte, error) {
+ // array = array-open [ array-values ] ws-comment-newline array-close
+ // array-open = %x5B ; [
+ // array-close = %x5D ; ]
+ // array-values = ws-comment-newline val ws-comment-newline array-sep array-values
+ // array-values =/ ws-comment-newline val ws-comment-newline [ array-sep ]
+ // array-sep = %x2C ; , Comma
+ // ws-comment-newline = *( wschar / [ comment ] newline )
+ arrayStart := b
+ b = b[1:]
+
+ parent := p.builder.Push(Node{
+ Kind: Array,
+ })
+
+ // First indicates whether the parser is looking for the first element
+ // (non-comment) of the array.
+ first := true
+
+ lastChild := invalidReference
+
+ addChild := func(valueRef reference) {
+ if lastChild == invalidReference {
+ p.builder.AttachChild(parent, valueRef)
+ } else {
+ p.builder.Chain(lastChild, valueRef)
+ }
+ lastChild = valueRef
+ }
+
+ var err error
+ for len(b) > 0 {
+ cref := invalidReference
+ cref, b, err = p.parseOptionalWhitespaceCommentNewline(b)
+ if err != nil {
+ return parent, nil, err
+ }
+
+ if cref != invalidReference {
+ addChild(cref)
+ }
+
+ if len(b) == 0 {
+ return parent, nil, NewParserError(arrayStart[:1], "array is incomplete")
+ }
+
+ if b[0] == ']' {
+ break
+ }
+
+ if b[0] == ',' {
+ if first {
+ return parent, nil, NewParserError(b[0:1], "array cannot start with comma")
+ }
+ b = b[1:]
+
+ cref, b, err = p.parseOptionalWhitespaceCommentNewline(b)
+ if err != nil {
+ return parent, nil, err
+ }
+ if cref != invalidReference {
+ addChild(cref)
+ }
+ } else if !first {
+ return parent, nil, NewParserError(b[0:1], "array elements must be separated by commas")
+ }
+
+ // TOML allows trailing commas in arrays.
+ if len(b) > 0 && b[0] == ']' {
+ break
+ }
+
+ var valueRef reference
+ valueRef, b, err = p.parseVal(b)
+ if err != nil {
+ return parent, nil, err
+ }
+
+ addChild(valueRef)
+
+ cref, b, err = p.parseOptionalWhitespaceCommentNewline(b)
+ if err != nil {
+ return parent, nil, err
+ }
+ if cref != invalidReference {
+ addChild(cref)
+ }
+
+ first = false
+ }
+
+ rest, err := expect(']', b)
+
+ return parent, rest, err
+}
+
+func (p *Parser) parseOptionalWhitespaceCommentNewline(b []byte) (reference, []byte, error) {
+ rootCommentRef := invalidReference
+ latestCommentRef := invalidReference
+
+ addComment := func(ref reference) {
+ if rootCommentRef == invalidReference {
+ rootCommentRef = ref
+ } else if latestCommentRef == invalidReference {
+ p.builder.AttachChild(rootCommentRef, ref)
+ latestCommentRef = ref
+ } else {
+ p.builder.Chain(latestCommentRef, ref)
+ latestCommentRef = ref
+ }
+ }
+
+ for len(b) > 0 {
+ var err error
+ b = p.parseWhitespace(b)
+
+ if len(b) > 0 && b[0] == '#' {
+ var ref reference
+ ref, b, err = p.parseComment(b)
+ if err != nil {
+ return invalidReference, nil, err
+ }
+ if ref != invalidReference {
+ addComment(ref)
+ }
+ }
+
+ if len(b) == 0 {
+ break
+ }
+
+ if b[0] == '\n' || b[0] == '\r' {
+ b, err = p.parseNewline(b)
+ if err != nil {
+ return invalidReference, nil, err
+ }
+ } else {
+ break
+ }
+ }
+
+ return rootCommentRef, b, nil
+}
+
+func (p *Parser) parseMultilineLiteralString(b []byte) ([]byte, []byte, []byte, error) {
+ token, rest, err := scanMultilineLiteralString(b)
+ if err != nil {
+ return nil, nil, nil, err
+ }
+
+ i := 3
+
+ // skip the immediate new line
+ if token[i] == '\n' {
+ i++
+ } else if token[i] == '\r' && token[i+1] == '\n' {
+ i += 2
+ }
+
+ return token, token[i : len(token)-3], rest, err
+}
+
+//nolint:funlen,gocognit,cyclop
+func (p *Parser) parseMultilineBasicString(b []byte) ([]byte, []byte, []byte, error) {
+ // ml-basic-string = ml-basic-string-delim [ newline ] ml-basic-body
+ // ml-basic-string-delim
+ // ml-basic-string-delim = 3quotation-mark
+ // ml-basic-body = *mlb-content *( mlb-quotes 1*mlb-content ) [ mlb-quotes ]
+ //
+ // mlb-content = mlb-char / newline / mlb-escaped-nl
+ // mlb-char = mlb-unescaped / escaped
+ // mlb-quotes = 1*2quotation-mark
+ // mlb-unescaped = wschar / %x21 / %x23-5B / %x5D-7E / non-ascii
+ // mlb-escaped-nl = escape ws newline *( wschar / newline )
+ token, escaped, rest, err := scanMultilineBasicString(b)
+ if err != nil {
+ return nil, nil, nil, err
+ }
+
+ i := 3
+
+ // skip the immediate new line
+ if token[i] == '\n' {
+ i++
+ } else if token[i] == '\r' && token[i+1] == '\n' {
+ i += 2
+ }
+
+ // fast path
+ startIdx := i
+ endIdx := len(token) - len(`"""`)
+
+ if !escaped {
+ str := token[startIdx:endIdx]
+ verr := characters.Utf8TomlValidAlreadyEscaped(str)
+ if verr.Zero() {
+ return token, str, rest, nil
+ }
+ return nil, nil, nil, NewParserError(str[verr.Index:verr.Index+verr.Size], "invalid UTF-8")
+ }
+
+ var builder bytes.Buffer
+
+ // The scanner ensures that the token starts and ends with quotes and that
+ // escapes are balanced.
+ for i < len(token)-3 {
+ c := token[i]
+
+ //nolint:nestif
+ if c == '\\' {
+ // When the last non-whitespace character on a line is an unescaped \,
+ // it will be trimmed along with all whitespace (including newlines) up
+ // to the next non-whitespace character or closing delimiter.
+
+ isLastNonWhitespaceOnLine := false
+ j := 1
+ findEOLLoop:
+ for ; j < len(token)-3-i; j++ {
+ switch token[i+j] {
+ case ' ', '\t':
+ continue
+ case '\r':
+ if token[i+j+1] == '\n' {
+ continue
+ }
+ case '\n':
+ isLastNonWhitespaceOnLine = true
+ }
+ break findEOLLoop
+ }
+ if isLastNonWhitespaceOnLine {
+ i += j
+ for ; i < len(token)-3; i++ {
+ c := token[i]
+ if !(c == '\n' || c == '\r' || c == ' ' || c == '\t') {
+ i--
+ break
+ }
+ }
+ i++
+ continue
+ }
+
+ // handle escaping
+ i++
+ c = token[i]
+
+ switch c {
+ case '"', '\\':
+ builder.WriteByte(c)
+ case 'b':
+ builder.WriteByte('\b')
+ case 'f':
+ builder.WriteByte('\f')
+ case 'n':
+ builder.WriteByte('\n')
+ case 'r':
+ builder.WriteByte('\r')
+ case 't':
+ builder.WriteByte('\t')
+ case 'e':
+ builder.WriteByte(0x1B)
+ case 'u':
+ x, err := hexToRune(atmost(token[i+1:], 4), 4)
+ if err != nil {
+ return nil, nil, nil, err
+ }
+ builder.WriteRune(x)
+ i += 4
+ case 'U':
+ x, err := hexToRune(atmost(token[i+1:], 8), 8)
+ if err != nil {
+ return nil, nil, nil, err
+ }
+
+ builder.WriteRune(x)
+ i += 8
+ default:
+ return nil, nil, nil, NewParserError(token[i:i+1], "invalid escaped character %#U", c)
+ }
+ i++
+ } else {
+ size := characters.Utf8ValidNext(token[i:])
+ if size == 0 {
+ return nil, nil, nil, NewParserError(token[i:i+1], "invalid character %#U", c)
+ }
+ builder.Write(token[i : i+size])
+ i += size
+ }
+ }
+
+ return token, builder.Bytes(), rest, nil
+}
+
+func (p *Parser) parseKey(b []byte) (reference, []byte, error) {
+ // key = simple-key / dotted-key
+ // simple-key = quoted-key / unquoted-key
+ //
+ // unquoted-key = 1*( ALPHA / DIGIT / %x2D / %x5F ) ; A-Z / a-z / 0-9 / - / _
+ // quoted-key = basic-string / literal-string
+ // dotted-key = simple-key 1*( dot-sep simple-key )
+ //
+ // dot-sep = ws %x2E ws ; . Period
+ raw, key, b, err := p.parseSimpleKey(b)
+ if err != nil {
+ return invalidReference, nil, err
+ }
+
+ ref := p.builder.Push(Node{
+ Kind: Key,
+ Raw: p.Range(raw),
+ Data: key,
+ })
+
+ for {
+ b = p.parseWhitespace(b)
+ if len(b) > 0 && b[0] == '.' {
+ b = p.parseWhitespace(b[1:])
+
+ raw, key, b, err = p.parseSimpleKey(b)
+ if err != nil {
+ return ref, nil, err
+ }
+
+ p.builder.PushAndChain(Node{
+ Kind: Key,
+ Raw: p.Range(raw),
+ Data: key,
+ })
+ } else {
+ break
+ }
+ }
+
+ return ref, b, nil
+}
+
+func (p *Parser) parseSimpleKey(b []byte) (raw, key, rest []byte, err error) {
+ if len(b) == 0 {
+ return nil, nil, nil, NewParserError(b, "expected key but found none")
+ }
+
+ // simple-key = quoted-key / unquoted-key
+ // unquoted-key = 1*( ALPHA / DIGIT / %x2D / %x5F ) ; A-Z / a-z / 0-9 / - / _
+ // quoted-key = basic-string / literal-string
+ switch {
+ case b[0] == '\'':
+ return p.parseLiteralString(b)
+ case b[0] == '"':
+ return p.parseBasicString(b)
+ case isUnquotedKeyChar(b[0]):
+ key, rest = scanUnquotedKey(b)
+ return key, key, rest, nil
+ default:
+ return nil, nil, nil, NewParserError(b[0:1], "invalid character at start of key: %c", b[0])
+ }
+}
+
+//nolint:funlen,cyclop
+func (p *Parser) parseBasicString(b []byte) ([]byte, []byte, []byte, error) {
+ // basic-string = quotation-mark *basic-char quotation-mark
+ // quotation-mark = %x22 ; "
+ // basic-char = basic-unescaped / escaped
+ // basic-unescaped = wschar / %x21 / %x23-5B / %x5D-7E / non-ascii
+ // escaped = escape escape-seq-char
+ // escape-seq-char = %x22 ; " quotation mark U+0022
+ // escape-seq-char =/ %x5C ; \ reverse solidus U+005C
+ // escape-seq-char =/ %x62 ; b backspace U+0008
+ // escape-seq-char =/ %x66 ; f form feed U+000C
+ // escape-seq-char =/ %x6E ; n line feed U+000A
+ // escape-seq-char =/ %x72 ; r carriage return U+000D
+ // escape-seq-char =/ %x74 ; t tab U+0009
+ // escape-seq-char =/ %x75 4HEXDIG ; uXXXX U+XXXX
+ // escape-seq-char =/ %x55 8HEXDIG ; UXXXXXXXX U+XXXXXXXX
+ token, escaped, rest, err := scanBasicString(b)
+ if err != nil {
+ return nil, nil, nil, err
+ }
+
+ startIdx := len(`"`)
+ endIdx := len(token) - len(`"`)
+
+ // Fast path. If there is no escape sequence, the string should just be
+ // an UTF-8 encoded string, which is the same as Go. In that case,
+ // validate the string and return a direct reference to the buffer.
+ if !escaped {
+ str := token[startIdx:endIdx]
+ verr := characters.Utf8TomlValidAlreadyEscaped(str)
+ if verr.Zero() {
+ return token, str, rest, nil
+ }
+ return nil, nil, nil, NewParserError(str[verr.Index:verr.Index+verr.Size], "invalid UTF-8")
+ }
+
+ i := startIdx
+
+ var builder bytes.Buffer
+
+ // The scanner ensures that the token starts and ends with quotes and that
+ // escapes are balanced.
+ for i < len(token)-1 {
+ c := token[i]
+ if c == '\\' {
+ i++
+ c = token[i]
+
+ switch c {
+ case '"', '\\':
+ builder.WriteByte(c)
+ case 'b':
+ builder.WriteByte('\b')
+ case 'f':
+ builder.WriteByte('\f')
+ case 'n':
+ builder.WriteByte('\n')
+ case 'r':
+ builder.WriteByte('\r')
+ case 't':
+ builder.WriteByte('\t')
+ case 'e':
+ builder.WriteByte(0x1B)
+ case 'u':
+ x, err := hexToRune(token[i+1:len(token)-1], 4)
+ if err != nil {
+ return nil, nil, nil, err
+ }
+
+ builder.WriteRune(x)
+ i += 4
+ case 'U':
+ x, err := hexToRune(token[i+1:len(token)-1], 8)
+ if err != nil {
+ return nil, nil, nil, err
+ }
+
+ builder.WriteRune(x)
+ i += 8
+ default:
+ return nil, nil, nil, NewParserError(token[i:i+1], "invalid escaped character %#U", c)
+ }
+ i++
+ } else {
+ size := characters.Utf8ValidNext(token[i:])
+ if size == 0 {
+ return nil, nil, nil, NewParserError(token[i:i+1], "invalid character %#U", c)
+ }
+ builder.Write(token[i : i+size])
+ i += size
+ }
+ }
+
+ return token, builder.Bytes(), rest, nil
+}
+
+func hexToRune(b []byte, length int) (rune, error) {
+ if len(b) < length {
+ return -1, NewParserError(b, "unicode point needs %d character, not %d", length, len(b))
+ }
+ b = b[:length]
+
+ var r uint32
+ for i, c := range b {
+ d := uint32(0)
+ switch {
+ case '0' <= c && c <= '9':
+ d = uint32(c - '0')
+ case 'a' <= c && c <= 'f':
+ d = uint32(c - 'a' + 10)
+ case 'A' <= c && c <= 'F':
+ d = uint32(c - 'A' + 10)
+ default:
+ return -1, NewParserError(b[i:i+1], "non-hex character")
+ }
+ r = r*16 + d
+ }
+
+ if r > unicode.MaxRune || 0xD800 <= r && r < 0xE000 {
+ return -1, NewParserError(b, "escape sequence is invalid Unicode code point")
+ }
+
+ return rune(r), nil
+}
+
+func (p *Parser) parseWhitespace(b []byte) []byte {
+ // ws = *wschar
+ // wschar = %x20 ; Space
+ // wschar =/ %x09 ; Horizontal tab
+ _, rest := scanWhitespace(b)
+
+ return rest
+}
+
+//nolint:cyclop
+func (p *Parser) parseIntOrFloatOrDateTime(b []byte) (reference, []byte, error) {
+ switch b[0] {
+ case 'i':
+ if !scanFollowsInf(b) {
+ return invalidReference, nil, NewParserError(atmost(b, 3), "expected 'inf'")
+ }
+
+ return p.builder.Push(Node{
+ Kind: Float,
+ Data: b[:3],
+ }), b[3:], nil
+ case 'n':
+ if !scanFollowsNan(b) {
+ return invalidReference, nil, NewParserError(atmost(b, 3), "expected 'nan'")
+ }
+
+ return p.builder.Push(Node{
+ Kind: Float,
+ Data: b[:3],
+ }), b[3:], nil
+ case '+', '-':
+ return p.scanIntOrFloat(b)
+ }
+
+ if len(b) < 3 {
+ return p.scanIntOrFloat(b)
+ }
+
+ s := 5
+ if len(b) < s {
+ s = len(b)
+ }
+
+ for idx, c := range b[:s] {
+ if isDigit(c) {
+ continue
+ }
+
+ if idx == 2 && c == ':' || (idx == 4 && c == '-') {
+ return p.scanDateTime(b)
+ }
+
+ break
+ }
+
+ return p.scanIntOrFloat(b)
+}
+
+func (p *Parser) scanDateTime(b []byte) (reference, []byte, error) {
+ // scans for contiguous characters in [0-9T:Z.+-], and up to one space if
+ // followed by a digit.
+ hasDate := false
+ hasTime := false
+ hasTz := false
+ seenSpace := false
+
+ i := 0
+byteLoop:
+ for ; i < len(b); i++ {
+ c := b[i]
+
+ switch {
+ case isDigit(c):
+ case c == '-':
+ hasDate = true
+ const minOffsetOfTz = 8
+ if i >= minOffsetOfTz {
+ hasTz = true
+ }
+ case c == 'T' || c == 't' || c == ':' || c == '.':
+ hasTime = true
+ case c == '+' || c == '-' || c == 'Z' || c == 'z':
+ hasTz = true
+ case c == ' ':
+ if !seenSpace && i+1 < len(b) && isDigit(b[i+1]) {
+ i += 2
+ // Avoid reaching past the end of the document in case the time
+ // is malformed. See TestIssue585.
+ if i >= len(b) {
+ i--
+ }
+ seenSpace = true
+ hasTime = true
+ } else {
+ break byteLoop
+ }
+ default:
+ break byteLoop
+ }
+ }
+
+ var kind Kind
+
+ if hasTime {
+ if hasDate {
+ if hasTz {
+ kind = DateTime
+ } else {
+ kind = LocalDateTime
+ }
+ } else {
+ kind = LocalTime
+ }
+ } else {
+ kind = LocalDate
+ }
+
+ return p.builder.Push(Node{
+ Kind: kind,
+ Data: b[:i],
+ }), b[i:], nil
+}
+
+//nolint:funlen,gocognit,cyclop
+func (p *Parser) scanIntOrFloat(b []byte) (reference, []byte, error) {
+ i := 0
+
+ if len(b) > 2 && b[0] == '0' && b[1] != '.' && b[1] != 'e' && b[1] != 'E' {
+ var isValidRune validRuneFn
+
+ switch b[1] {
+ case 'x':
+ isValidRune = isValidHexRune
+ case 'o':
+ isValidRune = isValidOctalRune
+ case 'b':
+ isValidRune = isValidBinaryRune
+ default:
+ i++
+ }
+
+ if isValidRune != nil {
+ i += 2
+ for ; i < len(b); i++ {
+ if !isValidRune(b[i]) {
+ break
+ }
+ }
+ }
+
+ return p.builder.Push(Node{
+ Kind: Integer,
+ Data: b[:i],
+ }), b[i:], nil
+ }
+
+ isFloat := false
+
+ for ; i < len(b); i++ {
+ c := b[i]
+
+ if c >= '0' && c <= '9' || c == '+' || c == '-' || c == '_' {
+ continue
+ }
+
+ if c == '.' || c == 'e' || c == 'E' {
+ isFloat = true
+
+ continue
+ }
+
+ if c == 'i' {
+ if scanFollowsInf(b[i:]) {
+ return p.builder.Push(Node{
+ Kind: Float,
+ Data: b[:i+3],
+ }), b[i+3:], nil
+ }
+
+ return invalidReference, nil, NewParserError(b[i:i+1], "unexpected character 'i' while scanning for a number")
+ }
+
+ if c == 'n' {
+ if scanFollowsNan(b[i:]) {
+ return p.builder.Push(Node{
+ Kind: Float,
+ Data: b[:i+3],
+ }), b[i+3:], nil
+ }
+
+ return invalidReference, nil, NewParserError(b[i:i+1], "unexpected character 'n' while scanning for a number")
+ }
+
+ break
+ }
+
+ if i == 0 {
+ return invalidReference, b, NewParserError(b, "incomplete number")
+ }
+
+ kind := Integer
+
+ if isFloat {
+ kind = Float
+ }
+
+ return p.builder.Push(Node{
+ Kind: kind,
+ Data: b[:i],
+ }), b[i:], nil
+}
+
+func isDigit(r byte) bool {
+ return r >= '0' && r <= '9'
+}
+
+type validRuneFn func(r byte) bool
+
+func isValidHexRune(r byte) bool {
+ return r >= 'a' && r <= 'f' ||
+ r >= 'A' && r <= 'F' ||
+ r >= '0' && r <= '9' ||
+ r == '_'
+}
+
+func isValidOctalRune(r byte) bool {
+ return r >= '0' && r <= '7' || r == '_'
+}
+
+func isValidBinaryRune(r byte) bool {
+ return r == '0' || r == '1' || r == '_'
+}
+
+func expect(x byte, b []byte) ([]byte, error) {
+ if len(b) == 0 {
+ return nil, NewParserError(b, "expected character %c but the document ended here", x)
+ }
+
+ if b[0] != x {
+ return nil, NewParserError(b[0:1], "expected character %c", x)
+ }
+
+ return b[1:], nil
+}
diff --git a/vendor/github.com/pelletier/go-toml/v2/unstable/scanner.go b/vendor/github.com/pelletier/go-toml/v2/unstable/scanner.go
new file mode 100644
index 000000000..0512181d2
--- /dev/null
+++ b/vendor/github.com/pelletier/go-toml/v2/unstable/scanner.go
@@ -0,0 +1,270 @@
+package unstable
+
+import "github.com/pelletier/go-toml/v2/internal/characters"
+
+func scanFollows(b []byte, pattern string) bool {
+ n := len(pattern)
+
+ return len(b) >= n && string(b[:n]) == pattern
+}
+
+func scanFollowsMultilineBasicStringDelimiter(b []byte) bool {
+ return scanFollows(b, `"""`)
+}
+
+func scanFollowsMultilineLiteralStringDelimiter(b []byte) bool {
+ return scanFollows(b, `'''`)
+}
+
+func scanFollowsTrue(b []byte) bool {
+ return scanFollows(b, `true`)
+}
+
+func scanFollowsFalse(b []byte) bool {
+ return scanFollows(b, `false`)
+}
+
+func scanFollowsInf(b []byte) bool {
+ return scanFollows(b, `inf`)
+}
+
+func scanFollowsNan(b []byte) bool {
+ return scanFollows(b, `nan`)
+}
+
+func scanUnquotedKey(b []byte) ([]byte, []byte) {
+ // unquoted-key = 1*( ALPHA / DIGIT / %x2D / %x5F ) ; A-Z / a-z / 0-9 / - / _
+ for i := 0; i < len(b); i++ {
+ if !isUnquotedKeyChar(b[i]) {
+ return b[:i], b[i:]
+ }
+ }
+
+ return b, b[len(b):]
+}
+
+func isUnquotedKeyChar(r byte) bool {
+ return (r >= 'A' && r <= 'Z') || (r >= 'a' && r <= 'z') || (r >= '0' && r <= '9') || r == '-' || r == '_'
+}
+
+func scanLiteralString(b []byte) ([]byte, []byte, error) {
+ // literal-string = apostrophe *literal-char apostrophe
+ // apostrophe = %x27 ; ' apostrophe
+ // literal-char = %x09 / %x20-26 / %x28-7E / non-ascii
+ for i := 1; i < len(b); {
+ switch b[i] {
+ case '\'':
+ return b[:i+1], b[i+1:], nil
+ case '\n', '\r':
+ return nil, nil, NewParserError(b[i:i+1], "literal strings cannot have new lines")
+ }
+ size := characters.Utf8ValidNext(b[i:])
+ if size == 0 {
+ return nil, nil, NewParserError(b[i:i+1], "invalid character")
+ }
+ i += size
+ }
+
+ return nil, nil, NewParserError(b[len(b):], "unterminated literal string")
+}
+
+func scanMultilineLiteralString(b []byte) ([]byte, []byte, error) {
+ // ml-literal-string = ml-literal-string-delim [ newline ] ml-literal-body
+ // ml-literal-string-delim
+ // ml-literal-string-delim = 3apostrophe
+ // ml-literal-body = *mll-content *( mll-quotes 1*mll-content ) [ mll-quotes ]
+ //
+ // mll-content = mll-char / newline
+ // mll-char = %x09 / %x20-26 / %x28-7E / non-ascii
+ // mll-quotes = 1*2apostrophe
+ for i := 3; i < len(b); {
+ switch b[i] {
+ case '\'':
+ if scanFollowsMultilineLiteralStringDelimiter(b[i:]) {
+ i += 3
+
+ // At that point we found 3 apostrophe, and i is the
+ // index of the byte after the third one. The scanner
+ // needs to be eager, because there can be an extra 2
+ // apostrophe that can be accepted at the end of the
+ // string.
+
+ if i >= len(b) || b[i] != '\'' {
+ return b[:i], b[i:], nil
+ }
+ i++
+
+ if i >= len(b) || b[i] != '\'' {
+ return b[:i], b[i:], nil
+ }
+ i++
+
+ if i < len(b) && b[i] == '\'' {
+ return nil, nil, NewParserError(b[i-3:i+1], "''' not allowed in multiline literal string")
+ }
+
+ return b[:i], b[i:], nil
+ }
+ case '\r':
+ if len(b) < i+2 {
+ return nil, nil, NewParserError(b[len(b):], `need a \n after \r`)
+ }
+ if b[i+1] != '\n' {
+ return nil, nil, NewParserError(b[i:i+2], `need a \n after \r`)
+ }
+ i += 2 // skip the \n
+ continue
+ }
+ size := characters.Utf8ValidNext(b[i:])
+ if size == 0 {
+ return nil, nil, NewParserError(b[i:i+1], "invalid character")
+ }
+ i += size
+ }
+
+ return nil, nil, NewParserError(b[len(b):], `multiline literal string not terminated by '''`)
+}
+
+func scanWindowsNewline(b []byte) ([]byte, []byte, error) {
+ const lenCRLF = 2
+ if len(b) < lenCRLF {
+ return nil, nil, NewParserError(b, "windows new line expected")
+ }
+
+ if b[1] != '\n' {
+ return nil, nil, NewParserError(b, `windows new line should be \r\n`)
+ }
+
+ return b[:lenCRLF], b[lenCRLF:], nil
+}
+
+func scanWhitespace(b []byte) ([]byte, []byte) {
+ for i := 0; i < len(b); i++ {
+ switch b[i] {
+ case ' ', '\t':
+ continue
+ default:
+ return b[:i], b[i:]
+ }
+ }
+
+ return b, b[len(b):]
+}
+
+func scanComment(b []byte) ([]byte, []byte, error) {
+ // comment-start-symbol = %x23 ; #
+ // non-ascii = %x80-D7FF / %xE000-10FFFF
+ // non-eol = %x09 / %x20-7F / non-ascii
+ //
+ // comment = comment-start-symbol *non-eol
+
+ for i := 1; i < len(b); {
+ if b[i] == '\n' {
+ return b[:i], b[i:], nil
+ }
+ if b[i] == '\r' {
+ if i+1 < len(b) && b[i+1] == '\n' {
+ return b[:i+1], b[i+1:], nil
+ }
+ return nil, nil, NewParserError(b[i:i+1], "invalid character in comment")
+ }
+ size := characters.Utf8ValidNext(b[i:])
+ if size == 0 {
+ return nil, nil, NewParserError(b[i:i+1], "invalid character in comment")
+ }
+
+ i += size
+ }
+
+ return b, b[len(b):], nil
+}
+
+func scanBasicString(b []byte) ([]byte, bool, []byte, error) {
+ // basic-string = quotation-mark *basic-char quotation-mark
+ // quotation-mark = %x22 ; "
+ // basic-char = basic-unescaped / escaped
+ // basic-unescaped = wschar / %x21 / %x23-5B / %x5D-7E / non-ascii
+ // escaped = escape escape-seq-char
+ escaped := false
+ i := 1
+
+ for ; i < len(b); i++ {
+ switch b[i] {
+ case '"':
+ return b[:i+1], escaped, b[i+1:], nil
+ case '\n', '\r':
+ return nil, escaped, nil, NewParserError(b[i:i+1], "basic strings cannot have new lines")
+ case '\\':
+ if len(b) < i+2 {
+ return nil, escaped, nil, NewParserError(b[i:i+1], "need a character after \\")
+ }
+ escaped = true
+ i++ // skip the next character
+ }
+ }
+
+ return nil, escaped, nil, NewParserError(b[len(b):], `basic string not terminated by "`)
+}
+
+func scanMultilineBasicString(b []byte) ([]byte, bool, []byte, error) {
+ // ml-basic-string = ml-basic-string-delim [ newline ] ml-basic-body
+ // ml-basic-string-delim
+ // ml-basic-string-delim = 3quotation-mark
+ // ml-basic-body = *mlb-content *( mlb-quotes 1*mlb-content ) [ mlb-quotes ]
+ //
+ // mlb-content = mlb-char / newline / mlb-escaped-nl
+ // mlb-char = mlb-unescaped / escaped
+ // mlb-quotes = 1*2quotation-mark
+ // mlb-unescaped = wschar / %x21 / %x23-5B / %x5D-7E / non-ascii
+ // mlb-escaped-nl = escape ws newline *( wschar / newline )
+
+ escaped := false
+ i := 3
+
+ for ; i < len(b); i++ {
+ switch b[i] {
+ case '"':
+ if scanFollowsMultilineBasicStringDelimiter(b[i:]) {
+ i += 3
+
+ // At that point we found 3 apostrophe, and i is the
+ // index of the byte after the third one. The scanner
+ // needs to be eager, because there can be an extra 2
+ // apostrophe that can be accepted at the end of the
+ // string.
+
+ if i >= len(b) || b[i] != '"' {
+ return b[:i], escaped, b[i:], nil
+ }
+ i++
+
+ if i >= len(b) || b[i] != '"' {
+ return b[:i], escaped, b[i:], nil
+ }
+ i++
+
+ if i < len(b) && b[i] == '"' {
+ return nil, escaped, nil, NewParserError(b[i-3:i+1], `""" not allowed in multiline basic string`)
+ }
+
+ return b[:i], escaped, b[i:], nil
+ }
+ case '\\':
+ if len(b) < i+2 {
+ return nil, escaped, nil, NewParserError(b[len(b):], "need a character after \\")
+ }
+ escaped = true
+ i++ // skip the next character
+ case '\r':
+ if len(b) < i+2 {
+ return nil, escaped, nil, NewParserError(b[len(b):], `need a \n after \r`)
+ }
+ if b[i+1] != '\n' {
+ return nil, escaped, nil, NewParserError(b[i:i+2], `need a \n after \r`)
+ }
+ i++ // skip the \n
+ }
+ }
+
+ return nil, escaped, nil, NewParserError(b[len(b):], `multiline basic string not terminated by """`)
+}
diff --git a/vendor/github.com/spf13/afero/.travis.yml b/vendor/github.com/spf13/afero/.travis.yml
deleted file mode 100644
index e944f5947..000000000
--- a/vendor/github.com/spf13/afero/.travis.yml
+++ /dev/null
@@ -1,26 +0,0 @@
-sudo: false
-language: go
-arch:
- - amd64
- - ppc64e
-
-go:
- - "1.14"
- - "1.15"
- - "1.16"
- - tip
-
-os:
- - linux
- - osx
-
-matrix:
- allow_failures:
- - go: tip
- fast_finish: true
-
-script:
- - go build -v ./...
- - go test -count=1 -cover -race -v ./...
- - go vet ./...
- - FILES=$(gofmt -s -l . zipfs sftpfs mem tarfs); if [[ -n "${FILES}" ]]; then echo "You have go format errors; gofmt your changes"; exit 1; fi
diff --git a/vendor/github.com/spf13/afero/README.md b/vendor/github.com/spf13/afero/README.md
index fb8eaaf89..3bafbfdfc 100644
--- a/vendor/github.com/spf13/afero/README.md
+++ b/vendor/github.com/spf13/afero/README.md
@@ -2,7 +2,7 @@
A FileSystem Abstraction System for Go
-[![Build Status](https://travis-ci.org/spf13/afero.svg)](https://travis-ci.org/spf13/afero) [![Build status](https://ci.appveyor.com/api/projects/status/github/spf13/afero?branch=master&svg=true)](https://ci.appveyor.com/project/spf13/afero) [![GoDoc](https://godoc.org/github.com/spf13/afero?status.svg)](https://godoc.org/github.com/spf13/afero) [![Join the chat at https://gitter.im/spf13/afero](https://badges.gitter.im/Dev%20Chat.svg)](https://gitter.im/spf13/afero?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
+[![Test](https://github.com/spf13/afero/actions/workflows/test.yml/badge.svg)](https://github.com/spf13/afero/actions/workflows/test.yml) [![GoDoc](https://godoc.org/github.com/spf13/afero?status.svg)](https://godoc.org/github.com/spf13/afero) [![Join the chat at https://gitter.im/spf13/afero](https://badges.gitter.im/Dev%20Chat.svg)](https://gitter.im/spf13/afero?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
# Overview
@@ -79,11 +79,11 @@ would.
So if my application before had:
```go
-os.Open('/tmp/foo')
+os.Open("/tmp/foo")
```
We would replace it with:
```go
-AppFs.Open('/tmp/foo')
+AppFs.Open("/tmp/foo")
```
`AppFs` being the variable we defined above.
@@ -259,6 +259,18 @@ system using InMemoryFile.
Afero has experimental support for secure file transfer protocol (sftp). Which can
be used to perform file operations over a encrypted channel.
+### GCSFs
+
+Afero has experimental support for Google Cloud Storage (GCS). You can either set the
+`GOOGLE_APPLICATION_CREDENTIALS_JSON` env variable to your JSON credentials or use `opts` in
+`NewGcsFS` to configure access to your GCS bucket.
+
+Some known limitations of the existing implementation:
+* No Chmod support - The GCS ACL could probably be mapped to *nix style permissions but that would add another level of complexity and is ignored in this version.
+* No Chtimes support - Could be simulated with attributes (gcs a/m-times are set implicitly) but that's is left for another version.
+* Not thread safe - Also assumes all file operations are done through the same instance of the GcsFs. File operations between different GcsFs instances are not guaranteed to be consistent.
+
+
## Filtering Backends
### BasePathFs
diff --git a/vendor/github.com/spf13/afero/afero.go b/vendor/github.com/spf13/afero/afero.go
index 469ff7d2d..39f658520 100644
--- a/vendor/github.com/spf13/afero/afero.go
+++ b/vendor/github.com/spf13/afero/afero.go
@@ -97,14 +97,14 @@ type Fs interface {
// Chown changes the uid and gid of the named file.
Chown(name string, uid, gid int) error
- //Chtimes changes the access and modification times of the named file
+ // Chtimes changes the access and modification times of the named file
Chtimes(name string, atime time.Time, mtime time.Time) error
}
var (
ErrFileClosed = errors.New("File is closed")
- ErrOutOfRange = errors.New("Out of range")
- ErrTooLarge = errors.New("Too large")
+ ErrOutOfRange = errors.New("out of range")
+ ErrTooLarge = errors.New("too large")
ErrFileNotFound = os.ErrNotExist
ErrFileExists = os.ErrExist
ErrDestinationExists = os.ErrExist
diff --git a/vendor/github.com/spf13/afero/appveyor.yml b/vendor/github.com/spf13/afero/appveyor.yml
index 5d2f34bf1..65e20e8ca 100644
--- a/vendor/github.com/spf13/afero/appveyor.yml
+++ b/vendor/github.com/spf13/afero/appveyor.yml
@@ -1,3 +1,5 @@
+# This currently does nothing. We have moved to GitHub action, but this is kept
+# until spf13 has disabled this project in AppVeyor.
version: '{build}'
clone_folder: C:\gopath\src\github.com\spf13\afero
environment:
@@ -6,10 +8,3 @@ build_script:
- cmd: >-
go version
- go env
-
- go get -v github.com/spf13/afero/...
-
- go build -v github.com/spf13/afero/...
-test_script:
-- cmd: go test -count=1 -cover -race -v github.com/spf13/afero/...
diff --git a/vendor/github.com/spf13/afero/basepath.go b/vendor/github.com/spf13/afero/basepath.go
index 4f9832829..2e72793a3 100644
--- a/vendor/github.com/spf13/afero/basepath.go
+++ b/vendor/github.com/spf13/afero/basepath.go
@@ -1,6 +1,7 @@
package afero
import (
+ "io/fs"
"os"
"path/filepath"
"runtime"
@@ -8,7 +9,10 @@ import (
"time"
)
-var _ Lstater = (*BasePathFs)(nil)
+var (
+ _ Lstater = (*BasePathFs)(nil)
+ _ fs.ReadDirFile = (*BasePathFile)(nil)
+)
// The BasePathFs restricts all operations to a given path within an Fs.
// The given file name to the operations on this Fs will be prepended with
@@ -33,6 +37,13 @@ func (f *BasePathFile) Name() string {
return strings.TrimPrefix(sourcename, filepath.Clean(f.path))
}
+func (f *BasePathFile) ReadDir(n int) ([]fs.DirEntry, error) {
+ if rdf, ok := f.File.(fs.ReadDirFile); ok {
+ return rdf.ReadDir(n)
+ }
+ return readDirFile{f.File}.ReadDir(n)
+}
+
func NewBasePathFs(source Fs, path string) Fs {
return &BasePathFs{source: source, path: path}
}
diff --git a/vendor/github.com/spf13/afero/cacheOnReadFs.go b/vendor/github.com/spf13/afero/cacheOnReadFs.go
index 71471aa25..017d344fd 100644
--- a/vendor/github.com/spf13/afero/cacheOnReadFs.go
+++ b/vendor/github.com/spf13/afero/cacheOnReadFs.go
@@ -75,6 +75,10 @@ func (u *CacheOnReadFs) copyToLayer(name string) error {
return copyToLayer(u.base, u.layer, name)
}
+func (u *CacheOnReadFs) copyFileToLayer(name string, flag int, perm os.FileMode) error {
+ return copyFileToLayer(u.base, u.layer, name, flag, perm)
+}
+
func (u *CacheOnReadFs) Chtimes(name string, atime, mtime time.Time) error {
st, _, err := u.cacheStatus(name)
if err != nil {
@@ -212,7 +216,7 @@ func (u *CacheOnReadFs) OpenFile(name string, flag int, perm os.FileMode) (File,
switch st {
case cacheLocal, cacheHit:
default:
- if err := u.copyToLayer(name); err != nil {
+ if err := u.copyFileToLayer(name, flag, perm); err != nil {
return nil, err
}
}
diff --git a/vendor/github.com/spf13/afero/const_bsds.go b/vendor/github.com/spf13/afero/const_bsds.go
index 18b45824b..eed0f225f 100644
--- a/vendor/github.com/spf13/afero/const_bsds.go
+++ b/vendor/github.com/spf13/afero/const_bsds.go
@@ -11,6 +11,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+//go:build aix || darwin || openbsd || freebsd || netbsd || dragonfly
// +build aix darwin openbsd freebsd netbsd dragonfly
package afero
diff --git a/vendor/github.com/spf13/afero/const_win_unix.go b/vendor/github.com/spf13/afero/const_win_unix.go
index 2b850e4dd..004d57e2f 100644
--- a/vendor/github.com/spf13/afero/const_win_unix.go
+++ b/vendor/github.com/spf13/afero/const_win_unix.go
@@ -10,12 +10,8 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-// +build !darwin
-// +build !openbsd
-// +build !freebsd
-// +build !dragonfly
-// +build !netbsd
-// +build !aix
+//go:build !darwin && !openbsd && !freebsd && !dragonfly && !netbsd && !aix
+// +build !darwin,!openbsd,!freebsd,!dragonfly,!netbsd,!aix
package afero
diff --git a/vendor/github.com/spf13/afero/copyOnWriteFs.go b/vendor/github.com/spf13/afero/copyOnWriteFs.go
index 6ff8f3099..184d6dd70 100644
--- a/vendor/github.com/spf13/afero/copyOnWriteFs.go
+++ b/vendor/github.com/spf13/afero/copyOnWriteFs.go
@@ -223,7 +223,7 @@ func (u *CopyOnWriteFs) OpenFile(name string, flag int, perm os.FileMode) (File,
return nil, err
}
if isaDir {
- if err = u.layer.MkdirAll(dir, 0777); err != nil {
+ if err = u.layer.MkdirAll(dir, 0o777); err != nil {
return nil, err
}
return u.layer.OpenFile(name, flag, perm)
@@ -247,8 +247,9 @@ func (u *CopyOnWriteFs) OpenFile(name string, flag int, perm os.FileMode) (File,
// This function handles the 9 different possibilities caused
// by the union which are the intersection of the following...
-// layer: doesn't exist, exists as a file, and exists as a directory
-// base: doesn't exist, exists as a file, and exists as a directory
+//
+// layer: doesn't exist, exists as a file, and exists as a directory
+// base: doesn't exist, exists as a file, and exists as a directory
func (u *CopyOnWriteFs) Open(name string) (File, error) {
// Since the overlay overrides the base we check that first
b, err := u.isBaseFile(name)
@@ -322,5 +323,5 @@ func (u *CopyOnWriteFs) MkdirAll(name string, perm os.FileMode) error {
}
func (u *CopyOnWriteFs) Create(name string) (File, error) {
- return u.OpenFile(name, os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0666)
+ return u.OpenFile(name, os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0o666)
}
diff --git a/vendor/github.com/spf13/afero/httpFs.go b/vendor/github.com/spf13/afero/httpFs.go
index 2b86e30d1..ac0de6d51 100644
--- a/vendor/github.com/spf13/afero/httpFs.go
+++ b/vendor/github.com/spf13/afero/httpFs.go
@@ -29,7 +29,7 @@ type httpDir struct {
}
func (d httpDir) Open(name string) (http.File, error) {
- if filepath.Separator != '/' && strings.IndexRune(name, filepath.Separator) >= 0 ||
+ if filepath.Separator != '/' && strings.ContainsRune(name, filepath.Separator) ||
strings.Contains(name, "\x00") {
return nil, errors.New("http: invalid character in file path")
}
diff --git a/vendor/github.com/spf13/afero/internal/common/adapters.go b/vendor/github.com/spf13/afero/internal/common/adapters.go
new file mode 100644
index 000000000..60685caa5
--- /dev/null
+++ b/vendor/github.com/spf13/afero/internal/common/adapters.go
@@ -0,0 +1,27 @@
+// Copyright © 2022 Steve Francia .
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package common
+
+import "io/fs"
+
+// FileInfoDirEntry provides an adapter from os.FileInfo to fs.DirEntry
+type FileInfoDirEntry struct {
+ fs.FileInfo
+}
+
+var _ fs.DirEntry = FileInfoDirEntry{}
+
+func (d FileInfoDirEntry) Type() fs.FileMode { return d.FileInfo.Mode().Type() }
+
+func (d FileInfoDirEntry) Info() (fs.FileInfo, error) { return d.FileInfo, nil }
diff --git a/vendor/github.com/spf13/afero/iofs.go b/vendor/github.com/spf13/afero/iofs.go
index c80345536..938b9316e 100644
--- a/vendor/github.com/spf13/afero/iofs.go
+++ b/vendor/github.com/spf13/afero/iofs.go
@@ -1,3 +1,4 @@
+//go:build go1.16
// +build go1.16
package afero
@@ -7,7 +8,10 @@ import (
"io/fs"
"os"
"path"
+ "sort"
"time"
+
+ "github.com/spf13/afero/internal/common"
)
// IOFS adopts afero.Fs to stdlib io/fs.FS
@@ -66,14 +70,31 @@ func (iofs IOFS) Glob(pattern string) ([]string, error) {
}
func (iofs IOFS) ReadDir(name string) ([]fs.DirEntry, error) {
- items, err := ReadDir(iofs.Fs, name)
+ f, err := iofs.Fs.Open(name)
if err != nil {
return nil, iofs.wrapError("readdir", name, err)
}
+ defer f.Close()
+
+ if rdf, ok := f.(fs.ReadDirFile); ok {
+ items, err := rdf.ReadDir(-1)
+ if err != nil {
+ return nil, iofs.wrapError("readdir", name, err)
+ }
+ sort.Slice(items, func(i, j int) bool { return items[i].Name() < items[j].Name() })
+ return items, nil
+ }
+
+ items, err := f.Readdir(-1)
+ if err != nil {
+ return nil, iofs.wrapError("readdir", name, err)
+ }
+ sort.Sort(byName(items))
+
ret := make([]fs.DirEntry, len(items))
for i := range items {
- ret[i] = dirEntry{items[i]}
+ ret[i] = common.FileInfoDirEntry{FileInfo: items[i]}
}
return ret, nil
@@ -108,17 +129,6 @@ func (IOFS) wrapError(op, path string, err error) error {
}
}
-// dirEntry provides adapter from os.FileInfo to fs.DirEntry
-type dirEntry struct {
- fs.FileInfo
-}
-
-var _ fs.DirEntry = dirEntry{}
-
-func (d dirEntry) Type() fs.FileMode { return d.FileInfo.Mode().Type() }
-
-func (d dirEntry) Info() (fs.FileInfo, error) { return d.FileInfo, nil }
-
// readDirFile provides adapter from afero.File to fs.ReadDirFile needed for correct Open
type readDirFile struct {
File
@@ -134,7 +144,7 @@ func (r readDirFile) ReadDir(n int) ([]fs.DirEntry, error) {
ret := make([]fs.DirEntry, len(items))
for i := range items {
- ret[i] = dirEntry{items[i]}
+ ret[i] = common.FileInfoDirEntry{FileInfo: items[i]}
}
return ret, nil
diff --git a/vendor/github.com/spf13/afero/ioutil.go b/vendor/github.com/spf13/afero/ioutil.go
index a403133e2..fa6abe1ee 100644
--- a/vendor/github.com/spf13/afero/ioutil.go
+++ b/vendor/github.com/spf13/afero/ioutil.go
@@ -141,8 +141,10 @@ func WriteFile(fs Fs, filename string, data []byte, perm os.FileMode) error {
// We generate random temporary file names so that there's a good
// chance the file doesn't exist yet - keeps the number of tries in
// TempFile to a minimum.
-var rand uint32
-var randmu sync.Mutex
+var (
+ randNum uint32
+ randmu sync.Mutex
+)
func reseed() uint32 {
return uint32(time.Now().UnixNano() + int64(os.Getpid()))
@@ -150,12 +152,12 @@ func reseed() uint32 {
func nextRandom() string {
randmu.Lock()
- r := rand
+ r := randNum
if r == 0 {
r = reseed()
}
r = r*1664525 + 1013904223 // constants from Numerical Recipes
- rand = r
+ randNum = r
randmu.Unlock()
return strconv.Itoa(int(1e9 + r%1e9))[1:]
}
@@ -190,11 +192,11 @@ func TempFile(fs Fs, dir, pattern string) (f File, err error) {
nconflict := 0
for i := 0; i < 10000; i++ {
name := filepath.Join(dir, prefix+nextRandom()+suffix)
- f, err = fs.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600)
+ f, err = fs.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0o600)
if os.IsExist(err) {
if nconflict++; nconflict > 10 {
randmu.Lock()
- rand = reseed()
+ randNum = reseed()
randmu.Unlock()
}
continue
@@ -214,6 +216,7 @@ func TempFile(fs Fs, dir, pattern string) (f File, err error) {
func (a Afero) TempDir(dir, prefix string) (name string, err error) {
return TempDir(a.Fs, dir, prefix)
}
+
func TempDir(fs Fs, dir, prefix string) (name string, err error) {
if dir == "" {
dir = os.TempDir()
@@ -222,11 +225,11 @@ func TempDir(fs Fs, dir, prefix string) (name string, err error) {
nconflict := 0
for i := 0; i < 10000; i++ {
try := filepath.Join(dir, prefix+nextRandom())
- err = fs.Mkdir(try, 0700)
+ err = fs.Mkdir(try, 0o700)
if os.IsExist(err) {
if nconflict++; nconflict > 10 {
randmu.Lock()
- rand = reseed()
+ randNum = reseed()
randmu.Unlock()
}
continue
diff --git a/vendor/github.com/spf13/afero/mem/file.go b/vendor/github.com/spf13/afero/mem/file.go
index 5a20730c2..62fe4498e 100644
--- a/vendor/github.com/spf13/afero/mem/file.go
+++ b/vendor/github.com/spf13/afero/mem/file.go
@@ -18,15 +18,20 @@ import (
"bytes"
"errors"
"io"
+ "io/fs"
"os"
"path/filepath"
"sync"
"sync/atomic"
"time"
+
+ "github.com/spf13/afero/internal/common"
)
const FilePathSeparator = string(filepath.Separator)
+var _ fs.ReadDirFile = &File{}
+
type File struct {
// atomic requires 64-bit alignment for struct field access
at int64
@@ -71,7 +76,7 @@ func CreateFile(name string) *FileData {
}
func CreateDir(name string) *FileData {
- return &FileData{name: name, memDir: &DirMap{}, dir: true}
+ return &FileData{name: name, memDir: &DirMap{}, dir: true, modtime: time.Now()}
}
func ChangeFileName(f *FileData, newname string) {
@@ -183,10 +188,23 @@ func (f *File) Readdirnames(n int) (names []string, err error) {
return names, err
}
+// Implements fs.ReadDirFile
+func (f *File) ReadDir(n int) ([]fs.DirEntry, error) {
+ fi, err := f.Readdir(n)
+ if err != nil {
+ return nil, err
+ }
+ di := make([]fs.DirEntry, len(fi))
+ for i, f := range fi {
+ di[i] = common.FileInfoDirEntry{FileInfo: f}
+ }
+ return di, nil
+}
+
func (f *File) Read(b []byte) (n int, err error) {
f.fileData.Lock()
defer f.fileData.Unlock()
- if f.closed == true {
+ if f.closed {
return 0, ErrFileClosed
}
if len(b) > 0 && int(f.at) == len(f.fileData.data) {
@@ -214,7 +232,7 @@ func (f *File) ReadAt(b []byte, off int64) (n int, err error) {
}
func (f *File) Truncate(size int64) error {
- if f.closed == true {
+ if f.closed {
return ErrFileClosed
}
if f.readOnly {
@@ -227,7 +245,7 @@ func (f *File) Truncate(size int64) error {
defer f.fileData.Unlock()
if size > int64(len(f.fileData.data)) {
diff := size - int64(len(f.fileData.data))
- f.fileData.data = append(f.fileData.data, bytes.Repeat([]byte{00}, int(diff))...)
+ f.fileData.data = append(f.fileData.data, bytes.Repeat([]byte{0o0}, int(diff))...)
} else {
f.fileData.data = f.fileData.data[0:size]
}
@@ -236,7 +254,7 @@ func (f *File) Truncate(size int64) error {
}
func (f *File) Seek(offset int64, whence int) (int64, error) {
- if f.closed == true {
+ if f.closed {
return 0, ErrFileClosed
}
switch whence {
@@ -251,7 +269,7 @@ func (f *File) Seek(offset int64, whence int) (int64, error) {
}
func (f *File) Write(b []byte) (n int, err error) {
- if f.closed == true {
+ if f.closed {
return 0, ErrFileClosed
}
if f.readOnly {
@@ -267,7 +285,7 @@ func (f *File) Write(b []byte) (n int, err error) {
tail = f.fileData.data[n+int(cur):]
}
if diff > 0 {
- f.fileData.data = append(f.fileData.data, append(bytes.Repeat([]byte{00}, int(diff)), b...)...)
+ f.fileData.data = append(f.fileData.data, append(bytes.Repeat([]byte{0o0}, int(diff)), b...)...)
f.fileData.data = append(f.fileData.data, tail...)
} else {
f.fileData.data = append(f.fileData.data[:cur], b...)
@@ -303,16 +321,19 @@ func (s *FileInfo) Name() string {
s.Unlock()
return name
}
+
func (s *FileInfo) Mode() os.FileMode {
s.Lock()
defer s.Unlock()
return s.mode
}
+
func (s *FileInfo) ModTime() time.Time {
s.Lock()
defer s.Unlock()
return s.modtime
}
+
func (s *FileInfo) IsDir() bool {
s.Lock()
defer s.Unlock()
@@ -330,8 +351,8 @@ func (s *FileInfo) Size() int64 {
var (
ErrFileClosed = errors.New("File is closed")
- ErrOutOfRange = errors.New("Out of range")
- ErrTooLarge = errors.New("Too large")
+ ErrOutOfRange = errors.New("out of range")
+ ErrTooLarge = errors.New("too large")
ErrFileNotFound = os.ErrNotExist
ErrFileExists = os.ErrExist
ErrDestinationExists = os.ErrExist
diff --git a/vendor/github.com/spf13/afero/memmap.go b/vendor/github.com/spf13/afero/memmap.go
index 5c265f92b..e6b7d70b9 100644
--- a/vendor/github.com/spf13/afero/memmap.go
+++ b/vendor/github.com/spf13/afero/memmap.go
@@ -15,6 +15,7 @@ package afero
import (
"fmt"
+ "io"
"log"
"os"
"path/filepath"
@@ -43,7 +44,7 @@ func (m *MemMapFs) getData() map[string]*mem.FileData {
// Root should always exist, right?
// TODO: what about windows?
root := mem.CreateDir(FilePathSeparator)
- mem.SetMode(root, os.ModeDir|0755)
+ mem.SetMode(root, os.ModeDir|0o755)
m.data[FilePathSeparator] = root
})
return m.data
@@ -96,12 +97,12 @@ func (m *MemMapFs) registerWithParent(f *mem.FileData, perm os.FileMode) {
pdir := filepath.Dir(filepath.Clean(f.Name()))
err := m.lockfreeMkdir(pdir, perm)
if err != nil {
- //log.Println("Mkdir error:", err)
+ // log.Println("Mkdir error:", err)
return
}
parent, err = m.lockfreeOpen(pdir)
if err != nil {
- //log.Println("Open after Mkdir error:", err)
+ // log.Println("Open after Mkdir error:", err)
return
}
}
@@ -142,6 +143,11 @@ func (m *MemMapFs) Mkdir(name string, perm os.FileMode) error {
}
m.mu.Lock()
+ // Dobule check that it doesn't exist.
+ if _, ok := m.getData()[name]; ok {
+ m.mu.Unlock()
+ return &os.PathError{Op: "mkdir", Path: name, Err: ErrFileExists}
+ }
item := mem.CreateDir(name)
mem.SetMode(item, os.ModeDir|perm)
m.getData()[name] = item
@@ -232,7 +238,7 @@ func (m *MemMapFs) OpenFile(name string, flag int, perm os.FileMode) (File, erro
file = mem.NewReadOnlyFileHandle(file.(*mem.File).Data())
}
if flag&os.O_APPEND > 0 {
- _, err = file.Seek(0, os.SEEK_END)
+ _, err = file.Seek(0, io.SeekEnd)
if err != nil {
file.Close()
return nil, err
@@ -279,7 +285,7 @@ func (m *MemMapFs) RemoveAll(path string) error {
defer m.mu.RUnlock()
for p := range m.getData() {
- if strings.HasPrefix(p, path) {
+ if p == path || strings.HasPrefix(p, path+FilePathSeparator) {
m.mu.RUnlock()
m.mu.Lock()
delete(m.getData(), p)
@@ -314,6 +320,18 @@ func (m *MemMapFs) Rename(oldname, newname string) error {
} else {
return &os.PathError{Op: "rename", Path: oldname, Err: ErrFileNotFound}
}
+
+ for p, fileData := range m.getData() {
+ if strings.HasPrefix(p, oldname+FilePathSeparator) {
+ m.mu.RUnlock()
+ m.mu.Lock()
+ delete(m.getData(), p)
+ p := strings.Replace(p, oldname, newname, 1)
+ m.getData()[p] = fileData
+ m.mu.Unlock()
+ m.mu.RLock()
+ }
+ }
return nil
}
diff --git a/vendor/github.com/spf13/afero/regexpfs.go b/vendor/github.com/spf13/afero/regexpfs.go
index ac359c62a..218f3b235 100644
--- a/vendor/github.com/spf13/afero/regexpfs.go
+++ b/vendor/github.com/spf13/afero/regexpfs.go
@@ -10,7 +10,6 @@ import (
// The RegexpFs filters files (not directories) by regular expression. Only
// files matching the given regexp will be allowed, all others get a ENOENT error (
// "No such file or directory").
-//
type RegexpFs struct {
re *regexp.Regexp
source Fs
diff --git a/vendor/github.com/spf13/afero/symlink.go b/vendor/github.com/spf13/afero/symlink.go
index d1c6ea53d..aa6ae125b 100644
--- a/vendor/github.com/spf13/afero/symlink.go
+++ b/vendor/github.com/spf13/afero/symlink.go
@@ -21,9 +21,9 @@ import (
// filesystems saying so.
// It indicates support for 3 symlink related interfaces that implement the
// behaviors of the os methods:
-// - Lstat
-// - Symlink, and
-// - Readlink
+// - Lstat
+// - Symlink, and
+// - Readlink
type Symlinker interface {
Lstater
Linker
diff --git a/vendor/github.com/spf13/afero/unionFile.go b/vendor/github.com/spf13/afero/unionFile.go
index 985363eea..62dd6c93c 100644
--- a/vendor/github.com/spf13/afero/unionFile.go
+++ b/vendor/github.com/spf13/afero/unionFile.go
@@ -47,7 +47,7 @@ func (f *UnionFile) Read(s []byte) (int, error) {
if (err == nil || err == io.EOF) && f.Base != nil {
// advance the file position also in the base file, the next
// call may be a write at this position (or a seek with SEEK_CUR)
- if _, seekErr := f.Base.Seek(int64(n), os.SEEK_CUR); seekErr != nil {
+ if _, seekErr := f.Base.Seek(int64(n), io.SeekCurrent); seekErr != nil {
// only overwrite err in case the seek fails: we need to
// report an eventual io.EOF to the caller
err = seekErr
@@ -65,7 +65,7 @@ func (f *UnionFile) ReadAt(s []byte, o int64) (int, error) {
if f.Layer != nil {
n, err := f.Layer.ReadAt(s, o)
if (err == nil || err == io.EOF) && f.Base != nil {
- _, err = f.Base.Seek(o+int64(n), os.SEEK_SET)
+ _, err = f.Base.Seek(o+int64(n), io.SeekStart)
}
return n, err
}
@@ -130,7 +130,7 @@ func (f *UnionFile) Name() string {
type DirsMerger func(lofi, bofi []os.FileInfo) ([]os.FileInfo, error)
var defaultUnionMergeDirsFn = func(lofi, bofi []os.FileInfo) ([]os.FileInfo, error) {
- var files = make(map[string]os.FileInfo)
+ files := make(map[string]os.FileInfo)
for _, fi := range lofi {
files[fi.Name()] = fi
@@ -151,7 +151,6 @@ var defaultUnionMergeDirsFn = func(lofi, bofi []os.FileInfo) ([]os.FileInfo, err
}
return rfi, nil
-
}
// Readdir will weave the two directories together and
@@ -268,20 +267,14 @@ func (f *UnionFile) WriteString(s string) (n int, err error) {
return 0, BADFD
}
-func copyToLayer(base Fs, layer Fs, name string) error {
- bfh, err := base.Open(name)
- if err != nil {
- return err
- }
- defer bfh.Close()
-
+func copyFile(base Fs, layer Fs, name string, bfh File) error {
// First make sure the directory exists
exists, err := Exists(layer, filepath.Dir(name))
if err != nil {
return err
}
if !exists {
- err = layer.MkdirAll(filepath.Dir(name), 0777) // FIXME?
+ err = layer.MkdirAll(filepath.Dir(name), 0o777) // FIXME?
if err != nil {
return err
}
@@ -315,3 +308,23 @@ func copyToLayer(base Fs, layer Fs, name string) error {
}
return layer.Chtimes(name, bfi.ModTime(), bfi.ModTime())
}
+
+func copyToLayer(base Fs, layer Fs, name string) error {
+ bfh, err := base.Open(name)
+ if err != nil {
+ return err
+ }
+ defer bfh.Close()
+
+ return copyFile(base, layer, name, bfh)
+}
+
+func copyFileToLayer(base Fs, layer Fs, name string, flag int, perm os.FileMode) error {
+ bfh, err := base.OpenFile(name, flag, perm)
+ if err != nil {
+ return err
+ }
+ defer bfh.Close()
+
+ return copyFile(base, layer, name, bfh)
+}
diff --git a/vendor/github.com/spf13/afero/util.go b/vendor/github.com/spf13/afero/util.go
index 4f253f481..9e4cba274 100644
--- a/vendor/github.com/spf13/afero/util.go
+++ b/vendor/github.com/spf13/afero/util.go
@@ -25,6 +25,7 @@ import (
"strings"
"unicode"
+ "golang.org/x/text/runes"
"golang.org/x/text/transform"
"golang.org/x/text/unicode/norm"
)
@@ -42,7 +43,7 @@ func WriteReader(fs Fs, path string, r io.Reader) (err error) {
ospath := filepath.FromSlash(dir)
if ospath != "" {
- err = fs.MkdirAll(ospath, 0777) // rwx, rw, r
+ err = fs.MkdirAll(ospath, 0o777) // rwx, rw, r
if err != nil {
if err != os.ErrExist {
return err
@@ -70,7 +71,7 @@ func SafeWriteReader(fs Fs, path string, r io.Reader) (err error) {
ospath := filepath.FromSlash(dir)
if ospath != "" {
- err = fs.MkdirAll(ospath, 0777) // rwx, rw, r
+ err = fs.MkdirAll(ospath, 0o777) // rwx, rw, r
if err != nil {
return
}
@@ -123,7 +124,7 @@ func GetTempDir(fs Fs, subPath string) string {
return addSlash(dir)
}
- err := fs.MkdirAll(dir, 0777)
+ err := fs.MkdirAll(dir, 0o777)
if err != nil {
panic(err)
}
@@ -158,16 +159,12 @@ func UnicodeSanitize(s string) string {
// Transform characters with accents into plain forms.
func NeuterAccents(s string) string {
- t := transform.Chain(norm.NFD, transform.RemoveFunc(isMn), norm.NFC)
+ t := transform.Chain(norm.NFD, runes.Remove(runes.In(unicode.Mn)), norm.NFC)
result, _, _ := transform.String(t, string(s))
return result
}
-func isMn(r rune) bool {
- return unicode.Is(unicode.Mn, r) // Mn: nonspacing marks
-}
-
func (a Afero) FileContainsBytes(filename string, subslice []byte) (bool, error) {
return FileContainsBytes(a.Fs, filename, subslice)
}
@@ -200,7 +197,6 @@ func FileContainsAnyBytes(fs Fs, filename string, subslices [][]byte) (bool, err
// readerContains reports whether any of the subslices is within r.
func readerContainsAny(r io.Reader, subslices ...[]byte) bool {
-
if r == nil || len(subslices) == 0 {
return false
}
@@ -299,6 +295,9 @@ func IsEmpty(fs Fs, path string) (bool, error) {
}
defer f.Close()
list, err := f.Readdir(-1)
+ if err != nil {
+ return false, err
+ }
return len(list) == 0, nil
}
return fi.Size() == 0, nil
diff --git a/vendor/github.com/spf13/cast/README.md b/vendor/github.com/spf13/cast/README.md
index 120a57342..58141f02f 100644
--- a/vendor/github.com/spf13/cast/README.md
+++ b/vendor/github.com/spf13/cast/README.md
@@ -1,7 +1,8 @@
-cast
-====
-[![GoDoc](https://godoc.org/github.com/spf13/cast?status.svg)](https://godoc.org/github.com/spf13/cast)
-[![Build Status](https://github.com/spf13/cast/actions/workflows/go.yml/badge.svg)](https://github.com/spf13/cast/actions/workflows/go.yml)
+# cast
+
+[![Build Status](https://github.com/spf13/cast/actions/workflows/ci.yml/badge.svg)](https://github.com/spf13/cast/actions/workflows/ci.yml)
+[![PkgGoDev](https://pkg.go.dev/badge/mod/github.com/spf13/cast)](https://pkg.go.dev/mod/github.com/spf13/cast)
+![Go Version](https://img.shields.io/badge/go%20version-%3E=1.16-61CFDD.svg?style=flat-square)
[![Go Report Card](https://goreportcard.com/badge/github.com/spf13/cast)](https://goreportcard.com/report/github.com/spf13/cast)
Easy and safe casting from one type to another in Go
@@ -17,7 +18,7 @@ interface into a bool, etc. Cast does this intelligently when an obvious
conversion is possible. It doesn’t make any attempts to guess what you meant,
for example you can only convert a string to an int when it is a string
representation of an int such as “8”. Cast was developed for use in
-[Hugo](http://hugo.spf13.com), a website engine which uses YAML, TOML or JSON
+[Hugo](https://gohugo.io), a website engine which uses YAML, TOML or JSON
for meta data.
## Why use Cast?
@@ -72,4 +73,3 @@ the code for a complete set.
var eight interface{} = 8
cast.ToInt(eight) // 8
cast.ToInt(nil) // 0
-
diff --git a/vendor/github.com/spf13/cast/caste.go b/vendor/github.com/spf13/cast/caste.go
index c04af6a97..d49bbf83e 100644
--- a/vendor/github.com/spf13/cast/caste.go
+++ b/vendor/github.com/spf13/cast/caste.go
@@ -34,6 +34,12 @@ func ToTimeInDefaultLocationE(i interface{}, location *time.Location) (tim time.
return v, nil
case string:
return StringToDateInDefaultLocation(v, location)
+ case json.Number:
+ s, err1 := ToInt64E(v)
+ if err1 != nil {
+ return time.Time{}, fmt.Errorf("unable to cast %#v of type %T to Time", i, i)
+ }
+ return time.Unix(s, 0), nil
case int:
return time.Unix(int64(v), 0), nil
case int64:
@@ -71,6 +77,11 @@ func ToDurationE(i interface{}) (d time.Duration, err error) {
d, err = time.ParseDuration(s + "ns")
}
return
+ case json.Number:
+ var v float64
+ v, err = s.Float64()
+ d = time.Duration(v)
+ return
default:
err = fmt.Errorf("unable to cast %#v of type %T to Duration", i, i)
return
@@ -87,12 +98,39 @@ func ToBoolE(i interface{}) (bool, error) {
case nil:
return false, nil
case int:
- if i.(int) != 0 {
- return true, nil
- }
- return false, nil
+ return b != 0, nil
+ case int64:
+ return b != 0, nil
+ case int32:
+ return b != 0, nil
+ case int16:
+ return b != 0, nil
+ case int8:
+ return b != 0, nil
+ case uint:
+ return b != 0, nil
+ case uint64:
+ return b != 0, nil
+ case uint32:
+ return b != 0, nil
+ case uint16:
+ return b != 0, nil
+ case uint8:
+ return b != 0, nil
+ case float64:
+ return b != 0, nil
+ case float32:
+ return b != 0, nil
+ case time.Duration:
+ return b != 0, nil
case string:
return strconv.ParseBool(i.(string))
+ case json.Number:
+ v, err := ToInt64E(b)
+ if err == nil {
+ return v != 0, nil
+ }
+ return false, fmt.Errorf("unable to cast %#v of type %T to bool", i, i)
default:
return false, fmt.Errorf("unable to cast %#v of type %T to bool", i, i)
}
@@ -102,13 +140,16 @@ func ToBoolE(i interface{}) (bool, error) {
func ToFloat64E(i interface{}) (float64, error) {
i = indirect(i)
+ intv, ok := toInt(i)
+ if ok {
+ return float64(intv), nil
+ }
+
switch s := i.(type) {
case float64:
return s, nil
case float32:
return float64(s), nil
- case int:
- return float64(s), nil
case int64:
return float64(s), nil
case int32:
@@ -133,11 +174,19 @@ func ToFloat64E(i interface{}) (float64, error) {
return v, nil
}
return 0, fmt.Errorf("unable to cast %#v of type %T to float64", i, i)
+ case json.Number:
+ v, err := s.Float64()
+ if err == nil {
+ return v, nil
+ }
+ return 0, fmt.Errorf("unable to cast %#v of type %T to float64", i, i)
case bool:
if s {
return 1, nil
}
return 0, nil
+ case nil:
+ return 0, nil
default:
return 0, fmt.Errorf("unable to cast %#v of type %T to float64", i, i)
}
@@ -147,13 +196,16 @@ func ToFloat64E(i interface{}) (float64, error) {
func ToFloat32E(i interface{}) (float32, error) {
i = indirect(i)
+ intv, ok := toInt(i)
+ if ok {
+ return float32(intv), nil
+ }
+
switch s := i.(type) {
case float64:
return float32(s), nil
case float32:
return s, nil
- case int:
- return float32(s), nil
case int64:
return float32(s), nil
case int32:
@@ -178,11 +230,19 @@ func ToFloat32E(i interface{}) (float32, error) {
return float32(v), nil
}
return 0, fmt.Errorf("unable to cast %#v of type %T to float32", i, i)
+ case json.Number:
+ v, err := s.Float64()
+ if err == nil {
+ return float32(v), nil
+ }
+ return 0, fmt.Errorf("unable to cast %#v of type %T to float32", i, i)
case bool:
if s {
return 1, nil
}
return 0, nil
+ case nil:
+ return 0, nil
default:
return 0, fmt.Errorf("unable to cast %#v of type %T to float32", i, i)
}
@@ -192,9 +252,12 @@ func ToFloat32E(i interface{}) (float32, error) {
func ToInt64E(i interface{}) (int64, error) {
i = indirect(i)
+ intv, ok := toInt(i)
+ if ok {
+ return int64(intv), nil
+ }
+
switch s := i.(type) {
- case int:
- return int64(s), nil
case int64:
return s, nil
case int32:
@@ -218,11 +281,13 @@ func ToInt64E(i interface{}) (int64, error) {
case float32:
return int64(s), nil
case string:
- v, err := strconv.ParseInt(s, 0, 0)
+ v, err := strconv.ParseInt(trimZeroDecimal(s), 0, 0)
if err == nil {
return v, nil
}
return 0, fmt.Errorf("unable to cast %#v of type %T to int64", i, i)
+ case json.Number:
+ return ToInt64E(string(s))
case bool:
if s {
return 1, nil
@@ -239,9 +304,12 @@ func ToInt64E(i interface{}) (int64, error) {
func ToInt32E(i interface{}) (int32, error) {
i = indirect(i)
+ intv, ok := toInt(i)
+ if ok {
+ return int32(intv), nil
+ }
+
switch s := i.(type) {
- case int:
- return int32(s), nil
case int64:
return int32(s), nil
case int32:
@@ -265,11 +333,13 @@ func ToInt32E(i interface{}) (int32, error) {
case float32:
return int32(s), nil
case string:
- v, err := strconv.ParseInt(s, 0, 0)
+ v, err := strconv.ParseInt(trimZeroDecimal(s), 0, 0)
if err == nil {
return int32(v), nil
}
return 0, fmt.Errorf("unable to cast %#v of type %T to int32", i, i)
+ case json.Number:
+ return ToInt32E(string(s))
case bool:
if s {
return 1, nil
@@ -286,9 +356,12 @@ func ToInt32E(i interface{}) (int32, error) {
func ToInt16E(i interface{}) (int16, error) {
i = indirect(i)
+ intv, ok := toInt(i)
+ if ok {
+ return int16(intv), nil
+ }
+
switch s := i.(type) {
- case int:
- return int16(s), nil
case int64:
return int16(s), nil
case int32:
@@ -312,11 +385,13 @@ func ToInt16E(i interface{}) (int16, error) {
case float32:
return int16(s), nil
case string:
- v, err := strconv.ParseInt(s, 0, 0)
+ v, err := strconv.ParseInt(trimZeroDecimal(s), 0, 0)
if err == nil {
return int16(v), nil
}
return 0, fmt.Errorf("unable to cast %#v of type %T to int16", i, i)
+ case json.Number:
+ return ToInt16E(string(s))
case bool:
if s {
return 1, nil
@@ -333,9 +408,12 @@ func ToInt16E(i interface{}) (int16, error) {
func ToInt8E(i interface{}) (int8, error) {
i = indirect(i)
+ intv, ok := toInt(i)
+ if ok {
+ return int8(intv), nil
+ }
+
switch s := i.(type) {
- case int:
- return int8(s), nil
case int64:
return int8(s), nil
case int32:
@@ -359,11 +437,13 @@ func ToInt8E(i interface{}) (int8, error) {
case float32:
return int8(s), nil
case string:
- v, err := strconv.ParseInt(s, 0, 0)
+ v, err := strconv.ParseInt(trimZeroDecimal(s), 0, 0)
if err == nil {
return int8(v), nil
}
return 0, fmt.Errorf("unable to cast %#v of type %T to int8", i, i)
+ case json.Number:
+ return ToInt8E(string(s))
case bool:
if s {
return 1, nil
@@ -380,9 +460,12 @@ func ToInt8E(i interface{}) (int8, error) {
func ToIntE(i interface{}) (int, error) {
i = indirect(i)
+ intv, ok := toInt(i)
+ if ok {
+ return intv, nil
+ }
+
switch s := i.(type) {
- case int:
- return s, nil
case int64:
return int(s), nil
case int32:
@@ -406,11 +489,13 @@ func ToIntE(i interface{}) (int, error) {
case float32:
return int(s), nil
case string:
- v, err := strconv.ParseInt(s, 0, 0)
+ v, err := strconv.ParseInt(trimZeroDecimal(s), 0, 0)
if err == nil {
return int(v), nil
}
- return 0, fmt.Errorf("unable to cast %#v of type %T to int", i, i)
+ return 0, fmt.Errorf("unable to cast %#v of type %T to int64", i, i)
+ case json.Number:
+ return ToIntE(string(s))
case bool:
if s {
return 1, nil
@@ -427,18 +512,26 @@ func ToIntE(i interface{}) (int, error) {
func ToUintE(i interface{}) (uint, error) {
i = indirect(i)
+ intv, ok := toInt(i)
+ if ok {
+ if intv < 0 {
+ return 0, errNegativeNotAllowed
+ }
+ return uint(intv), nil
+ }
+
switch s := i.(type) {
case string:
- v, err := strconv.ParseUint(s, 0, 0)
+ v, err := strconv.ParseInt(trimZeroDecimal(s), 0, 0)
if err == nil {
+ if v < 0 {
+ return 0, errNegativeNotAllowed
+ }
return uint(v), nil
}
- return 0, fmt.Errorf("unable to cast %#v to uint: %s", i, err)
- case int:
- if s < 0 {
- return 0, errNegativeNotAllowed
- }
- return uint(s), nil
+ return 0, fmt.Errorf("unable to cast %#v of type %T to uint", i, i)
+ case json.Number:
+ return ToUintE(string(s))
case int64:
if s < 0 {
return 0, errNegativeNotAllowed
@@ -495,18 +588,26 @@ func ToUintE(i interface{}) (uint, error) {
func ToUint64E(i interface{}) (uint64, error) {
i = indirect(i)
+ intv, ok := toInt(i)
+ if ok {
+ if intv < 0 {
+ return 0, errNegativeNotAllowed
+ }
+ return uint64(intv), nil
+ }
+
switch s := i.(type) {
case string:
- v, err := strconv.ParseUint(s, 0, 64)
+ v, err := strconv.ParseInt(trimZeroDecimal(s), 0, 0)
if err == nil {
- return v, nil
- }
- return 0, fmt.Errorf("unable to cast %#v to uint64: %s", i, err)
- case int:
- if s < 0 {
- return 0, errNegativeNotAllowed
+ if v < 0 {
+ return 0, errNegativeNotAllowed
+ }
+ return uint64(v), nil
}
- return uint64(s), nil
+ return 0, fmt.Errorf("unable to cast %#v of type %T to uint64", i, i)
+ case json.Number:
+ return ToUint64E(string(s))
case int64:
if s < 0 {
return 0, errNegativeNotAllowed
@@ -563,18 +664,26 @@ func ToUint64E(i interface{}) (uint64, error) {
func ToUint32E(i interface{}) (uint32, error) {
i = indirect(i)
+ intv, ok := toInt(i)
+ if ok {
+ if intv < 0 {
+ return 0, errNegativeNotAllowed
+ }
+ return uint32(intv), nil
+ }
+
switch s := i.(type) {
case string:
- v, err := strconv.ParseUint(s, 0, 32)
+ v, err := strconv.ParseInt(trimZeroDecimal(s), 0, 0)
if err == nil {
+ if v < 0 {
+ return 0, errNegativeNotAllowed
+ }
return uint32(v), nil
}
- return 0, fmt.Errorf("unable to cast %#v to uint32: %s", i, err)
- case int:
- if s < 0 {
- return 0, errNegativeNotAllowed
- }
- return uint32(s), nil
+ return 0, fmt.Errorf("unable to cast %#v of type %T to uint32", i, i)
+ case json.Number:
+ return ToUint32E(string(s))
case int64:
if s < 0 {
return 0, errNegativeNotAllowed
@@ -631,18 +740,26 @@ func ToUint32E(i interface{}) (uint32, error) {
func ToUint16E(i interface{}) (uint16, error) {
i = indirect(i)
+ intv, ok := toInt(i)
+ if ok {
+ if intv < 0 {
+ return 0, errNegativeNotAllowed
+ }
+ return uint16(intv), nil
+ }
+
switch s := i.(type) {
case string:
- v, err := strconv.ParseUint(s, 0, 16)
+ v, err := strconv.ParseInt(trimZeroDecimal(s), 0, 0)
if err == nil {
+ if v < 0 {
+ return 0, errNegativeNotAllowed
+ }
return uint16(v), nil
}
- return 0, fmt.Errorf("unable to cast %#v to uint16: %s", i, err)
- case int:
- if s < 0 {
- return 0, errNegativeNotAllowed
- }
- return uint16(s), nil
+ return 0, fmt.Errorf("unable to cast %#v of type %T to uint16", i, i)
+ case json.Number:
+ return ToUint16E(string(s))
case int64:
if s < 0 {
return 0, errNegativeNotAllowed
@@ -699,18 +816,26 @@ func ToUint16E(i interface{}) (uint16, error) {
func ToUint8E(i interface{}) (uint8, error) {
i = indirect(i)
+ intv, ok := toInt(i)
+ if ok {
+ if intv < 0 {
+ return 0, errNegativeNotAllowed
+ }
+ return uint8(intv), nil
+ }
+
switch s := i.(type) {
case string:
- v, err := strconv.ParseUint(s, 0, 8)
+ v, err := strconv.ParseInt(trimZeroDecimal(s), 0, 0)
if err == nil {
+ if v < 0 {
+ return 0, errNegativeNotAllowed
+ }
return uint8(v), nil
}
- return 0, fmt.Errorf("unable to cast %#v to uint8: %s", i, err)
- case int:
- if s < 0 {
- return 0, errNegativeNotAllowed
- }
- return uint8(s), nil
+ return 0, fmt.Errorf("unable to cast %#v of type %T to uint8", i, i)
+ case json.Number:
+ return ToUint8E(string(s))
case int64:
if s < 0 {
return 0, errNegativeNotAllowed
@@ -835,6 +960,8 @@ func ToStringE(i interface{}) (string, error) {
return strconv.FormatUint(uint64(s), 10), nil
case uint8:
return strconv.FormatUint(uint64(s), 10), nil
+ case json.Number:
+ return s.String(), nil
case []byte:
return string(s), nil
case template.HTML:
@@ -1279,30 +1406,31 @@ func (f timeFormat) hasTimezone() bool {
var (
timeFormats = []timeFormat{
- timeFormat{time.RFC3339, timeFormatNumericTimezone},
- timeFormat{"2006-01-02T15:04:05", timeFormatNoTimezone}, // iso8601 without timezone
- timeFormat{time.RFC1123Z, timeFormatNumericTimezone},
- timeFormat{time.RFC1123, timeFormatNamedTimezone},
- timeFormat{time.RFC822Z, timeFormatNumericTimezone},
- timeFormat{time.RFC822, timeFormatNamedTimezone},
- timeFormat{time.RFC850, timeFormatNamedTimezone},
- timeFormat{"2006-01-02 15:04:05.999999999 -0700 MST", timeFormatNumericAndNamedTimezone}, // Time.String()
- timeFormat{"2006-01-02T15:04:05-0700", timeFormatNumericTimezone}, // RFC3339 without timezone hh:mm colon
- timeFormat{"2006-01-02 15:04:05Z0700", timeFormatNumericTimezone}, // RFC3339 without T or timezone hh:mm colon
- timeFormat{"2006-01-02 15:04:05", timeFormatNoTimezone},
- timeFormat{time.ANSIC, timeFormatNoTimezone},
- timeFormat{time.UnixDate, timeFormatNamedTimezone},
- timeFormat{time.RubyDate, timeFormatNumericTimezone},
- timeFormat{"2006-01-02 15:04:05Z07:00", timeFormatNumericTimezone},
- timeFormat{"2006-01-02", timeFormatNoTimezone},
- timeFormat{"02 Jan 2006", timeFormatNoTimezone},
- timeFormat{"2006-01-02 15:04:05 -07:00", timeFormatNumericTimezone},
- timeFormat{"2006-01-02 15:04:05 -0700", timeFormatNumericTimezone},
- timeFormat{time.Kitchen, timeFormatTimeOnly},
- timeFormat{time.Stamp, timeFormatTimeOnly},
- timeFormat{time.StampMilli, timeFormatTimeOnly},
- timeFormat{time.StampMicro, timeFormatTimeOnly},
- timeFormat{time.StampNano, timeFormatTimeOnly},
+ // Keep common formats at the top.
+ {"2006-01-02", timeFormatNoTimezone},
+ {time.RFC3339, timeFormatNumericTimezone},
+ {"2006-01-02T15:04:05", timeFormatNoTimezone}, // iso8601 without timezone
+ {time.RFC1123Z, timeFormatNumericTimezone},
+ {time.RFC1123, timeFormatNamedTimezone},
+ {time.RFC822Z, timeFormatNumericTimezone},
+ {time.RFC822, timeFormatNamedTimezone},
+ {time.RFC850, timeFormatNamedTimezone},
+ {"2006-01-02 15:04:05.999999999 -0700 MST", timeFormatNumericAndNamedTimezone}, // Time.String()
+ {"2006-01-02T15:04:05-0700", timeFormatNumericTimezone}, // RFC3339 without timezone hh:mm colon
+ {"2006-01-02 15:04:05Z0700", timeFormatNumericTimezone}, // RFC3339 without T or timezone hh:mm colon
+ {"2006-01-02 15:04:05", timeFormatNoTimezone},
+ {time.ANSIC, timeFormatNoTimezone},
+ {time.UnixDate, timeFormatNamedTimezone},
+ {time.RubyDate, timeFormatNumericTimezone},
+ {"2006-01-02 15:04:05Z07:00", timeFormatNumericTimezone},
+ {"02 Jan 2006", timeFormatNoTimezone},
+ {"2006-01-02 15:04:05 -07:00", timeFormatNumericTimezone},
+ {"2006-01-02 15:04:05 -0700", timeFormatNumericTimezone},
+ {time.Kitchen, timeFormatTimeOnly},
+ {time.Stamp, timeFormatTimeOnly},
+ {time.StampMilli, timeFormatTimeOnly},
+ {time.StampMicro, timeFormatTimeOnly},
+ {time.StampNano, timeFormatTimeOnly},
}
)
@@ -1335,3 +1463,36 @@ func jsonStringToObject(s string, v interface{}) error {
data := []byte(s)
return json.Unmarshal(data, v)
}
+
+// toInt returns the int value of v if v or v's underlying type
+// is an int.
+// Note that this will return false for int64 etc. types.
+func toInt(v interface{}) (int, bool) {
+ switch v := v.(type) {
+ case int:
+ return v, true
+ case time.Weekday:
+ return int(v), true
+ case time.Month:
+ return int(v), true
+ default:
+ return 0, false
+ }
+}
+
+func trimZeroDecimal(s string) string {
+ var foundZero bool
+ for i := len(s); i > 0; i-- {
+ switch s[i-1] {
+ case '.':
+ if foundZero {
+ return s[:i-1]
+ }
+ case '0':
+ foundZero = true
+ default:
+ return s
+ }
+ }
+ return s
+}
diff --git a/vendor/github.com/spf13/viper/.editorconfig b/vendor/github.com/spf13/viper/.editorconfig
index 63afcbcdd..6d0b6d356 100644
--- a/vendor/github.com/spf13/viper/.editorconfig
+++ b/vendor/github.com/spf13/viper/.editorconfig
@@ -11,5 +11,5 @@ trim_trailing_whitespace = true
[*.go]
indent_style = tab
-[{Makefile, *.mk}]
+[{Makefile,*.mk}]
indent_style = tab
diff --git a/vendor/github.com/spf13/viper/.golangci.yml b/vendor/github.com/spf13/viper/.golangci.yaml
similarity index 89%
rename from vendor/github.com/spf13/viper/.golangci.yml
rename to vendor/github.com/spf13/viper/.golangci.yaml
index 52e77eef0..acd9eebac 100644
--- a/vendor/github.com/spf13/viper/.golangci.yml
+++ b/vendor/github.com/spf13/viper/.golangci.yaml
@@ -3,7 +3,10 @@ run:
linters-settings:
gci:
- local-prefixes: github.com/spf13/viper
+ sections:
+ - standard
+ - default
+ - prefix(github.com/spf13/viper)
golint:
min-confidence: 0
goimports:
@@ -13,7 +16,6 @@ linters:
disable-all: true
enable:
- bodyclose
- - deadcode
- dogsled
- dupl
- durationcheck
@@ -40,14 +42,12 @@ linters:
- rowserrcheck
- sqlclosecheck
- staticcheck
- - structcheck
- stylecheck
- tparallel
- typecheck
- unconvert
- unparam
- unused
- - varcheck
- wastedassign
- whitespace
@@ -80,6 +80,11 @@ linters:
# - goheader
# - gomodguard
+ # deprecated
+ # - deadcode
+ # - structcheck
+ # - varcheck
+
# don't enable:
# - asciicheck
# - funlen
diff --git a/vendor/github.com/spf13/viper/Makefile b/vendor/github.com/spf13/viper/Makefile
index 1279096f4..e8d3baaa8 100644
--- a/vendor/github.com/spf13/viper/Makefile
+++ b/vendor/github.com/spf13/viper/Makefile
@@ -15,8 +15,8 @@ TEST_FORMAT = short-verbose
endif
# Dependency versions
-GOTESTSUM_VERSION = 1.7.0
-GOLANGCI_VERSION = 1.43.0
+GOTESTSUM_VERSION = 1.9.0
+GOLANGCI_VERSION = 1.52.2
# Add the ability to override some variables
# Use with care
@@ -48,7 +48,7 @@ bin/golangci-lint: bin/golangci-lint-${GOLANGCI_VERSION}
@ln -sf golangci-lint-${GOLANGCI_VERSION} bin/golangci-lint
bin/golangci-lint-${GOLANGCI_VERSION}:
@mkdir -p bin
- curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | bash -s -- -b ./bin/ v${GOLANGCI_VERSION}
+ curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | bash -s -- -b ./bin/ v${GOLANGCI_VERSION}
@mv bin/golangci-lint "$@"
.PHONY: lint
diff --git a/vendor/github.com/spf13/viper/README.md b/vendor/github.com/spf13/viper/README.md
index 9712e7051..4184d2a11 100644
--- a/vendor/github.com/spf13/viper/README.md
+++ b/vendor/github.com/spf13/viper/README.md
@@ -8,10 +8,10 @@
[![Mentioned in Awesome Go](https://awesome.re/mentioned-badge-flat.svg)](https://github.com/avelino/awesome-go#configuration)
[![run on repl.it](https://repl.it/badge/github/sagikazarmark/Viper-example)](https://repl.it/@sagikazarmark/Viper-example#main.go)
-[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/spf13/viper/CI?style=flat-square)](https://github.com/spf13/viper/actions?query=workflow%3ACI)
+[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/spf13/viper/ci.yaml?branch=master&style=flat-square)](https://github.com/spf13/viper/actions?query=workflow%3ACI)
[![Join the chat at https://gitter.im/spf13/viper](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/spf13/viper?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Go Report Card](https://goreportcard.com/badge/github.com/spf13/viper?style=flat-square)](https://goreportcard.com/report/github.com/spf13/viper)
-![Go Version](https://img.shields.io/badge/go%20version-%3E=1.14-61CFDD.svg?style=flat-square)
+![Go Version](https://img.shields.io/badge/go%20version-%3E=1.16-61CFDD.svg?style=flat-square)
[![PkgGoDev](https://pkg.go.dev/badge/mod/github.com/spf13/viper)](https://pkg.go.dev/mod/github.com/spf13/viper)
**Go configuration with fangs!**
@@ -27,6 +27,9 @@ Many Go projects are built using Viper including:
* [doctl](https://github.com/digitalocean/doctl)
* [Clairctl](https://github.com/jgsqware/clairctl)
* [Mercure](https://mercure.rocks)
+* [Meshery](https://github.com/meshery/meshery)
+* [Bearer](https://github.com/bearer/bearer)
+* [Coder](https://github.com/coder/coder)
## Install
@@ -40,8 +43,8 @@ go get github.com/spf13/viper
## What is Viper?
-Viper is a complete configuration solution for Go applications including 12-Factor apps. It is designed
-to work within an application, and can handle all types of configuration needs
+Viper is a complete configuration solution for Go applications including [12-Factor apps](https://12factor.net/#the_twelve_factors).
+It is designed to work within an application, and can handle all types of configuration needs
and formats. It supports:
* setting defaults
@@ -119,7 +122,7 @@ viper.AddConfigPath("$HOME/.appname") // call multiple times to add many search
viper.AddConfigPath(".") // optionally look for config in the working directory
err := viper.ReadInConfig() // Find and read the config file
if err != nil { // Handle errors reading the config file
- panic(fmt.Errorf("Fatal error config file: %w \n", err))
+ panic(fmt.Errorf("fatal error config file: %w", err))
}
```
@@ -447,6 +450,13 @@ viper.SetConfigType("json") // because there is no file extension in a stream of
err := viper.ReadRemoteConfig()
```
+#### etcd3
+```go
+viper.AddRemoteProvider("etcd3", "http://127.0.0.1:4001","/config/hugo.json")
+viper.SetConfigType("json") // because there is no file extension in a stream of bytes, supported extensions are "json", "toml", "yaml", "yml", "properties", "props", "prop", "env", "dotenv"
+err := viper.ReadRemoteConfig()
+```
+
#### Consul
You need to set a key to Consul key/value storage with JSON value containing your desired config.
For example, create a Consul key/value store key `MY_CONSUL_KEY` with value:
@@ -594,7 +604,7 @@ configuration level.
Viper can access array indices by using numbers in the path. For example:
-```json
+```jsonc
{
"host": {
"address": "localhost",
@@ -622,7 +632,7 @@ GetInt("host.ports.1") // returns 6029
Lastly, if there exists a key that matches the delimited key path, its value
will be returned instead. E.g.
-```json
+```jsonc
{
"datastore.metric.host": "0.0.0.0",
"host": {
diff --git a/vendor/github.com/spf13/viper/TROUBLESHOOTING.md b/vendor/github.com/spf13/viper/TROUBLESHOOTING.md
index 096277af7..c4e36c686 100644
--- a/vendor/github.com/spf13/viper/TROUBLESHOOTING.md
+++ b/vendor/github.com/spf13/viper/TROUBLESHOOTING.md
@@ -21,3 +21,12 @@ The solution is easy: switch to using Go Modules.
Please refer to the [wiki](https://github.com/golang/go/wiki/Modules) on how to do that.
**tl;dr* `export GO111MODULE=on`
+
+## Unquoted 'y' and 'n' characters get replaced with _true_ and _false_ when reading a YAML file
+
+This is a YAML 1.1 feature according to [go-yaml/yaml#740](https://github.com/go-yaml/yaml/issues/740).
+
+Potential solutions are:
+
+1. Quoting values resolved as boolean
+1. Upgrading to YAML v3 (for the time being this is possible by passing the `viper_yaml3` tag to your build)
diff --git a/vendor/github.com/spf13/viper/experimental_logger.go b/vendor/github.com/spf13/viper/experimental_logger.go
new file mode 100644
index 000000000..206dad6a0
--- /dev/null
+++ b/vendor/github.com/spf13/viper/experimental_logger.go
@@ -0,0 +1,11 @@
+//go:build viper_logger
+// +build viper_logger
+
+package viper
+
+// WithLogger sets a custom logger.
+func WithLogger(l Logger) Option {
+ return optionFunc(func(v *Viper) {
+ v.logger = l
+ })
+}
diff --git a/vendor/github.com/spf13/viper/internal/encoding/decoder.go b/vendor/github.com/spf13/viper/internal/encoding/decoder.go
index 08b1bb66b..f472e9ff1 100644
--- a/vendor/github.com/spf13/viper/internal/encoding/decoder.go
+++ b/vendor/github.com/spf13/viper/internal/encoding/decoder.go
@@ -4,10 +4,10 @@ import (
"sync"
)
-// Decoder decodes the contents of b into a v representation.
+// Decoder decodes the contents of b into v.
// It's primarily used for decoding contents of a file into a map[string]interface{}.
type Decoder interface {
- Decode(b []byte, v interface{}) error
+ Decode(b []byte, v map[string]interface{}) error
}
const (
@@ -48,7 +48,7 @@ func (e *DecoderRegistry) RegisterDecoder(format string, enc Decoder) error {
}
// Decode calls the underlying Decoder based on the format.
-func (e *DecoderRegistry) Decode(format string, b []byte, v interface{}) error {
+func (e *DecoderRegistry) Decode(format string, b []byte, v map[string]interface{}) error {
e.mu.RLock()
decoder, ok := e.decoders[format]
e.mu.RUnlock()
diff --git a/vendor/github.com/spf13/viper/internal/encoding/dotenv/codec.go b/vendor/github.com/spf13/viper/internal/encoding/dotenv/codec.go
new file mode 100644
index 000000000..4485063b6
--- /dev/null
+++ b/vendor/github.com/spf13/viper/internal/encoding/dotenv/codec.go
@@ -0,0 +1,61 @@
+package dotenv
+
+import (
+ "bytes"
+ "fmt"
+ "sort"
+ "strings"
+
+ "github.com/subosito/gotenv"
+)
+
+const keyDelimiter = "_"
+
+// Codec implements the encoding.Encoder and encoding.Decoder interfaces for encoding data containing environment variables
+// (commonly called as dotenv format).
+type Codec struct{}
+
+func (Codec) Encode(v map[string]interface{}) ([]byte, error) {
+ flattened := map[string]interface{}{}
+
+ flattened = flattenAndMergeMap(flattened, v, "", keyDelimiter)
+
+ keys := make([]string, 0, len(flattened))
+
+ for key := range flattened {
+ keys = append(keys, key)
+ }
+
+ sort.Strings(keys)
+
+ var buf bytes.Buffer
+
+ for _, key := range keys {
+ _, err := buf.WriteString(fmt.Sprintf("%v=%v\n", strings.ToUpper(key), flattened[key]))
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ return buf.Bytes(), nil
+}
+
+func (Codec) Decode(b []byte, v map[string]interface{}) error {
+ var buf bytes.Buffer
+
+ _, err := buf.Write(b)
+ if err != nil {
+ return err
+ }
+
+ env, err := gotenv.StrictParse(&buf)
+ if err != nil {
+ return err
+ }
+
+ for key, value := range env {
+ v[key] = value
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/spf13/viper/internal/encoding/dotenv/map_utils.go b/vendor/github.com/spf13/viper/internal/encoding/dotenv/map_utils.go
new file mode 100644
index 000000000..ce6e6efa3
--- /dev/null
+++ b/vendor/github.com/spf13/viper/internal/encoding/dotenv/map_utils.go
@@ -0,0 +1,41 @@
+package dotenv
+
+import (
+ "strings"
+
+ "github.com/spf13/cast"
+)
+
+// flattenAndMergeMap recursively flattens the given map into a new map
+// Code is based on the function with the same name in tha main package.
+// TODO: move it to a common place
+func flattenAndMergeMap(shadow map[string]interface{}, m map[string]interface{}, prefix string, delimiter string) map[string]interface{} {
+ if shadow != nil && prefix != "" && shadow[prefix] != nil {
+ // prefix is shadowed => nothing more to flatten
+ return shadow
+ }
+ if shadow == nil {
+ shadow = make(map[string]interface{})
+ }
+
+ var m2 map[string]interface{}
+ if prefix != "" {
+ prefix += delimiter
+ }
+ for k, val := range m {
+ fullKey := prefix + k
+ switch val.(type) {
+ case map[string]interface{}:
+ m2 = val.(map[string]interface{})
+ case map[interface{}]interface{}:
+ m2 = cast.ToStringMap(val)
+ default:
+ // immediate value
+ shadow[strings.ToLower(fullKey)] = val
+ continue
+ }
+ // recursively merge to shadow map
+ shadow = flattenAndMergeMap(shadow, m2, fullKey, delimiter)
+ }
+ return shadow
+}
diff --git a/vendor/github.com/spf13/viper/internal/encoding/encoder.go b/vendor/github.com/spf13/viper/internal/encoding/encoder.go
index 82c7996cb..2341bf235 100644
--- a/vendor/github.com/spf13/viper/internal/encoding/encoder.go
+++ b/vendor/github.com/spf13/viper/internal/encoding/encoder.go
@@ -7,7 +7,7 @@ import (
// Encoder encodes the contents of v into a byte representation.
// It's primarily used for encoding a map[string]interface{} into a file format.
type Encoder interface {
- Encode(v interface{}) ([]byte, error)
+ Encode(v map[string]interface{}) ([]byte, error)
}
const (
@@ -47,7 +47,7 @@ func (e *EncoderRegistry) RegisterEncoder(format string, enc Encoder) error {
return nil
}
-func (e *EncoderRegistry) Encode(format string, v interface{}) ([]byte, error) {
+func (e *EncoderRegistry) Encode(format string, v map[string]interface{}) ([]byte, error) {
e.mu.RLock()
encoder, ok := e.encoders[format]
e.mu.RUnlock()
diff --git a/vendor/github.com/spf13/viper/internal/encoding/hcl/codec.go b/vendor/github.com/spf13/viper/internal/encoding/hcl/codec.go
index f3e4ab122..7fde8e4bc 100644
--- a/vendor/github.com/spf13/viper/internal/encoding/hcl/codec.go
+++ b/vendor/github.com/spf13/viper/internal/encoding/hcl/codec.go
@@ -12,7 +12,7 @@ import (
// TODO: add printer config to the codec?
type Codec struct{}
-func (Codec) Encode(v interface{}) ([]byte, error) {
+func (Codec) Encode(v map[string]interface{}) ([]byte, error) {
b, err := json.Marshal(v)
if err != nil {
return nil, err
@@ -35,6 +35,6 @@ func (Codec) Encode(v interface{}) ([]byte, error) {
return buf.Bytes(), nil
}
-func (Codec) Decode(b []byte, v interface{}) error {
- return hcl.Unmarshal(b, v)
+func (Codec) Decode(b []byte, v map[string]interface{}) error {
+ return hcl.Unmarshal(b, &v)
}
diff --git a/vendor/github.com/spf13/viper/internal/encoding/ini/codec.go b/vendor/github.com/spf13/viper/internal/encoding/ini/codec.go
new file mode 100644
index 000000000..9acd87fc3
--- /dev/null
+++ b/vendor/github.com/spf13/viper/internal/encoding/ini/codec.go
@@ -0,0 +1,99 @@
+package ini
+
+import (
+ "bytes"
+ "sort"
+ "strings"
+
+ "github.com/spf13/cast"
+ "gopkg.in/ini.v1"
+)
+
+// LoadOptions contains all customized options used for load data source(s).
+// This type is added here for convenience: this way consumers can import a single package called "ini".
+type LoadOptions = ini.LoadOptions
+
+// Codec implements the encoding.Encoder and encoding.Decoder interfaces for INI encoding.
+type Codec struct {
+ KeyDelimiter string
+ LoadOptions LoadOptions
+}
+
+func (c Codec) Encode(v map[string]interface{}) ([]byte, error) {
+ cfg := ini.Empty()
+ ini.PrettyFormat = false
+
+ flattened := map[string]interface{}{}
+
+ flattened = flattenAndMergeMap(flattened, v, "", c.keyDelimiter())
+
+ keys := make([]string, 0, len(flattened))
+
+ for key := range flattened {
+ keys = append(keys, key)
+ }
+
+ sort.Strings(keys)
+
+ for _, key := range keys {
+ sectionName, keyName := "", key
+
+ lastSep := strings.LastIndex(key, ".")
+ if lastSep != -1 {
+ sectionName = key[:(lastSep)]
+ keyName = key[(lastSep + 1):]
+ }
+
+ // TODO: is this a good idea?
+ if sectionName == "default" {
+ sectionName = ""
+ }
+
+ cfg.Section(sectionName).Key(keyName).SetValue(cast.ToString(flattened[key]))
+ }
+
+ var buf bytes.Buffer
+
+ _, err := cfg.WriteTo(&buf)
+ if err != nil {
+ return nil, err
+ }
+
+ return buf.Bytes(), nil
+}
+
+func (c Codec) Decode(b []byte, v map[string]interface{}) error {
+ cfg := ini.Empty(c.LoadOptions)
+
+ err := cfg.Append(b)
+ if err != nil {
+ return err
+ }
+
+ sections := cfg.Sections()
+
+ for i := 0; i < len(sections); i++ {
+ section := sections[i]
+ keys := section.Keys()
+
+ for j := 0; j < len(keys); j++ {
+ key := keys[j]
+ value := cfg.Section(section.Name()).Key(key.Name()).String()
+
+ deepestMap := deepSearch(v, strings.Split(section.Name(), c.keyDelimiter()))
+
+ // set innermost value
+ deepestMap[key.Name()] = value
+ }
+ }
+
+ return nil
+}
+
+func (c Codec) keyDelimiter() string {
+ if c.KeyDelimiter == "" {
+ return "."
+ }
+
+ return c.KeyDelimiter
+}
diff --git a/vendor/github.com/spf13/viper/internal/encoding/ini/map_utils.go b/vendor/github.com/spf13/viper/internal/encoding/ini/map_utils.go
new file mode 100644
index 000000000..8329856b5
--- /dev/null
+++ b/vendor/github.com/spf13/viper/internal/encoding/ini/map_utils.go
@@ -0,0 +1,74 @@
+package ini
+
+import (
+ "strings"
+
+ "github.com/spf13/cast"
+)
+
+// THIS CODE IS COPIED HERE: IT SHOULD NOT BE MODIFIED
+// AT SOME POINT IT WILL BE MOVED TO A COMMON PLACE
+// deepSearch scans deep maps, following the key indexes listed in the
+// sequence "path".
+// The last value is expected to be another map, and is returned.
+//
+// In case intermediate keys do not exist, or map to a non-map value,
+// a new map is created and inserted, and the search continues from there:
+// the initial map "m" may be modified!
+func deepSearch(m map[string]interface{}, path []string) map[string]interface{} {
+ for _, k := range path {
+ m2, ok := m[k]
+ if !ok {
+ // intermediate key does not exist
+ // => create it and continue from there
+ m3 := make(map[string]interface{})
+ m[k] = m3
+ m = m3
+ continue
+ }
+ m3, ok := m2.(map[string]interface{})
+ if !ok {
+ // intermediate key is a value
+ // => replace with a new map
+ m3 = make(map[string]interface{})
+ m[k] = m3
+ }
+ // continue search from here
+ m = m3
+ }
+ return m
+}
+
+// flattenAndMergeMap recursively flattens the given map into a new map
+// Code is based on the function with the same name in tha main package.
+// TODO: move it to a common place
+func flattenAndMergeMap(shadow map[string]interface{}, m map[string]interface{}, prefix string, delimiter string) map[string]interface{} {
+ if shadow != nil && prefix != "" && shadow[prefix] != nil {
+ // prefix is shadowed => nothing more to flatten
+ return shadow
+ }
+ if shadow == nil {
+ shadow = make(map[string]interface{})
+ }
+
+ var m2 map[string]interface{}
+ if prefix != "" {
+ prefix += delimiter
+ }
+ for k, val := range m {
+ fullKey := prefix + k
+ switch val.(type) {
+ case map[string]interface{}:
+ m2 = val.(map[string]interface{})
+ case map[interface{}]interface{}:
+ m2 = cast.ToStringMap(val)
+ default:
+ // immediate value
+ shadow[strings.ToLower(fullKey)] = val
+ continue
+ }
+ // recursively merge to shadow map
+ shadow = flattenAndMergeMap(shadow, m2, fullKey, delimiter)
+ }
+ return shadow
+}
diff --git a/vendor/github.com/spf13/viper/internal/encoding/javaproperties/codec.go b/vendor/github.com/spf13/viper/internal/encoding/javaproperties/codec.go
new file mode 100644
index 000000000..b8a2251c1
--- /dev/null
+++ b/vendor/github.com/spf13/viper/internal/encoding/javaproperties/codec.go
@@ -0,0 +1,86 @@
+package javaproperties
+
+import (
+ "bytes"
+ "sort"
+ "strings"
+
+ "github.com/magiconair/properties"
+ "github.com/spf13/cast"
+)
+
+// Codec implements the encoding.Encoder and encoding.Decoder interfaces for Java properties encoding.
+type Codec struct {
+ KeyDelimiter string
+
+ // Store read properties on the object so that we can write back in order with comments.
+ // This will only be used if the configuration read is a properties file.
+ // TODO: drop this feature in v2
+ // TODO: make use of the global properties object optional
+ Properties *properties.Properties
+}
+
+func (c *Codec) Encode(v map[string]interface{}) ([]byte, error) {
+ if c.Properties == nil {
+ c.Properties = properties.NewProperties()
+ }
+
+ flattened := map[string]interface{}{}
+
+ flattened = flattenAndMergeMap(flattened, v, "", c.keyDelimiter())
+
+ keys := make([]string, 0, len(flattened))
+
+ for key := range flattened {
+ keys = append(keys, key)
+ }
+
+ sort.Strings(keys)
+
+ for _, key := range keys {
+ _, _, err := c.Properties.Set(key, cast.ToString(flattened[key]))
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ var buf bytes.Buffer
+
+ _, err := c.Properties.WriteComment(&buf, "#", properties.UTF8)
+ if err != nil {
+ return nil, err
+ }
+
+ return buf.Bytes(), nil
+}
+
+func (c *Codec) Decode(b []byte, v map[string]interface{}) error {
+ var err error
+ c.Properties, err = properties.Load(b, properties.UTF8)
+ if err != nil {
+ return err
+ }
+
+ for _, key := range c.Properties.Keys() {
+ // ignore existence check: we know it's there
+ value, _ := c.Properties.Get(key)
+
+ // recursively build nested maps
+ path := strings.Split(key, c.keyDelimiter())
+ lastKey := strings.ToLower(path[len(path)-1])
+ deepestMap := deepSearch(v, path[0:len(path)-1])
+
+ // set innermost value
+ deepestMap[lastKey] = value
+ }
+
+ return nil
+}
+
+func (c Codec) keyDelimiter() string {
+ if c.KeyDelimiter == "" {
+ return "."
+ }
+
+ return c.KeyDelimiter
+}
diff --git a/vendor/github.com/spf13/viper/internal/encoding/javaproperties/map_utils.go b/vendor/github.com/spf13/viper/internal/encoding/javaproperties/map_utils.go
new file mode 100644
index 000000000..93755cac1
--- /dev/null
+++ b/vendor/github.com/spf13/viper/internal/encoding/javaproperties/map_utils.go
@@ -0,0 +1,74 @@
+package javaproperties
+
+import (
+ "strings"
+
+ "github.com/spf13/cast"
+)
+
+// THIS CODE IS COPIED HERE: IT SHOULD NOT BE MODIFIED
+// AT SOME POINT IT WILL BE MOVED TO A COMMON PLACE
+// deepSearch scans deep maps, following the key indexes listed in the
+// sequence "path".
+// The last value is expected to be another map, and is returned.
+//
+// In case intermediate keys do not exist, or map to a non-map value,
+// a new map is created and inserted, and the search continues from there:
+// the initial map "m" may be modified!
+func deepSearch(m map[string]interface{}, path []string) map[string]interface{} {
+ for _, k := range path {
+ m2, ok := m[k]
+ if !ok {
+ // intermediate key does not exist
+ // => create it and continue from there
+ m3 := make(map[string]interface{})
+ m[k] = m3
+ m = m3
+ continue
+ }
+ m3, ok := m2.(map[string]interface{})
+ if !ok {
+ // intermediate key is a value
+ // => replace with a new map
+ m3 = make(map[string]interface{})
+ m[k] = m3
+ }
+ // continue search from here
+ m = m3
+ }
+ return m
+}
+
+// flattenAndMergeMap recursively flattens the given map into a new map
+// Code is based on the function with the same name in tha main package.
+// TODO: move it to a common place
+func flattenAndMergeMap(shadow map[string]interface{}, m map[string]interface{}, prefix string, delimiter string) map[string]interface{} {
+ if shadow != nil && prefix != "" && shadow[prefix] != nil {
+ // prefix is shadowed => nothing more to flatten
+ return shadow
+ }
+ if shadow == nil {
+ shadow = make(map[string]interface{})
+ }
+
+ var m2 map[string]interface{}
+ if prefix != "" {
+ prefix += delimiter
+ }
+ for k, val := range m {
+ fullKey := prefix + k
+ switch val.(type) {
+ case map[string]interface{}:
+ m2 = val.(map[string]interface{})
+ case map[interface{}]interface{}:
+ m2 = cast.ToStringMap(val)
+ default:
+ // immediate value
+ shadow[strings.ToLower(fullKey)] = val
+ continue
+ }
+ // recursively merge to shadow map
+ shadow = flattenAndMergeMap(shadow, m2, fullKey, delimiter)
+ }
+ return shadow
+}
diff --git a/vendor/github.com/spf13/viper/internal/encoding/json/codec.go b/vendor/github.com/spf13/viper/internal/encoding/json/codec.go
index dff9ec982..1b7caaceb 100644
--- a/vendor/github.com/spf13/viper/internal/encoding/json/codec.go
+++ b/vendor/github.com/spf13/viper/internal/encoding/json/codec.go
@@ -7,11 +7,11 @@ import (
// Codec implements the encoding.Encoder and encoding.Decoder interfaces for JSON encoding.
type Codec struct{}
-func (Codec) Encode(v interface{}) ([]byte, error) {
+func (Codec) Encode(v map[string]interface{}) ([]byte, error) {
// TODO: expose prefix and indent in the Codec as setting?
return json.MarshalIndent(v, "", " ")
}
-func (Codec) Decode(b []byte, v interface{}) error {
- return json.Unmarshal(b, v)
+func (Codec) Decode(b []byte, v map[string]interface{}) error {
+ return json.Unmarshal(b, &v)
}
diff --git a/vendor/github.com/spf13/viper/internal/encoding/toml/codec.go b/vendor/github.com/spf13/viper/internal/encoding/toml/codec.go
index c043802b9..a993c5994 100644
--- a/vendor/github.com/spf13/viper/internal/encoding/toml/codec.go
+++ b/vendor/github.com/spf13/viper/internal/encoding/toml/codec.go
@@ -1,45 +1,16 @@
package toml
import (
- "github.com/pelletier/go-toml"
+ "github.com/pelletier/go-toml/v2"
)
// Codec implements the encoding.Encoder and encoding.Decoder interfaces for TOML encoding.
type Codec struct{}
-func (Codec) Encode(v interface{}) ([]byte, error) {
- if m, ok := v.(map[string]interface{}); ok {
- t, err := toml.TreeFromMap(m)
- if err != nil {
- return nil, err
- }
-
- s, err := t.ToTomlString()
- if err != nil {
- return nil, err
- }
-
- return []byte(s), nil
- }
-
+func (Codec) Encode(v map[string]interface{}) ([]byte, error) {
return toml.Marshal(v)
}
-func (Codec) Decode(b []byte, v interface{}) error {
- tree, err := toml.LoadBytes(b)
- if err != nil {
- return err
- }
-
- if m, ok := v.(*map[string]interface{}); ok {
- vmap := *m
- tmap := tree.ToMap()
- for k, v := range tmap {
- vmap[k] = v
- }
-
- return nil
- }
-
- return tree.Unmarshal(v)
+func (Codec) Decode(b []byte, v map[string]interface{}) error {
+ return toml.Unmarshal(b, &v)
}
diff --git a/vendor/github.com/spf13/viper/internal/encoding/yaml/codec.go b/vendor/github.com/spf13/viper/internal/encoding/yaml/codec.go
index f94b26996..82dc136a3 100644
--- a/vendor/github.com/spf13/viper/internal/encoding/yaml/codec.go
+++ b/vendor/github.com/spf13/viper/internal/encoding/yaml/codec.go
@@ -1,14 +1,14 @@
package yaml
-import "gopkg.in/yaml.v2"
+import "gopkg.in/yaml.v3"
// Codec implements the encoding.Encoder and encoding.Decoder interfaces for YAML encoding.
type Codec struct{}
-func (Codec) Encode(v interface{}) ([]byte, error) {
+func (Codec) Encode(v map[string]interface{}) ([]byte, error) {
return yaml.Marshal(v)
}
-func (Codec) Decode(b []byte, v interface{}) error {
- return yaml.Unmarshal(b, v)
+func (Codec) Decode(b []byte, v map[string]interface{}) error {
+ return yaml.Unmarshal(b, &v)
}
diff --git a/vendor/github.com/spf13/viper/logger.go b/vendor/github.com/spf13/viper/logger.go
index 0115067ae..a64e1446c 100644
--- a/vendor/github.com/spf13/viper/logger.go
+++ b/vendor/github.com/spf13/viper/logger.go
@@ -7,8 +7,8 @@ import (
)
// Logger is a unified interface for various logging use cases and practices, including:
-// - leveled logging
-// - structured logging
+// - leveled logging
+// - structured logging
type Logger interface {
// Trace logs a Trace event.
//
diff --git a/vendor/github.com/spf13/viper/util.go b/vendor/github.com/spf13/viper/util.go
index ee7a86d9d..95009a147 100644
--- a/vendor/github.com/spf13/viper/util.go
+++ b/vendor/github.com/spf13/viper/util.go
@@ -31,6 +31,11 @@ func (pe ConfigParseError) Error() string {
return fmt.Sprintf("While parsing config: %s", pe.err.Error())
}
+// Unwrap returns the wrapped error.
+func (pe ConfigParseError) Unwrap() error {
+ return pe.err
+}
+
// toCaseInsensitiveValue checks if the value is a map;
// if so, create a copy and lower-case the keys recursively.
func toCaseInsensitiveValue(value interface{}) interface{} {
@@ -64,18 +69,25 @@ func copyAndInsensitiviseMap(m map[string]interface{}) map[string]interface{} {
return nm
}
+func insensitiviseVal(val interface{}) interface{} {
+ switch val.(type) {
+ case map[interface{}]interface{}:
+ // nested map: cast and recursively insensitivise
+ val = cast.ToStringMap(val)
+ insensitiviseMap(val.(map[string]interface{}))
+ case map[string]interface{}:
+ // nested map: recursively insensitivise
+ insensitiviseMap(val.(map[string]interface{}))
+ case []interface{}:
+ // nested array: recursively insensitivise
+ insensitiveArray(val.([]interface{}))
+ }
+ return val
+}
+
func insensitiviseMap(m map[string]interface{}) {
for key, val := range m {
- switch val.(type) {
- case map[interface{}]interface{}:
- // nested map: cast and recursively insensitivise
- val = cast.ToStringMap(val)
- insensitiviseMap(val.(map[string]interface{}))
- case map[string]interface{}:
- // nested map: recursively insensitivise
- insensitiviseMap(val.(map[string]interface{}))
- }
-
+ val = insensitiviseVal(val)
lower := strings.ToLower(key)
if key != lower {
// remove old key (not lower-cased)
@@ -86,6 +98,12 @@ func insensitiviseMap(m map[string]interface{}) {
}
}
+func insensitiveArray(a []interface{}) {
+ for i, val := range a {
+ a[i] = insensitiviseVal(val)
+ }
+}
+
func absPathify(logger Logger, inPath string) string {
logger.Info("trying to resolve absolute path", "path", inPath)
diff --git a/vendor/github.com/spf13/viper/viper.go b/vendor/github.com/spf13/viper/viper.go
index 4a9935899..7fb1e1913 100644
--- a/vendor/github.com/spf13/viper/viper.go
+++ b/vendor/github.com/spf13/viper/viper.go
@@ -25,7 +25,6 @@ import (
"errors"
"fmt"
"io"
- "log"
"os"
"path/filepath"
"reflect"
@@ -35,16 +34,16 @@ import (
"time"
"github.com/fsnotify/fsnotify"
- "github.com/magiconair/properties"
"github.com/mitchellh/mapstructure"
"github.com/spf13/afero"
"github.com/spf13/cast"
"github.com/spf13/pflag"
- "github.com/subosito/gotenv"
- "gopkg.in/ini.v1"
"github.com/spf13/viper/internal/encoding"
+ "github.com/spf13/viper/internal/encoding/dotenv"
"github.com/spf13/viper/internal/encoding/hcl"
+ "github.com/spf13/viper/internal/encoding/ini"
+ "github.com/spf13/viper/internal/encoding/javaproperties"
"github.com/spf13/viper/internal/encoding/json"
"github.com/spf13/viper/internal/encoding/toml"
"github.com/spf13/viper/internal/encoding/yaml"
@@ -67,47 +66,8 @@ type RemoteResponse struct {
Error error
}
-var (
- encoderRegistry = encoding.NewEncoderRegistry()
- decoderRegistry = encoding.NewDecoderRegistry()
-)
-
func init() {
v = New()
-
- {
- codec := yaml.Codec{}
-
- encoderRegistry.RegisterEncoder("yaml", codec)
- decoderRegistry.RegisterDecoder("yaml", codec)
-
- encoderRegistry.RegisterEncoder("yml", codec)
- decoderRegistry.RegisterDecoder("yml", codec)
- }
-
- {
- codec := json.Codec{}
-
- encoderRegistry.RegisterEncoder("json", codec)
- decoderRegistry.RegisterDecoder("json", codec)
- }
-
- {
- codec := toml.Codec{}
-
- encoderRegistry.RegisterEncoder("toml", codec)
- decoderRegistry.RegisterDecoder("toml", codec)
- }
-
- {
- codec := hcl.Codec{}
-
- encoderRegistry.RegisterEncoder("hcl", codec)
- decoderRegistry.RegisterDecoder("hcl", codec)
-
- encoderRegistry.RegisterEncoder("tfvars", codec)
- decoderRegistry.RegisterDecoder("tfvars", codec)
- }
}
type remoteConfigFactory interface {
@@ -171,10 +131,10 @@ type DecoderConfigOption func(*mapstructure.DecoderConfig)
// DecodeHook returns a DecoderConfigOption which overrides the default
// DecoderConfig.DecodeHook value, the default is:
//
-// mapstructure.ComposeDecodeHookFunc(
-// mapstructure.StringToTimeDurationHookFunc(),
-// mapstructure.StringToSliceHookFunc(","),
-// )
+// mapstructure.ComposeDecodeHookFunc(
+// mapstructure.StringToTimeDurationHookFunc(),
+// mapstructure.StringToSliceHookFunc(","),
+// )
func DecodeHook(hook mapstructure.DecodeHookFunc) DecoderConfigOption {
return func(c *mapstructure.DecoderConfig) {
c.DecodeHook = hook
@@ -195,18 +155,18 @@ func DecodeHook(hook mapstructure.DecodeHookFunc) DecoderConfigOption {
//
// For example, if values from the following sources were loaded:
//
-// Defaults : {
-// "secret": "",
-// "user": "default",
-// "endpoint": "https://localhost"
-// }
-// Config : {
-// "user": "root"
-// "secret": "defaultsecret"
-// }
-// Env : {
-// "secret": "somesecretkey"
-// }
+// Defaults : {
+// "secret": "",
+// "user": "default",
+// "endpoint": "https://localhost"
+// }
+// Config : {
+// "user": "root"
+// "secret": "defaultsecret"
+// }
+// Env : {
+// "secret": "somesecretkey"
+// }
//
// The resulting config will have the following values:
//
@@ -245,6 +205,7 @@ type Viper struct {
envKeyReplacer StringReplacer
allowEmptyEnv bool
+ parents []string
config map[string]interface{}
override map[string]interface{}
defaults map[string]interface{}
@@ -254,13 +215,13 @@ type Viper struct {
aliases map[string]string
typeByDefValue bool
- // Store read properties on the object so that we can write back in order with comments.
- // This will only be used if the configuration read is a properties file.
- properties *properties.Properties
-
onConfigChange func(fsnotify.Event)
logger Logger
+
+ // TODO: should probably be protected with a mutex
+ encoderRegistry *encoding.EncoderRegistry
+ decoderRegistry *encoding.DecoderRegistry
}
// New returns an initialized Viper instance.
@@ -271,6 +232,7 @@ func New() *Viper {
v.configPermissions = os.FileMode(0o644)
v.fs = afero.NewOsFs()
v.config = make(map[string]interface{})
+ v.parents = []string{}
v.override = make(map[string]interface{})
v.defaults = make(map[string]interface{})
v.kvstore = make(map[string]interface{})
@@ -280,6 +242,8 @@ func New() *Viper {
v.typeByDefValue = false
v.logger = jwwLogger{}
+ v.resetEncoding()
+
return v
}
@@ -326,6 +290,8 @@ func NewWithOptions(opts ...Option) *Viper {
opt.apply(v)
}
+ v.resetEncoding()
+
return v
}
@@ -335,7 +301,85 @@ func NewWithOptions(opts ...Option) *Viper {
func Reset() {
v = New()
SupportedExts = []string{"json", "toml", "yaml", "yml", "properties", "props", "prop", "hcl", "tfvars", "dotenv", "env", "ini"}
- SupportedRemoteProviders = []string{"etcd", "consul", "firestore"}
+ SupportedRemoteProviders = []string{"etcd", "etcd3", "consul", "firestore"}
+}
+
+// TODO: make this lazy initialization instead
+func (v *Viper) resetEncoding() {
+ encoderRegistry := encoding.NewEncoderRegistry()
+ decoderRegistry := encoding.NewDecoderRegistry()
+
+ {
+ codec := yaml.Codec{}
+
+ encoderRegistry.RegisterEncoder("yaml", codec)
+ decoderRegistry.RegisterDecoder("yaml", codec)
+
+ encoderRegistry.RegisterEncoder("yml", codec)
+ decoderRegistry.RegisterDecoder("yml", codec)
+ }
+
+ {
+ codec := json.Codec{}
+
+ encoderRegistry.RegisterEncoder("json", codec)
+ decoderRegistry.RegisterDecoder("json", codec)
+ }
+
+ {
+ codec := toml.Codec{}
+
+ encoderRegistry.RegisterEncoder("toml", codec)
+ decoderRegistry.RegisterDecoder("toml", codec)
+ }
+
+ {
+ codec := hcl.Codec{}
+
+ encoderRegistry.RegisterEncoder("hcl", codec)
+ decoderRegistry.RegisterDecoder("hcl", codec)
+
+ encoderRegistry.RegisterEncoder("tfvars", codec)
+ decoderRegistry.RegisterDecoder("tfvars", codec)
+ }
+
+ {
+ codec := ini.Codec{
+ KeyDelimiter: v.keyDelim,
+ LoadOptions: v.iniLoadOptions,
+ }
+
+ encoderRegistry.RegisterEncoder("ini", codec)
+ decoderRegistry.RegisterDecoder("ini", codec)
+ }
+
+ {
+ codec := &javaproperties.Codec{
+ KeyDelimiter: v.keyDelim,
+ }
+
+ encoderRegistry.RegisterEncoder("properties", codec)
+ decoderRegistry.RegisterDecoder("properties", codec)
+
+ encoderRegistry.RegisterEncoder("props", codec)
+ decoderRegistry.RegisterDecoder("props", codec)
+
+ encoderRegistry.RegisterEncoder("prop", codec)
+ decoderRegistry.RegisterDecoder("prop", codec)
+ }
+
+ {
+ codec := &dotenv.Codec{}
+
+ encoderRegistry.RegisterEncoder("dotenv", codec)
+ decoderRegistry.RegisterDecoder("dotenv", codec)
+
+ encoderRegistry.RegisterEncoder("env", codec)
+ decoderRegistry.RegisterDecoder("env", codec)
+ }
+
+ v.encoderRegistry = encoderRegistry
+ v.decoderRegistry = decoderRegistry
}
type defaultRemoteProvider struct {
@@ -376,28 +420,34 @@ type RemoteProvider interface {
var SupportedExts = []string{"json", "toml", "yaml", "yml", "properties", "props", "prop", "hcl", "tfvars", "dotenv", "env", "ini"}
// SupportedRemoteProviders are universally supported remote providers.
-var SupportedRemoteProviders = []string{"etcd", "consul", "firestore"}
+var SupportedRemoteProviders = []string{"etcd", "etcd3", "consul", "firestore"}
+// OnConfigChange sets the event handler that is called when a config file changes.
func OnConfigChange(run func(in fsnotify.Event)) { v.OnConfigChange(run) }
+
+// OnConfigChange sets the event handler that is called when a config file changes.
func (v *Viper) OnConfigChange(run func(in fsnotify.Event)) {
v.onConfigChange = run
}
+// WatchConfig starts watching a config file for changes.
func WatchConfig() { v.WatchConfig() }
+// WatchConfig starts watching a config file for changes.
func (v *Viper) WatchConfig() {
initWG := sync.WaitGroup{}
initWG.Add(1)
go func() {
watcher, err := newWatcher()
if err != nil {
- log.Fatal(err)
+ v.logger.Error(fmt.Sprintf("failed to create watcher: %s", err))
+ os.Exit(1)
}
defer watcher.Close()
// we have to watch the entire directory to pick up renames/atomic saves in a cross-platform way
filename, err := v.getConfigFile()
if err != nil {
- log.Printf("error: %v\n", err)
+ v.logger.Error(fmt.Sprintf("get config file: %s", err))
initWG.Done()
return
}
@@ -420,27 +470,25 @@ func (v *Viper) WatchConfig() {
// we only care about the config file with the following cases:
// 1 - if the config file was modified or created
// 2 - if the real path to the config file changed (eg: k8s ConfigMap replacement)
- const writeOrCreateMask = fsnotify.Write | fsnotify.Create
if (filepath.Clean(event.Name) == configFile &&
- event.Op&writeOrCreateMask != 0) ||
+ (event.Has(fsnotify.Write) || event.Has(fsnotify.Create))) ||
(currentConfigFile != "" && currentConfigFile != realConfigFile) {
realConfigFile = currentConfigFile
err := v.ReadInConfig()
if err != nil {
- log.Printf("error reading config file: %v\n", err)
+ v.logger.Error(fmt.Sprintf("read config file: %s", err))
}
if v.onConfigChange != nil {
v.onConfigChange(event)
}
- } else if filepath.Clean(event.Name) == configFile &&
- event.Op&fsnotify.Remove&fsnotify.Remove != 0 {
+ } else if filepath.Clean(event.Name) == configFile && event.Has(fsnotify.Remove) {
eventsWG.Done()
return
}
case err, ok := <-watcher.Errors:
if ok { // 'Errors' channel is not closed
- log.Printf("watcher error: %v\n", err)
+ v.logger.Error(fmt.Sprintf("watcher error: %s", err))
}
eventsWG.Done()
return
@@ -530,7 +578,7 @@ func (v *Viper) AddConfigPath(in string) {
// AddRemoteProvider adds a remote configuration source.
// Remote Providers are searched in the order they are added.
-// provider is a string value: "etcd", "consul" or "firestore" are currently supported.
+// provider is a string value: "etcd", "etcd3", "consul" or "firestore" are currently supported.
// endpoint is the url. etcd requires http://ip:port consul requires ip:port
// path is the path in the k/v store to retrieve configuration
// To retrieve a config file called myapp.json from /configs/myapp.json
@@ -561,7 +609,7 @@ func (v *Viper) AddRemoteProvider(provider, endpoint, path string) error {
// AddSecureRemoteProvider adds a remote configuration source.
// Secure Remote Providers are searched in the order they are added.
-// provider is a string value: "etcd", "consul" or "firestore" are currently supported.
+// provider is a string value: "etcd", "etcd3", "consul" or "firestore" are currently supported.
// endpoint is the url. etcd requires http://ip:port consul requires ip:port
// secretkeyring is the filepath to your openpgp secret keyring. e.g. /etc/secrets/myring.gpg
// path is the path in the k/v store to retrieve configuration
@@ -742,7 +790,8 @@ func (v *Viper) searchMapWithPathPrefixes(
// isPathShadowedInDeepMap makes sure the given path is not shadowed somewhere
// on its path in the map.
// e.g., if "foo.bar" has a value in the given map, it “shadows”
-// "foo.bar.baz" in a lower-priority map
+//
+// "foo.bar.baz" in a lower-priority map
func (v *Viper) isPathShadowedInDeepMap(path []string, m map[string]interface{}) string {
var parentVal interface{}
for i := 1; i < len(path); i++ {
@@ -767,7 +816,8 @@ func (v *Viper) isPathShadowedInDeepMap(path []string, m map[string]interface{})
// isPathShadowedInFlatMap makes sure the given path is not shadowed somewhere
// in a sub-path of the map.
// e.g., if "foo.bar" has a value in the given map, it “shadows”
-// "foo.bar.baz" in a lower-priority map
+//
+// "foo.bar.baz" in a lower-priority map
func (v *Viper) isPathShadowedInFlatMap(path []string, mi interface{}) string {
// unify input map
var m map[string]interface{}
@@ -792,7 +842,8 @@ func (v *Viper) isPathShadowedInFlatMap(path []string, mi interface{}) string {
// isPathShadowedInAutoEnv makes sure the given path is not shadowed somewhere
// in the environment, when automatic env is on.
// e.g., if "foo.bar" has a value in the environment, it “shadows”
-// "foo.bar.baz" in a lower-priority map
+//
+// "foo.bar.baz" in a lower-priority map
func (v *Viper) isPathShadowedInAutoEnv(path []string) string {
var parentKey string
for i := 1; i < len(path); i++ {
@@ -813,11 +864,11 @@ func (v *Viper) isPathShadowedInAutoEnv(path []string) string {
// would return a string slice for the key if the key's type is inferred by
// the default value and the Get function would return:
//
-// []string {"a", "b", "c"}
+// []string {"a", "b", "c"}
//
// Otherwise the Get function would return:
//
-// "a b c"
+// "a b c"
func SetTypeByDefaultValue(enable bool) { v.SetTypeByDefaultValue(enable) }
func (v *Viper) SetTypeByDefaultValue(enable bool) {
@@ -879,6 +930,8 @@ func (v *Viper) Get(key string) interface{} {
return cast.ToStringSlice(val)
case []int:
return cast.ToIntSlice(val)
+ case []time.Duration:
+ return cast.ToDurationSlice(val)
}
}
@@ -897,6 +950,10 @@ func (v *Viper) Sub(key string) *Viper {
}
if reflect.TypeOf(data).Kind() == reflect.Map {
+ subv.parents = append(v.parents, strings.ToLower(key))
+ subv.automaticEnvApplied = v.automaticEnvApplied
+ subv.envPrefix = v.envPrefix
+ subv.envKeyReplacer = v.envKeyReplacer
subv.config = cast.ToStringMap(data)
return subv
}
@@ -945,6 +1002,13 @@ func (v *Viper) GetUint(key string) uint {
return cast.ToUint(v.Get(key))
}
+// GetUint16 returns the value associated with the key as an unsigned integer.
+func GetUint16(key string) uint16 { return v.GetUint16(key) }
+
+func (v *Viper) GetUint16(key string) uint16 {
+ return cast.ToUint16(v.Get(key))
+}
+
// GetUint32 returns the value associated with the key as an unsigned integer.
func GetUint32(key string) uint32 { return v.GetUint32(key) }
@@ -1043,7 +1107,7 @@ func (v *Viper) Unmarshal(rawVal interface{}, opts ...DecoderConfigOption) error
return decode(v.AllSettings(), defaultDecoderConfig(rawVal, opts...))
}
-// defaultDecoderConfig returns default mapsstructure.DecoderConfig with suppot
+// defaultDecoderConfig returns default mapstructure.DecoderConfig with support
// of time.Duration values & string slices
func defaultDecoderConfig(output interface{}, opts ...DecoderConfigOption) *mapstructure.DecoderConfig {
c := &mapstructure.DecoderConfig{
@@ -1094,9 +1158,8 @@ func (v *Viper) BindPFlags(flags *pflag.FlagSet) error {
// BindPFlag binds a specific key to a pflag (as used by cobra).
// Example (where serverCmd is a Cobra instance):
//
-// serverCmd.Flags().Int("port", 1138, "Port to run Application server on")
-// Viper.BindPFlag("port", serverCmd.Flags().Lookup("port"))
-//
+// serverCmd.Flags().Int("port", 1138, "Port to run Application server on")
+// Viper.BindPFlag("port", serverCmd.Flags().Lookup("port"))
func BindPFlag(key string, flag *pflag.Flag) error { return v.BindPFlag(key, flag) }
func (v *Viper) BindPFlag(key string, flag *pflag.Flag) error {
@@ -1154,6 +1217,17 @@ func (v *Viper) BindEnv(input ...string) error {
return nil
}
+// MustBindEnv wraps BindEnv in a panic.
+// If there is an error binding an environment variable, MustBindEnv will
+// panic.
+func MustBindEnv(input ...string) { v.MustBindEnv(input...) }
+
+func (v *Viper) MustBindEnv(input ...string) {
+ if err := v.BindEnv(input...); err != nil {
+ panic(fmt.Sprintf("error while binding environment variable: %v", err))
+ }
+}
+
// Given a key, find the value.
//
// Viper will check to see if an alias exists first.
@@ -1208,8 +1282,15 @@ func (v *Viper) find(lcaseKey string, flagDefault bool) interface{} {
s = strings.TrimSuffix(s, "]")
res, _ := readAsCSV(s)
return cast.ToIntSlice(res)
+ case "durationSlice":
+ s := strings.TrimPrefix(flag.ValueString(), "[")
+ s = strings.TrimSuffix(s, "]")
+ slice := strings.Split(s, ",")
+ return cast.ToDurationSlice(slice)
case "stringToString":
return stringToStringConv(flag.ValueString())
+ case "stringToInt":
+ return stringToIntConv(flag.ValueString())
default:
return flag.ValueString()
}
@@ -1220,9 +1301,10 @@ func (v *Viper) find(lcaseKey string, flagDefault bool) interface{} {
// Env override next
if v.automaticEnvApplied {
+ envKey := strings.Join(append(v.parents, lcaseKey), ".")
// even if it hasn't been registered, if automaticEnv is used,
// check any Get request
- if val, ok := v.getEnv(v.mergeWithEnvPrefix(lcaseKey)); ok {
+ if val, ok := v.getEnv(v.mergeWithEnvPrefix(envKey)); ok {
return val
}
if nested && v.isPathShadowedInAutoEnv(path) != "" {
@@ -1289,6 +1371,13 @@ func (v *Viper) find(lcaseKey string, flagDefault bool) interface{} {
return cast.ToIntSlice(res)
case "stringToString":
return stringToStringConv(flag.ValueString())
+ case "stringToInt":
+ return stringToIntConv(flag.ValueString())
+ case "durationSlice":
+ s := strings.TrimPrefix(flag.ValueString(), "[")
+ s = strings.TrimSuffix(s, "]")
+ slice := strings.Split(s, ",")
+ return cast.ToDurationSlice(slice)
default:
return flag.ValueString()
}
@@ -1332,6 +1421,30 @@ func stringToStringConv(val string) interface{} {
return out
}
+// mostly copied from pflag's implementation of this operation here https://github.com/spf13/pflag/blob/d5e0c0615acee7028e1e2740a11102313be88de1/string_to_int.go#L68
+// alterations are: errors are swallowed, map[string]interface{} is returned in order to enable cast.ToStringMap
+func stringToIntConv(val string) interface{} {
+ val = strings.Trim(val, "[]")
+ // An empty string would cause an empty map
+ if len(val) == 0 {
+ return map[string]interface{}{}
+ }
+ ss := strings.Split(val, ",")
+ out := make(map[string]interface{}, len(ss))
+ for _, pair := range ss {
+ kv := strings.SplitN(pair, "=", 2)
+ if len(kv) != 2 {
+ return nil
+ }
+ var err error
+ out[kv[0]], err = strconv.Atoi(kv[1])
+ if err != nil {
+ return nil
+ }
+ }
+ return out
+}
+
// IsSet checks to see if the key has been set in any of the data locations.
// IsSet is case-insensitive for a key.
func IsSet(key string) bool { return v.IsSet(key) }
@@ -1634,53 +1747,11 @@ func (v *Viper) unmarshalReader(in io.Reader, c map[string]interface{}) error {
buf.ReadFrom(in)
switch format := strings.ToLower(v.getConfigType()); format {
- case "yaml", "yml", "json", "toml", "hcl", "tfvars":
- err := decoderRegistry.Decode(format, buf.Bytes(), &c)
- if err != nil {
- return ConfigParseError{err}
- }
-
- case "dotenv", "env":
- env, err := gotenv.StrictParse(buf)
- if err != nil {
- return ConfigParseError{err}
- }
- for k, v := range env {
- c[k] = v
- }
-
- case "properties", "props", "prop":
- v.properties = properties.NewProperties()
- var err error
- if v.properties, err = properties.Load(buf.Bytes(), properties.UTF8); err != nil {
- return ConfigParseError{err}
- }
- for _, key := range v.properties.Keys() {
- value, _ := v.properties.Get(key)
- // recursively build nested maps
- path := strings.Split(key, ".")
- lastKey := strings.ToLower(path[len(path)-1])
- deepestMap := deepSearch(c, path[0:len(path)-1])
- // set innermost value
- deepestMap[lastKey] = value
- }
-
- case "ini":
- cfg := ini.Empty(v.iniLoadOptions)
- err := cfg.Append(buf.Bytes())
+ case "yaml", "yml", "json", "toml", "hcl", "tfvars", "ini", "properties", "props", "prop", "dotenv", "env":
+ err := v.decoderRegistry.Decode(format, buf.Bytes(), c)
if err != nil {
return ConfigParseError{err}
}
- sections := cfg.Sections()
- for i := 0; i < len(sections); i++ {
- section := sections[i]
- keys := section.Keys()
- for j := 0; j < len(keys); j++ {
- key := keys[j]
- value := cfg.Section(section.Name()).Key(key.Name()).String()
- c[section.Name()+"."+key.Name()] = value
- }
- }
}
insensitiviseMap(c)
@@ -1691,8 +1762,8 @@ func (v *Viper) unmarshalReader(in io.Reader, c map[string]interface{}) error {
func (v *Viper) marshalWriter(f afero.File, configType string) error {
c := v.AllSettings()
switch configType {
- case "yaml", "yml", "json", "toml", "hcl", "tfvars":
- b, err := encoderRegistry.Encode(configType, c)
+ case "yaml", "yml", "json", "toml", "hcl", "tfvars", "ini", "prop", "props", "properties", "dotenv", "env":
+ b, err := v.encoderRegistry.Encode(configType, c)
if err != nil {
return ConfigMarshalError{err}
}
@@ -1701,50 +1772,6 @@ func (v *Viper) marshalWriter(f afero.File, configType string) error {
if err != nil {
return ConfigMarshalError{err}
}
-
- case "prop", "props", "properties":
- if v.properties == nil {
- v.properties = properties.NewProperties()
- }
- p := v.properties
- for _, key := range v.AllKeys() {
- _, _, err := p.Set(key, v.GetString(key))
- if err != nil {
- return ConfigMarshalError{err}
- }
- }
- _, err := p.WriteComment(f, "#", properties.UTF8)
- if err != nil {
- return ConfigMarshalError{err}
- }
-
- case "dotenv", "env":
- lines := []string{}
- for _, key := range v.AllKeys() {
- envName := strings.ToUpper(strings.Replace(key, ".", "_", -1))
- val := v.Get(key)
- lines = append(lines, fmt.Sprintf("%v=%v", envName, val))
- }
- s := strings.Join(lines, "\n")
- if _, err := f.WriteString(s); err != nil {
- return ConfigMarshalError{err}
- }
-
- case "ini":
- keys := v.AllKeys()
- cfg := ini.Empty()
- ini.PrettyFormat = false
- for i := 0; i < len(keys); i++ {
- key := keys[i]
- lastSep := strings.LastIndex(key, ".")
- sectionName := key[:(lastSep)]
- keyName := key[(lastSep + 1):]
- if sectionName == "default" {
- sectionName = ""
- }
- cfg.Section(sectionName).Key(keyName).SetValue(v.GetString(key))
- }
- cfg.WriteTo(f)
}
return nil
}
@@ -1761,7 +1788,8 @@ func keyExists(k string, m map[string]interface{}) string {
}
func castToMapStringInterface(
- src map[interface{}]interface{}) map[string]interface{} {
+ src map[interface{}]interface{},
+) map[string]interface{} {
tgt := map[string]interface{}{}
for k, v := range src {
tgt[fmt.Sprintf("%v", k)] = v
@@ -1799,7 +1827,8 @@ func castMapFlagToMapInterface(src map[string]FlagValue) map[string]interface{}
// deep. Both map types are supported as there is a go-yaml fork that uses
// `map[string]interface{}` instead.
func mergeMaps(
- src, tgt map[string]interface{}, itgt map[interface{}]interface{}) {
+ src, tgt map[string]interface{}, itgt map[interface{}]interface{},
+) {
for sk, sv := range src {
tk := keyExists(sk, tgt)
if tk == "" {
@@ -1823,17 +1852,6 @@ func mergeMaps(
svType := reflect.TypeOf(sv)
tvType := reflect.TypeOf(tv)
- if tvType != nil && svType != tvType { // Allow for the target to be nil
- v.logger.Error(
- "svType != tvType",
- "key", sk,
- "st", svType,
- "tt", tvType,
- "sv", sv,
- "tv", tv,
- )
- continue
- }
v.logger.Trace(
"processing",
@@ -1847,13 +1865,37 @@ func mergeMaps(
switch ttv := tv.(type) {
case map[interface{}]interface{}:
v.logger.Trace("merging maps (must convert)")
- tsv := sv.(map[interface{}]interface{})
+ tsv, ok := sv.(map[interface{}]interface{})
+ if !ok {
+ v.logger.Error(
+ "Could not cast sv to map[interface{}]interface{}",
+ "key", sk,
+ "st", svType,
+ "tt", tvType,
+ "sv", sv,
+ "tv", tv,
+ )
+ continue
+ }
+
ssv := castToMapStringInterface(tsv)
stv := castToMapStringInterface(ttv)
mergeMaps(ssv, stv, ttv)
case map[string]interface{}:
v.logger.Trace("merging maps")
- mergeMaps(sv.(map[string]interface{}), ttv, nil)
+ tsv, ok := sv.(map[string]interface{})
+ if !ok {
+ v.logger.Error(
+ "Could not cast sv to map[string]interface{}",
+ "key", sk,
+ "st", svType,
+ "tt", tvType,
+ "sv", sv,
+ "tv", tv,
+ )
+ continue
+ }
+ mergeMaps(tsv, ttv, nil)
default:
v.logger.Trace("setting value")
tgt[tk] = sv
@@ -1887,6 +1929,10 @@ func (v *Viper) getKeyValueConfig() error {
return RemoteConfigError("Enable the remote features by doing a blank import of the viper/remote package: '_ github.com/spf13/viper/remote'")
}
+ if len(v.remoteProviders) == 0 {
+ return RemoteConfigError("No Remote Providers")
+ }
+
for _, rp := range v.remoteProviders {
val, err := v.getRemoteConfig(rp)
if err != nil {
@@ -1913,6 +1959,10 @@ func (v *Viper) getRemoteConfig(provider RemoteProvider) (map[string]interface{}
// Retrieve the first found remote configuration.
func (v *Viper) watchKeyValueConfigOnChannel() error {
+ if len(v.remoteProviders) == 0 {
+ return RemoteConfigError("No Remote Providers")
+ }
+
for _, rp := range v.remoteProviders {
respc, _ := RemoteConfig.WatchChannel(rp)
// Todo: Add quit channel
@@ -1930,9 +1980,15 @@ func (v *Viper) watchKeyValueConfigOnChannel() error {
// Retrieve the first found remote configuration.
func (v *Viper) watchKeyValueConfig() error {
+ if len(v.remoteProviders) == 0 {
+ return RemoteConfigError("No Remote Providers")
+ }
+
for _, rp := range v.remoteProviders {
val, err := v.watchRemoteConfig(rp)
if err != nil {
+ v.logger.Error(fmt.Errorf("watch remote config: %w", err).Error())
+
continue
}
v.kvstore = val
@@ -1975,9 +2031,10 @@ func (v *Viper) AllKeys() []string {
// flattenAndMergeMap recursively flattens the given map into a map[string]bool
// of key paths (used as a set, easier to manipulate than a []string):
-// - each path is merged into a single key string, delimited with v.keyDelim
-// - if a path is shadowed by an earlier value in the initial shadow map,
-// it is skipped.
+// - each path is merged into a single key string, delimited with v.keyDelim
+// - if a path is shadowed by an earlier value in the initial shadow map,
+// it is skipped.
+//
// The resulting set of paths is merged to the given shadow set at the same time.
func (v *Viper) flattenAndMergeMap(shadow map[string]bool, m map[string]interface{}, prefix string) map[string]bool {
if shadow != nil && prefix != "" && shadow[prefix] {
@@ -2128,14 +2185,17 @@ func (v *Viper) getConfigFile() (string, error) {
// Debug prints all configuration registries for debugging
// purposes.
-func Debug() { v.Debug() }
-
-func (v *Viper) Debug() {
- fmt.Printf("Aliases:\n%#v\n", v.aliases)
- fmt.Printf("Override:\n%#v\n", v.override)
- fmt.Printf("PFlags:\n%#v\n", v.pflags)
- fmt.Printf("Env:\n%#v\n", v.env)
- fmt.Printf("Key/Value Store:\n%#v\n", v.kvstore)
- fmt.Printf("Config:\n%#v\n", v.config)
- fmt.Printf("Defaults:\n%#v\n", v.defaults)
+func Debug() { v.Debug() }
+func DebugTo(w io.Writer) { v.DebugTo(w) }
+
+func (v *Viper) Debug() { v.DebugTo(os.Stdout) }
+
+func (v *Viper) DebugTo(w io.Writer) {
+ fmt.Fprintf(w, "Aliases:\n%#v\n", v.aliases)
+ fmt.Fprintf(w, "Override:\n%#v\n", v.override)
+ fmt.Fprintf(w, "PFlags:\n%#v\n", v.pflags)
+ fmt.Fprintf(w, "Env:\n%#v\n", v.env)
+ fmt.Fprintf(w, "Key/Value Store:\n%#v\n", v.kvstore)
+ fmt.Fprintf(w, "Config:\n%#v\n", v.config)
+ fmt.Fprintf(w, "Defaults:\n%#v\n", v.defaults)
}
diff --git a/vendor/github.com/spf13/viper/watch.go b/vendor/github.com/spf13/viper/watch.go
index b5523b8f9..1ce84eaf8 100644
--- a/vendor/github.com/spf13/viper/watch.go
+++ b/vendor/github.com/spf13/viper/watch.go
@@ -1,5 +1,5 @@
-//go:build !js
-// +build !js
+//go:build darwin || dragonfly || freebsd || openbsd || linux || netbsd || solaris || windows
+// +build darwin dragonfly freebsd openbsd linux netbsd solaris windows
package viper
diff --git a/vendor/github.com/spf13/viper/watch_wasm.go b/vendor/github.com/spf13/viper/watch_unsupported.go
similarity index 52%
rename from vendor/github.com/spf13/viper/watch_wasm.go
rename to vendor/github.com/spf13/viper/watch_unsupported.go
index 8e47e6a91..7e2715377 100644
--- a/vendor/github.com/spf13/viper/watch_wasm.go
+++ b/vendor/github.com/spf13/viper/watch_unsupported.go
@@ -1,13 +1,19 @@
-// +build js,wasm
+//go:build appengine || (!darwin && !dragonfly && !freebsd && !openbsd && !linux && !netbsd && !solaris && !windows)
+// +build appengine !darwin,!dragonfly,!freebsd,!openbsd,!linux,!netbsd,!solaris,!windows
package viper
import (
- "errors"
+ "fmt"
+ "runtime"
"github.com/fsnotify/fsnotify"
)
+func newWatcher() (*watcher, error) {
+ return &watcher{}, fmt.Errorf("fsnotify not supported on %s", runtime.GOOS)
+}
+
type watcher struct {
Events chan fsnotify.Event
Errors chan error
@@ -24,7 +30,3 @@ func (*watcher) Add(name string) error {
func (*watcher) Remove(name string) error {
return nil
}
-
-func newWatcher() (*watcher, error) {
- return &watcher{}, errors.New("fsnotify is not supported on WASM")
-}
diff --git a/vendor/github.com/subosito/gotenv/.gitignore b/vendor/github.com/subosito/gotenv/.gitignore
index 2b8d45610..7db37c1db 100644
--- a/vendor/github.com/subosito/gotenv/.gitignore
+++ b/vendor/github.com/subosito/gotenv/.gitignore
@@ -1,3 +1,4 @@
*.test
*.out
annotate.json
+profile.cov
diff --git a/vendor/github.com/subosito/gotenv/.golangci.yaml b/vendor/github.com/subosito/gotenv/.golangci.yaml
new file mode 100644
index 000000000..8c82a762e
--- /dev/null
+++ b/vendor/github.com/subosito/gotenv/.golangci.yaml
@@ -0,0 +1,7 @@
+# Options for analysis running.
+run:
+ timeout: 1m
+
+linters-settings:
+ gofmt:
+ simplify: true
diff --git a/vendor/github.com/subosito/gotenv/.travis.yml b/vendor/github.com/subosito/gotenv/.travis.yml
deleted file mode 100644
index 3370d5f40..000000000
--- a/vendor/github.com/subosito/gotenv/.travis.yml
+++ /dev/null
@@ -1,10 +0,0 @@
-language: go
-go:
- - 1.x
-os:
- - linux
- - osx
-script:
- - go test -test.v -coverprofile=coverage.out -covermode=count
-after_success:
- - bash <(curl -s https://codecov.io/bash)
diff --git a/vendor/github.com/subosito/gotenv/CHANGELOG.md b/vendor/github.com/subosito/gotenv/CHANGELOG.md
index 67f687382..757caad26 100644
--- a/vendor/github.com/subosito/gotenv/CHANGELOG.md
+++ b/vendor/github.com/subosito/gotenv/CHANGELOG.md
@@ -1,5 +1,26 @@
# Changelog
+## [1.4.0] - 2022-06-02
+
+### Added
+
+- Add `Marshal` and `Unmarshal` helpers
+
+### Changed
+
+- The CI will now run a linter and the tests on PRs.
+
+## [1.3.0] - 2022-05-23
+
+### Added
+
+- Support = within double-quoted strings
+- Add support for multiline values
+
+### Changed
+
+- `OverLoad` prefer environment variables over local variables
+
## [1.2.0] - 2019-08-03
### Added
@@ -30,7 +51,7 @@
### Added
- Supports carriage return in env
-- Handle files with UTF-8 BOM
+- Handle files with UTF-8 BOM
### Changed
diff --git a/vendor/github.com/subosito/gotenv/README.md b/vendor/github.com/subosito/gotenv/README.md
index d610cdf0b..fc9616e3b 100644
--- a/vendor/github.com/subosito/gotenv/README.md
+++ b/vendor/github.com/subosito/gotenv/README.md
@@ -1,12 +1,11 @@
# gotenv
-[![Build Status](https://travis-ci.org/subosito/gotenv.svg?branch=master)](https://travis-ci.org/subosito/gotenv)
-[![Build status](https://ci.appveyor.com/api/projects/status/wb2e075xkfl0m0v2/branch/master?svg=true)](https://ci.appveyor.com/project/subosito/gotenv/branch/master)
+[![Build Status](https://github.com/subosito/gotenv/workflows/Go%20workflow/badge.svg)](https://github.com/subosito/gotenv/actions)
[![Coverage Status](https://badgen.net/codecov/c/github/subosito/gotenv)](https://codecov.io/gh/subosito/gotenv)
[![Go Report Card](https://goreportcard.com/badge/github.com/subosito/gotenv)](https://goreportcard.com/report/github.com/subosito/gotenv)
[![GoDoc](https://godoc.org/github.com/subosito/gotenv?status.svg)](https://godoc.org/github.com/subosito/gotenv)
-Load environment variables dynamically in Go.
+Load environment variables from `.env` or `io.Reader` in Go.
## Usage
@@ -29,7 +28,7 @@ Once loaded you can use `os.Getenv()` to get the value of the variable.
Let's say you have `.env` file:
-```
+```sh
APP_ID=1234567
APP_SECRET=abcdef
```
@@ -79,7 +78,6 @@ Besides above functions, `gotenv` also provides another functions that overrides
- `gotenv.OverLoad`
- `gotenv.OverApply`
-
Here's the example of this overrides behavior:
```go
@@ -120,7 +118,7 @@ Just in case you want to parse environment variables from any `io.Reader`, goten
pairs := gotenv.Parse(strings.NewReader("FOO=test\nBAR=$FOO"))
// gotenv.Env{"FOO": "test", "BAR": "test"}
-err, pairs = gotenv.StrictParse(strings.NewReader(`FOO="bar"`))
+pairs, err := gotenv.StrictParse(strings.NewReader(`FOO="bar"`))
// gotenv.Env{"FOO": "bar"}
```
diff --git a/vendor/github.com/subosito/gotenv/appveyor.yml b/vendor/github.com/subosito/gotenv/appveyor.yml
deleted file mode 100644
index 33b4c4046..000000000
--- a/vendor/github.com/subosito/gotenv/appveyor.yml
+++ /dev/null
@@ -1,9 +0,0 @@
-build: off
-clone_folder: c:\gopath\src\github.com\subosito\gotenv
-environment:
- GOPATH: c:\gopath
-stack: go 1.10
-before_test:
- - go get -t
-test_script:
- - go test -v -cover -race
diff --git a/vendor/github.com/subosito/gotenv/gotenv.go b/vendor/github.com/subosito/gotenv/gotenv.go
index 745a34489..dc013e1e0 100644
--- a/vendor/github.com/subosito/gotenv/gotenv.go
+++ b/vendor/github.com/subosito/gotenv/gotenv.go
@@ -3,10 +3,14 @@ package gotenv
import (
"bufio"
+ "bytes"
"fmt"
"io"
"os"
+ "path/filepath"
"regexp"
+ "sort"
+ "strconv"
"strings"
)
@@ -16,46 +20,39 @@ const (
// Pattern for detecting valid variable within a value
variablePattern = `(\\)?(\$)(\{?([A-Z0-9_]+)?\}?)`
+
+ // Byte order mark character
+ bom = "\xef\xbb\xbf"
)
// Env holds key/value pair of valid environment variable
type Env map[string]string
-/*
-Load is a function to load a file or multiple files and then export the valid variables into environment variables if they do not exist.
-When it's called with no argument, it will load `.env` file on the current path and set the environment variables.
-Otherwise, it will loop over the filenames parameter and set the proper environment variables.
-*/
+// Load is a function to load a file or multiple files and then export the valid variables into environment variables if they do not exist.
+// When it's called with no argument, it will load `.env` file on the current path and set the environment variables.
+// Otherwise, it will loop over the filenames parameter and set the proper environment variables.
func Load(filenames ...string) error {
return loadenv(false, filenames...)
}
-/*
-OverLoad is a function to load a file or multiple files and then export and override the valid variables into environment variables.
-*/
+// OverLoad is a function to load a file or multiple files and then export and override the valid variables into environment variables.
func OverLoad(filenames ...string) error {
return loadenv(true, filenames...)
}
-/*
-Must is wrapper function that will panic when supplied function returns an error.
-*/
+// Must is wrapper function that will panic when supplied function returns an error.
func Must(fn func(filenames ...string) error, filenames ...string) {
if err := fn(filenames...); err != nil {
panic(err.Error())
}
}
-/*
-Apply is a function to load an io Reader then export the valid variables into environment variables if they do not exist.
-*/
+// Apply is a function to load an io Reader then export the valid variables into environment variables if they do not exist.
func Apply(r io.Reader) error {
return parset(r, false)
}
-/*
-OverApply is a function to load an io Reader then export and override the valid variables into environment variables.
-*/
+// OverApply is a function to load an io Reader then export and override the valid variables into environment variables.
func OverApply(r io.Reader) error {
return parset(r, true)
}
@@ -72,11 +69,10 @@ func loadenv(override bool, filenames ...string) error {
}
err = parset(f, override)
+ f.Close()
if err != nil {
return err
}
-
- f.Close()
}
return nil
@@ -84,7 +80,7 @@ func loadenv(override bool, filenames ...string) error {
// parse and set :)
func parset(r io.Reader, override bool) error {
- env, err := StrictParse(r)
+ env, err := strictParse(r, override)
if err != nil {
return err
}
@@ -110,7 +106,7 @@ func setenv(key, val string, override bool) {
// It expands the value of a variable from the environment variable but does not set the value to the environment itself.
// This function is skipping any invalid lines and only processing the valid one.
func Parse(r io.Reader) Env {
- env, _ := StrictParse(r)
+ env, _ := strictParse(r, false)
return env
}
@@ -118,22 +114,150 @@ func Parse(r io.Reader) Env {
// It expands the value of a variable from the environment variable but does not set the value to the environment itself.
// This function is returning an error if there are any invalid lines.
func StrictParse(r io.Reader) (Env, error) {
+ return strictParse(r, false)
+}
+
+// Read is a function to parse a file line by line and returns the valid Env key/value pair of valid variables.
+// It expands the value of a variable from the environment variable but does not set the value to the environment itself.
+// This function is skipping any invalid lines and only processing the valid one.
+func Read(filename string) (Env, error) {
+ f, err := os.Open(filename)
+ if err != nil {
+ return nil, err
+ }
+ defer f.Close()
+ return strictParse(f, false)
+}
+
+// Unmarshal reads a string line by line and returns the valid Env key/value pair of valid variables.
+// It expands the value of a variable from the environment variable but does not set the value to the environment itself.
+// This function is returning an error if there are any invalid lines.
+func Unmarshal(str string) (Env, error) {
+ return strictParse(strings.NewReader(str), false)
+}
+
+// Marshal outputs the given environment as a env file.
+// Variables will be sorted by name.
+func Marshal(env Env) (string, error) {
+ lines := make([]string, 0, len(env))
+ for k, v := range env {
+ if d, err := strconv.Atoi(v); err == nil {
+ lines = append(lines, fmt.Sprintf(`%s=%d`, k, d))
+ } else {
+ lines = append(lines, fmt.Sprintf(`%s=%q`, k, v))
+ }
+ }
+ sort.Strings(lines)
+ return strings.Join(lines, "\n"), nil
+}
+
+// Write serializes the given environment and writes it to a file
+func Write(env Env, filename string) error {
+ content, err := Marshal(env)
+ if err != nil {
+ return err
+ }
+ // ensure the path exists
+ if err := os.MkdirAll(filepath.Dir(filename), 0o775); err != nil {
+ return err
+ }
+ // create or truncate the file
+ file, err := os.Create(filename)
+ if err != nil {
+ return err
+ }
+ defer file.Close()
+ _, err = file.WriteString(content + "\n")
+ if err != nil {
+ return err
+ }
+
+ return file.Sync()
+}
+
+// splitLines is a valid SplitFunc for a bufio.Scanner. It will split lines on CR ('\r'), LF ('\n') or CRLF (any of the three sequences).
+// If a CR is immediately followed by a LF, it is treated as a CRLF (one single line break).
+func splitLines(data []byte, atEOF bool) (advance int, token []byte, err error) {
+ if atEOF && len(data) == 0 {
+ return 0, nil, bufio.ErrFinalToken
+ }
+
+ idx := bytes.IndexAny(data, "\r\n")
+ switch {
+ case atEOF && idx < 0:
+ return len(data), data, bufio.ErrFinalToken
+
+ case idx < 0:
+ return 0, nil, nil
+ }
+
+ // consume CR or LF
+ eol := idx + 1
+ // detect CRLF
+ if len(data) > eol && data[eol-1] == '\r' && data[eol] == '\n' {
+ eol++
+ }
+
+ return eol, data[:idx], nil
+}
+
+func strictParse(r io.Reader, override bool) (Env, error) {
env := make(Env)
scanner := bufio.NewScanner(r)
+ scanner.Split(splitLines)
- i := 1
- bom := string([]byte{239, 187, 191})
+ firstLine := true
for scanner.Scan() {
- line := scanner.Text()
+ line := strings.TrimSpace(scanner.Text())
- if i == 1 {
+ if firstLine {
line = strings.TrimPrefix(line, bom)
+ firstLine = false
+ }
+
+ if line == "" || line[0] == '#' {
+ continue
+ }
+
+ quote := ""
+ // look for the delimiter character
+ idx := strings.Index(line, "=")
+ if idx == -1 {
+ idx = strings.Index(line, ":")
+ }
+ // look for a quote character
+ if idx > 0 && idx < len(line)-1 {
+ val := strings.TrimSpace(line[idx+1:])
+ if val[0] == '"' || val[0] == '\'' {
+ quote = val[:1]
+ // look for the closing quote character within the same line
+ idx = strings.LastIndex(strings.TrimSpace(val[1:]), quote)
+ if idx >= 0 && val[idx] != '\\' {
+ quote = ""
+ }
+ }
+ }
+ // look for the closing quote character
+ for quote != "" && scanner.Scan() {
+ l := scanner.Text()
+ line += "\n" + l
+ idx := strings.LastIndex(l, quote)
+ if idx > 0 && l[idx-1] == '\\' {
+ // foud a matching quote character but it's escaped
+ continue
+ }
+ if idx >= 0 {
+ // foud a matching quote
+ quote = ""
+ }
}
- i++
+ if quote != "" {
+ return env, fmt.Errorf("missing quotes")
+ }
- err := parseLine(line, env)
+ err := parseLine(line, env, override)
if err != nil {
return env, err
}
@@ -142,47 +266,53 @@ func StrictParse(r io.Reader) (Env, error) {
return env, nil
}
-func parseLine(s string, env Env) error {
- rl := regexp.MustCompile(linePattern)
- rm := rl.FindStringSubmatch(s)
+var (
+ lineRgx = regexp.MustCompile(linePattern)
+ unescapeRgx = regexp.MustCompile(`\\([^$])`)
+ varRgx = regexp.MustCompile(variablePattern)
+)
+
+func parseLine(s string, env Env, override bool) error {
+ rm := lineRgx.FindStringSubmatch(s)
if len(rm) == 0 {
return checkFormat(s, env)
}
- key := rm[1]
- val := rm[2]
-
- // determine if string has quote prefix
- hdq := strings.HasPrefix(val, `"`)
+ key := strings.TrimSpace(rm[1])
+ val := strings.TrimSpace(rm[2])
- // determine if string has single quote prefix
- hsq := strings.HasPrefix(val, `'`)
+ var hsq, hdq bool
- // trim whitespace
- val = strings.Trim(val, " ")
+ // check if the value is quoted
+ if l := len(val); l >= 2 {
+ l -= 1
+ // has double quotes
+ hdq = val[0] == '"' && val[l] == '"'
+ // has single quotes
+ hsq = val[0] == '\'' && val[l] == '\''
- // remove quotes '' or ""
- rq := regexp.MustCompile(`\A(['"])(.*)(['"])\z`)
- val = rq.ReplaceAllString(val, "$2")
+ // remove quotes '' or ""
+ if hsq || hdq {
+ val = val[1:l]
+ }
+ }
if hdq {
- val = strings.Replace(val, `\n`, "\n", -1)
- val = strings.Replace(val, `\r`, "\r", -1)
+ val = strings.ReplaceAll(val, `\n`, "\n")
+ val = strings.ReplaceAll(val, `\r`, "\r")
// Unescape all characters except $ so variables can be escaped properly
- re := regexp.MustCompile(`\\([^$])`)
- val = re.ReplaceAllString(val, "$1")
+ val = unescapeRgx.ReplaceAllString(val, "$1")
}
- rv := regexp.MustCompile(variablePattern)
- fv := func(s string) string {
- return varReplacement(s, hsq, env)
+ if !hsq {
+ fv := func(s string) string {
+ return varReplacement(s, hsq, env, override)
+ }
+ val = varRgx.ReplaceAllStringFunc(val, fv)
}
- val = rv.ReplaceAllStringFunc(val, fv)
- val = parseVal(val, env)
-
env[key] = val
return nil
}
@@ -201,18 +331,23 @@ func parseExport(st string, env Env) error {
return nil
}
-func varReplacement(s string, hsq bool, env Env) string {
- if strings.HasPrefix(s, "\\") {
- return strings.TrimPrefix(s, "\\")
+var varNameRgx = regexp.MustCompile(`(\$)(\{?([A-Z0-9_]+)\}?)`)
+
+func varReplacement(s string, hsq bool, env Env, override bool) string {
+ if s == "" {
+ return s
+ }
+
+ if s[0] == '\\' {
+ // the dollar sign is escaped
+ return s[1:]
}
if hsq {
return s
}
- sn := `(\$)(\{?([A-Z0-9_]+)\}?)`
- rn := regexp.MustCompile(sn)
- mn := rn.FindStringSubmatch(s)
+ mn := varNameRgx.FindStringSubmatch(s)
if len(mn) == 0 {
return s
@@ -220,18 +355,21 @@ func varReplacement(s string, hsq bool, env Env) string {
v := mn[3]
- replace, ok := env[v]
- if !ok {
- replace = os.Getenv(v)
+ if replace, ok := os.LookupEnv(v); ok && !override {
+ return replace
+ }
+
+ if replace, ok := env[v]; ok {
+ return replace
}
- return replace
+ return os.Getenv(v)
}
func checkFormat(s string, env Env) error {
st := strings.TrimSpace(s)
- if (st == "") || strings.HasPrefix(st, "#") {
+ if st == "" || st[0] == '#' {
return nil
}
@@ -241,25 +379,3 @@ func checkFormat(s string, env Env) error {
return fmt.Errorf("line `%s` doesn't match format", s)
}
-
-func parseVal(val string, env Env) string {
- if strings.Contains(val, "=") {
- if !(val == "\n" || val == "\r") {
- kv := strings.Split(val, "\n")
-
- if len(kv) == 1 {
- kv = strings.Split(val, "\r")
- }
-
- if len(kv) > 1 {
- val = kv[0]
-
- for i := 1; i < len(kv); i++ {
- parseLine(kv[i], env)
- }
- }
- }
- }
-
- return val
-}
diff --git a/vendor/golang.org/x/text/runes/cond.go b/vendor/golang.org/x/text/runes/cond.go
new file mode 100644
index 000000000..df7aa02db
--- /dev/null
+++ b/vendor/golang.org/x/text/runes/cond.go
@@ -0,0 +1,187 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runes
+
+import (
+ "unicode/utf8"
+
+ "golang.org/x/text/transform"
+)
+
+// Note: below we pass invalid UTF-8 to the tIn and tNotIn transformers as is.
+// This is done for various reasons:
+// - To retain the semantics of the Nop transformer: if input is passed to a Nop
+// one would expect it to be unchanged.
+// - It would be very expensive to pass a converted RuneError to a transformer:
+// a transformer might need more source bytes after RuneError, meaning that
+// the only way to pass it safely is to create a new buffer and manage the
+// intermingling of RuneErrors and normal input.
+// - Many transformers leave ill-formed UTF-8 as is, so this is not
+// inconsistent. Generally ill-formed UTF-8 is only replaced if it is a
+// logical consequence of the operation (as for Map) or if it otherwise would
+// pose security concerns (as for Remove).
+// - An alternative would be to return an error on ill-formed UTF-8, but this
+// would be inconsistent with other operations.
+
+// If returns a transformer that applies tIn to consecutive runes for which
+// s.Contains(r) and tNotIn to consecutive runes for which !s.Contains(r). Reset
+// is called on tIn and tNotIn at the start of each run. A Nop transformer will
+// substitute a nil value passed to tIn or tNotIn. Invalid UTF-8 is translated
+// to RuneError to determine which transformer to apply, but is passed as is to
+// the respective transformer.
+func If(s Set, tIn, tNotIn transform.Transformer) Transformer {
+ if tIn == nil && tNotIn == nil {
+ return Transformer{transform.Nop}
+ }
+ if tIn == nil {
+ tIn = transform.Nop
+ }
+ if tNotIn == nil {
+ tNotIn = transform.Nop
+ }
+ sIn, ok := tIn.(transform.SpanningTransformer)
+ if !ok {
+ sIn = dummySpan{tIn}
+ }
+ sNotIn, ok := tNotIn.(transform.SpanningTransformer)
+ if !ok {
+ sNotIn = dummySpan{tNotIn}
+ }
+
+ a := &cond{
+ tIn: sIn,
+ tNotIn: sNotIn,
+ f: s.Contains,
+ }
+ a.Reset()
+ return Transformer{a}
+}
+
+type dummySpan struct{ transform.Transformer }
+
+func (d dummySpan) Span(src []byte, atEOF bool) (n int, err error) {
+ return 0, transform.ErrEndOfSpan
+}
+
+type cond struct {
+ tIn, tNotIn transform.SpanningTransformer
+ f func(rune) bool
+ check func(rune) bool // current check to perform
+ t transform.SpanningTransformer // current transformer to use
+}
+
+// Reset implements transform.Transformer.
+func (t *cond) Reset() {
+ t.check = t.is
+ t.t = t.tIn
+ t.t.Reset() // notIn will be reset on first usage.
+}
+
+func (t *cond) is(r rune) bool {
+ if t.f(r) {
+ return true
+ }
+ t.check = t.isNot
+ t.t = t.tNotIn
+ t.tNotIn.Reset()
+ return false
+}
+
+func (t *cond) isNot(r rune) bool {
+ if !t.f(r) {
+ return true
+ }
+ t.check = t.is
+ t.t = t.tIn
+ t.tIn.Reset()
+ return false
+}
+
+// This implementation of Span doesn't help all too much, but it needs to be
+// there to satisfy this package's Transformer interface.
+// TODO: there are certainly room for improvements, though. For example, if
+// t.t == transform.Nop (which will a common occurrence) it will save a bundle
+// to special-case that loop.
+func (t *cond) Span(src []byte, atEOF bool) (n int, err error) {
+ p := 0
+ for n < len(src) && err == nil {
+ // Don't process too much at a time as the Spanner that will be
+ // called on this block may terminate early.
+ const maxChunk = 4096
+ max := len(src)
+ if v := n + maxChunk; v < max {
+ max = v
+ }
+ atEnd := false
+ size := 0
+ current := t.t
+ for ; p < max; p += size {
+ r := rune(src[p])
+ if r < utf8.RuneSelf {
+ size = 1
+ } else if r, size = utf8.DecodeRune(src[p:]); size == 1 {
+ if !atEOF && !utf8.FullRune(src[p:]) {
+ err = transform.ErrShortSrc
+ break
+ }
+ }
+ if !t.check(r) {
+ // The next rune will be the start of a new run.
+ atEnd = true
+ break
+ }
+ }
+ n2, err2 := current.Span(src[n:p], atEnd || (atEOF && p == len(src)))
+ n += n2
+ if err2 != nil {
+ return n, err2
+ }
+ // At this point either err != nil or t.check will pass for the rune at p.
+ p = n + size
+ }
+ return n, err
+}
+
+func (t *cond) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
+ p := 0
+ for nSrc < len(src) && err == nil {
+ // Don't process too much at a time, as the work might be wasted if the
+ // destination buffer isn't large enough to hold the result or a
+ // transform returns an error early.
+ const maxChunk = 4096
+ max := len(src)
+ if n := nSrc + maxChunk; n < len(src) {
+ max = n
+ }
+ atEnd := false
+ size := 0
+ current := t.t
+ for ; p < max; p += size {
+ r := rune(src[p])
+ if r < utf8.RuneSelf {
+ size = 1
+ } else if r, size = utf8.DecodeRune(src[p:]); size == 1 {
+ if !atEOF && !utf8.FullRune(src[p:]) {
+ err = transform.ErrShortSrc
+ break
+ }
+ }
+ if !t.check(r) {
+ // The next rune will be the start of a new run.
+ atEnd = true
+ break
+ }
+ }
+ nDst2, nSrc2, err2 := current.Transform(dst[nDst:], src[nSrc:p], atEnd || (atEOF && p == len(src)))
+ nDst += nDst2
+ nSrc += nSrc2
+ if err2 != nil {
+ return nDst, nSrc, err2
+ }
+ // At this point either err != nil or t.check will pass for the rune at p.
+ p = nSrc + size
+ }
+ return nDst, nSrc, err
+}
diff --git a/vendor/golang.org/x/text/runes/runes.go b/vendor/golang.org/x/text/runes/runes.go
new file mode 100644
index 000000000..930e87fed
--- /dev/null
+++ b/vendor/golang.org/x/text/runes/runes.go
@@ -0,0 +1,355 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package runes provide transforms for UTF-8 encoded text.
+package runes // import "golang.org/x/text/runes"
+
+import (
+ "unicode"
+ "unicode/utf8"
+
+ "golang.org/x/text/transform"
+)
+
+// A Set is a collection of runes.
+type Set interface {
+ // Contains returns true if r is contained in the set.
+ Contains(r rune) bool
+}
+
+type setFunc func(rune) bool
+
+func (s setFunc) Contains(r rune) bool {
+ return s(r)
+}
+
+// Note: using funcs here instead of wrapping types result in cleaner
+// documentation and a smaller API.
+
+// In creates a Set with a Contains method that returns true for all runes in
+// the given RangeTable.
+func In(rt *unicode.RangeTable) Set {
+ return setFunc(func(r rune) bool { return unicode.Is(rt, r) })
+}
+
+// NotIn creates a Set with a Contains method that returns true for all runes not
+// in the given RangeTable.
+func NotIn(rt *unicode.RangeTable) Set {
+ return setFunc(func(r rune) bool { return !unicode.Is(rt, r) })
+}
+
+// Predicate creates a Set with a Contains method that returns f(r).
+func Predicate(f func(rune) bool) Set {
+ return setFunc(f)
+}
+
+// Transformer implements the transform.Transformer interface.
+type Transformer struct {
+ t transform.SpanningTransformer
+}
+
+func (t Transformer) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
+ return t.t.Transform(dst, src, atEOF)
+}
+
+func (t Transformer) Span(b []byte, atEOF bool) (n int, err error) {
+ return t.t.Span(b, atEOF)
+}
+
+func (t Transformer) Reset() { t.t.Reset() }
+
+// Bytes returns a new byte slice with the result of converting b using t. It
+// calls Reset on t. It returns nil if any error was found. This can only happen
+// if an error-producing Transformer is passed to If.
+func (t Transformer) Bytes(b []byte) []byte {
+ b, _, err := transform.Bytes(t, b)
+ if err != nil {
+ return nil
+ }
+ return b
+}
+
+// String returns a string with the result of converting s using t. It calls
+// Reset on t. It returns the empty string if any error was found. This can only
+// happen if an error-producing Transformer is passed to If.
+func (t Transformer) String(s string) string {
+ s, _, err := transform.String(t, s)
+ if err != nil {
+ return ""
+ }
+ return s
+}
+
+// TODO:
+// - Copy: copying strings and bytes in whole-rune units.
+// - Validation (maybe)
+// - Well-formed-ness (maybe)
+
+const runeErrorString = string(utf8.RuneError)
+
+// Remove returns a Transformer that removes runes r for which s.Contains(r).
+// Illegal input bytes are replaced by RuneError before being passed to f.
+func Remove(s Set) Transformer {
+ if f, ok := s.(setFunc); ok {
+ // This little trick cuts the running time of BenchmarkRemove for sets
+ // created by Predicate roughly in half.
+ // TODO: special-case RangeTables as well.
+ return Transformer{remove(f)}
+ }
+ return Transformer{remove(s.Contains)}
+}
+
+// TODO: remove transform.RemoveFunc.
+
+type remove func(r rune) bool
+
+func (remove) Reset() {}
+
+// Span implements transform.Spanner.
+func (t remove) Span(src []byte, atEOF bool) (n int, err error) {
+ for r, size := rune(0), 0; n < len(src); {
+ if r = rune(src[n]); r < utf8.RuneSelf {
+ size = 1
+ } else if r, size = utf8.DecodeRune(src[n:]); size == 1 {
+ // Invalid rune.
+ if !atEOF && !utf8.FullRune(src[n:]) {
+ err = transform.ErrShortSrc
+ } else {
+ err = transform.ErrEndOfSpan
+ }
+ break
+ }
+ if t(r) {
+ err = transform.ErrEndOfSpan
+ break
+ }
+ n += size
+ }
+ return
+}
+
+// Transform implements transform.Transformer.
+func (t remove) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
+ for r, size := rune(0), 0; nSrc < len(src); {
+ if r = rune(src[nSrc]); r < utf8.RuneSelf {
+ size = 1
+ } else if r, size = utf8.DecodeRune(src[nSrc:]); size == 1 {
+ // Invalid rune.
+ if !atEOF && !utf8.FullRune(src[nSrc:]) {
+ err = transform.ErrShortSrc
+ break
+ }
+ // We replace illegal bytes with RuneError. Not doing so might
+ // otherwise turn a sequence of invalid UTF-8 into valid UTF-8.
+ // The resulting byte sequence may subsequently contain runes
+ // for which t(r) is true that were passed unnoticed.
+ if !t(utf8.RuneError) {
+ if nDst+3 > len(dst) {
+ err = transform.ErrShortDst
+ break
+ }
+ dst[nDst+0] = runeErrorString[0]
+ dst[nDst+1] = runeErrorString[1]
+ dst[nDst+2] = runeErrorString[2]
+ nDst += 3
+ }
+ nSrc++
+ continue
+ }
+ if t(r) {
+ nSrc += size
+ continue
+ }
+ if nDst+size > len(dst) {
+ err = transform.ErrShortDst
+ break
+ }
+ for i := 0; i < size; i++ {
+ dst[nDst] = src[nSrc]
+ nDst++
+ nSrc++
+ }
+ }
+ return
+}
+
+// Map returns a Transformer that maps the runes in the input using the given
+// mapping. Illegal bytes in the input are converted to utf8.RuneError before
+// being passed to the mapping func.
+func Map(mapping func(rune) rune) Transformer {
+ return Transformer{mapper(mapping)}
+}
+
+type mapper func(rune) rune
+
+func (mapper) Reset() {}
+
+// Span implements transform.Spanner.
+func (t mapper) Span(src []byte, atEOF bool) (n int, err error) {
+ for r, size := rune(0), 0; n < len(src); n += size {
+ if r = rune(src[n]); r < utf8.RuneSelf {
+ size = 1
+ } else if r, size = utf8.DecodeRune(src[n:]); size == 1 {
+ // Invalid rune.
+ if !atEOF && !utf8.FullRune(src[n:]) {
+ err = transform.ErrShortSrc
+ } else {
+ err = transform.ErrEndOfSpan
+ }
+ break
+ }
+ if t(r) != r {
+ err = transform.ErrEndOfSpan
+ break
+ }
+ }
+ return n, err
+}
+
+// Transform implements transform.Transformer.
+func (t mapper) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
+ var replacement rune
+ var b [utf8.UTFMax]byte
+
+ for r, size := rune(0), 0; nSrc < len(src); {
+ if r = rune(src[nSrc]); r < utf8.RuneSelf {
+ if replacement = t(r); replacement < utf8.RuneSelf {
+ if nDst == len(dst) {
+ err = transform.ErrShortDst
+ break
+ }
+ dst[nDst] = byte(replacement)
+ nDst++
+ nSrc++
+ continue
+ }
+ size = 1
+ } else if r, size = utf8.DecodeRune(src[nSrc:]); size == 1 {
+ // Invalid rune.
+ if !atEOF && !utf8.FullRune(src[nSrc:]) {
+ err = transform.ErrShortSrc
+ break
+ }
+
+ if replacement = t(utf8.RuneError); replacement == utf8.RuneError {
+ if nDst+3 > len(dst) {
+ err = transform.ErrShortDst
+ break
+ }
+ dst[nDst+0] = runeErrorString[0]
+ dst[nDst+1] = runeErrorString[1]
+ dst[nDst+2] = runeErrorString[2]
+ nDst += 3
+ nSrc++
+ continue
+ }
+ } else if replacement = t(r); replacement == r {
+ if nDst+size > len(dst) {
+ err = transform.ErrShortDst
+ break
+ }
+ for i := 0; i < size; i++ {
+ dst[nDst] = src[nSrc]
+ nDst++
+ nSrc++
+ }
+ continue
+ }
+
+ n := utf8.EncodeRune(b[:], replacement)
+
+ if nDst+n > len(dst) {
+ err = transform.ErrShortDst
+ break
+ }
+ for i := 0; i < n; i++ {
+ dst[nDst] = b[i]
+ nDst++
+ }
+ nSrc += size
+ }
+ return
+}
+
+// ReplaceIllFormed returns a transformer that replaces all input bytes that are
+// not part of a well-formed UTF-8 code sequence with utf8.RuneError.
+func ReplaceIllFormed() Transformer {
+ return Transformer{&replaceIllFormed{}}
+}
+
+type replaceIllFormed struct{ transform.NopResetter }
+
+func (t replaceIllFormed) Span(src []byte, atEOF bool) (n int, err error) {
+ for n < len(src) {
+ // ASCII fast path.
+ if src[n] < utf8.RuneSelf {
+ n++
+ continue
+ }
+
+ r, size := utf8.DecodeRune(src[n:])
+
+ // Look for a valid non-ASCII rune.
+ if r != utf8.RuneError || size != 1 {
+ n += size
+ continue
+ }
+
+ // Look for short source data.
+ if !atEOF && !utf8.FullRune(src[n:]) {
+ err = transform.ErrShortSrc
+ break
+ }
+
+ // We have an invalid rune.
+ err = transform.ErrEndOfSpan
+ break
+ }
+ return n, err
+}
+
+func (t replaceIllFormed) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
+ for nSrc < len(src) {
+ // ASCII fast path.
+ if r := src[nSrc]; r < utf8.RuneSelf {
+ if nDst == len(dst) {
+ err = transform.ErrShortDst
+ break
+ }
+ dst[nDst] = r
+ nDst++
+ nSrc++
+ continue
+ }
+
+ // Look for a valid non-ASCII rune.
+ if _, size := utf8.DecodeRune(src[nSrc:]); size != 1 {
+ if size != copy(dst[nDst:], src[nSrc:nSrc+size]) {
+ err = transform.ErrShortDst
+ break
+ }
+ nDst += size
+ nSrc += size
+ continue
+ }
+
+ // Look for short source data.
+ if !atEOF && !utf8.FullRune(src[nSrc:]) {
+ err = transform.ErrShortSrc
+ break
+ }
+
+ // We have an invalid rune.
+ if nDst+3 > len(dst) {
+ err = transform.ErrShortDst
+ break
+ }
+ dst[nDst+0] = runeErrorString[0]
+ dst[nDst+1] = runeErrorString[1]
+ dst[nDst+2] = runeErrorString[2]
+ nDst += 3
+ nSrc++
+ }
+ return nDst, nSrc, err
+}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 87322b5de..6b3670bb2 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -150,8 +150,8 @@ github.com/klauspost/cpuid/v2
# github.com/libp2p/go-reuseport v0.3.0
## explicit; go 1.19
github.com/libp2p/go-reuseport
-# github.com/magiconair/properties v1.8.5
-## explicit; go 1.13
+# github.com/magiconair/properties v1.8.7
+## explicit; go 1.19
github.com/magiconair/properties
# github.com/mailru/easyjson v0.7.7
## explicit; go 1.12
@@ -186,7 +186,7 @@ github.com/minio/minio-go/v7/pkg/tags
# github.com/minio/sha256-simd v1.0.1
## explicit; go 1.17
github.com/minio/sha256-simd
-# github.com/mitchellh/mapstructure v1.4.3
+# github.com/mitchellh/mapstructure v1.5.0
## explicit; go 1.14
github.com/mitchellh/mapstructure
# github.com/moby/spdystream v0.2.0
@@ -240,9 +240,13 @@ github.com/netsampler/goflow2/pb
github.com/netsampler/goflow2/producer
github.com/netsampler/goflow2/transport
github.com/netsampler/goflow2/utils
-# github.com/pelletier/go-toml v1.9.4
-## explicit; go 1.12
-github.com/pelletier/go-toml
+# github.com/pelletier/go-toml/v2 v2.0.8
+## explicit; go 1.16
+github.com/pelletier/go-toml/v2
+github.com/pelletier/go-toml/v2/internal/characters
+github.com/pelletier/go-toml/v2/internal/danger
+github.com/pelletier/go-toml/v2/internal/tracker
+github.com/pelletier/go-toml/v2/unstable
# github.com/pierrec/lz4/v4 v4.1.17
## explicit; go 1.14
github.com/pierrec/lz4/v4
@@ -371,12 +375,13 @@ github.com/segmentio/kafka-go/sasl/scram
# github.com/sirupsen/logrus v1.9.3
## explicit; go 1.13
github.com/sirupsen/logrus
-# github.com/spf13/afero v1.6.0
-## explicit; go 1.13
+# github.com/spf13/afero v1.9.5
+## explicit; go 1.16
github.com/spf13/afero
+github.com/spf13/afero/internal/common
github.com/spf13/afero/mem
-# github.com/spf13/cast v1.4.1
-## explicit
+# github.com/spf13/cast v1.5.1
+## explicit; go 1.18
github.com/spf13/cast
# github.com/spf13/cobra v1.7.0
## explicit; go 1.15
@@ -387,11 +392,14 @@ github.com/spf13/jwalterweatherman
# github.com/spf13/pflag v1.0.5
## explicit; go 1.12
github.com/spf13/pflag
-# github.com/spf13/viper v1.10.1
+# github.com/spf13/viper v1.16.0
## explicit; go 1.17
github.com/spf13/viper
github.com/spf13/viper/internal/encoding
+github.com/spf13/viper/internal/encoding/dotenv
github.com/spf13/viper/internal/encoding/hcl
+github.com/spf13/viper/internal/encoding/ini
+github.com/spf13/viper/internal/encoding/javaproperties
github.com/spf13/viper/internal/encoding/json
github.com/spf13/viper/internal/encoding/toml
github.com/spf13/viper/internal/encoding/yaml
@@ -403,8 +411,8 @@ github.com/stretchr/objx
github.com/stretchr/testify/assert
github.com/stretchr/testify/mock
github.com/stretchr/testify/require
-# github.com/subosito/gotenv v1.2.0
-## explicit
+# github.com/subosito/gotenv v1.4.2
+## explicit; go 1.18
github.com/subosito/gotenv
# github.com/vladimirvivien/gexe v0.2.0
## explicit; go 1.16
@@ -469,6 +477,7 @@ golang.org/x/sys/windows
golang.org/x/term
# golang.org/x/text v0.12.0
## explicit; go 1.17
+golang.org/x/text/runes
golang.org/x/text/secure/bidirule
golang.org/x/text/transform
golang.org/x/text/unicode/bidi