diff --git a/go.mod b/go.mod index fb2b22923f..6d84dc04c1 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/openshift/rosa go 1.25.8 require ( - github.com/AlecAivazis/survey/v2 v2.2.15 + github.com/AlecAivazis/survey/v2 v2.3.7 github.com/Masterminds/semver v1.5.0 github.com/PuerkitoBio/goquery v1.8.1 github.com/aws/aws-sdk-go-v2 v1.42.0 @@ -34,10 +34,10 @@ require ( github.com/openshift-online/ocm-sdk-go v0.1.503 github.com/pkg/errors v0.9.1 github.com/robfig/cron/v3 v3.0.1 - github.com/sirupsen/logrus v1.9.3 + github.com/sirupsen/logrus v1.9.4 github.com/spf13/cobra v1.10.2 github.com/spf13/pflag v1.0.10 - github.com/zgalor/weberr v0.6.0 + github.com/zgalor/weberr v0.9.0 gitlab.com/c0b/go-ordered-json v0.0.0-20201030195603-febf46534d5a go.uber.org/mock v0.6.0 gopkg.in/yaml.v3 v3.0.1 @@ -54,7 +54,6 @@ require ( github.com/fxamacker/cbor/v2 v2.9.0 // indirect github.com/go-jose/go-jose/v4 v4.1.4 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect - github.com/kr/pty v1.1.8 // indirect github.com/lib/pq v1.10.5 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/openshift-online/ocm-api-model/model v0.0.457 // indirect diff --git a/go.sum b/go.sum index 086278e1a8..55b07224df 100644 --- a/go.sum +++ b/go.sum @@ -2,14 +2,14 @@ github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 h1:/vQbFIOMb github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4/go.mod h1:hN7oaIRCjzsZ2dE+yG5k+rsdt3qcwykqK6HVGcKwsw4= github.com/99designs/keyring v1.2.2 h1:pZd3neh/EmUzWONb35LxQfvuY7kiSXAq3HQd97+XBn0= github.com/99designs/keyring v1.2.2/go.mod h1:wes/FrByc8j7lFOAGLGSNEg8f/PaI3cgTBqhFkHUrPk= -github.com/AlecAivazis/survey/v2 v2.2.15 h1:6UNMnk+YGegYFiPfdTOyZDIN+m08x2nGnqOn15BWcEQ= -github.com/AlecAivazis/survey/v2 v2.2.15/go.mod h1:TH2kPCDU3Kqq7pLbnCWwZXDBjnhZtmsCle5EiYDJ2fg= +github.com/AlecAivazis/survey/v2 v2.3.7 h1:6I/u8FvytdGsgonrYsVn2t8t4QiRnh6QSTqkkhIiSjQ= +github.com/AlecAivazis/survey/v2 v2.3.7/go.mod h1:xUTIdE4KCOIjsBAE1JYsUPoCqYdZ1reCfTwbto0Fduo= github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0= github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= -github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8 h1:xzYJEypr/85nBpB11F9br+3HUrpgb+fcm5iADzXXYEw= -github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8/go.mod h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc= +github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s= +github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w= github.com/PuerkitoBio/goquery v1.8.1 h1:uQxhNlArOIdbrH1tr0UXwdVFgDcZDrZVdcpygAcwmWM= github.com/PuerkitoBio/goquery v1.8.1/go.mod h1:Q8ICL1kNUJ2sXGoAhPGUdYDJvgQgHzJsnnd3H7Ho5jQ= github.com/alessio/shellescape v1.4.1 h1:V7yhSDDn8LP4lc4jS8pFkt0zCnzVJlG5JXy9BVKJUX0= @@ -89,8 +89,8 @@ github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UF github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cpuguy83/go-md2man/v2 v2.0.6 h1:XJtiaUW6dEEqVuZiMTn1ldk455QWwEIsMIJlo5vtkx0= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= -github.com/creack/pty v1.1.7 h1:6pwm8kMQKCmgUg0ZHTm5+/YvRK0s3THD/28+T6/kk4A= -github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI= +github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/danieljoos/wincred v1.2.0 h1:ozqKHaLK0W/ii4KVbbvluM91W2H3Sh0BncbUNPS7jLE= github.com/danieljoos/wincred v1.2.0/go.mod h1:FzQLLMKBFdvu+osBrnFODiv32YGwCfx0SkRa/eYHgec= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -141,8 +141,8 @@ github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c h1:6rhixN/i8 github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c/go.mod h1:NMPJylDgVpX0MLRlPy15sqSwOFv/U1GZ2m21JhFfek0= github.com/hashicorp/go-version v1.9.0 h1:CeOIz6k+LoN3qX9Z0tyQrPtiB1DFYRPfCIBtaXPSCnA= github.com/hashicorp/go-version v1.9.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174 h1:WlZsjVhE8Af9IcZDGgJGQpNflI3+MJSBhsgT5PCtzBQ= -github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174/go.mod h1:DqJ97dSdRW1W22yXSB90986pcOyQ7r45iio1KN2ez1A= +github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec h1:qv2VnGeEQHchGaZ/u7lxST/RaJw+cv273q79D81Xbog= +github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec/go.mod h1:Q48J4R4DvxnHolD5P8pOtXigYlRuPLGl6moFx3ulM68= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/itchyny/gojq v0.12.9 h1:biKpbKwMxVYhCU1d6mR7qMr3f0Hn9F5k5YykCVb3gmM= @@ -165,9 +165,6 @@ github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYW github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.4/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.8 h1:AkaSdXYQOWeaO3neb8EM634ahkXXe3jYbVh/F9lq+GI= -github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= @@ -237,8 +234,8 @@ github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0t github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= -github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w= +github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g= github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA= github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog= github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU= @@ -249,9 +246,8 @@ github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3A github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY= @@ -267,8 +263,8 @@ github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcY github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/zalando/go-keyring v0.2.3 h1:v9CUu9phlABObO4LPWycf+zwMG7nlbb3t/B5wa97yms= github.com/zalando/go-keyring v0.2.3/go.mod h1:HL4k+OXQfJUWaMnqyuSOc0drfGPX2b51Du6K+MRgZMk= -github.com/zgalor/weberr v0.6.0 h1:k6XSpFcOUNco8qtyAMBqXbCAVUivV7mRxGE5CMqHHdM= -github.com/zgalor/weberr v0.6.0/go.mod h1:cqK89mj84q3PRgqQXQFWJDzCorOd8xOtov/ulOnqDwc= +github.com/zgalor/weberr v0.9.0 h1:ps/W5wlzv6aruKF/e6cN+/t79Dmp23e8qpFUyCFvgg0= +github.com/zgalor/weberr v0.9.0/go.mod h1:cqK89mj84q3PRgqQXQFWJDzCorOd8xOtov/ulOnqDwc= gitlab.com/c0b/go-ordered-json v0.0.0-20201030195603-febf46534d5a h1:DxppxFKRqJ8WD6oJ3+ZXKDY0iMONQDl5UTg2aTyHh8k= gitlab.com/c0b/go-ordered-json v0.0.0-20201030195603-febf46534d5a/go.mod h1:NREvu3a57BaK0R1+ztrEzHWiZAihohNLQ6trPxlIqZI= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= @@ -280,7 +276,6 @@ go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= @@ -288,7 +283,6 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91 golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk= golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= @@ -307,14 +301,12 @@ golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -322,7 +314,6 @@ golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= @@ -332,6 +323,7 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= diff --git a/vendor/github.com/AlecAivazis/survey/v2/.travis.yml b/vendor/github.com/AlecAivazis/survey/v2/.travis.yml deleted file mode 100644 index f96db1ac0e..0000000000 --- a/vendor/github.com/AlecAivazis/survey/v2/.travis.yml +++ /dev/null @@ -1,22 +0,0 @@ -language: go - -go: - - 1.12 - -os: - - linux - - linux-ppc64le - - osx - - windows - -go_import_path: github.com/AlecAivazis/survey/v2 - -before_install: - - go get github.com/alecaivazis/run - -install: - - run install-deps - -script: - - run tests - # - run autoplay-tests diff --git a/vendor/github.com/AlecAivazis/survey/v2/CONTRIBUTING.md b/vendor/github.com/AlecAivazis/survey/v2/CONTRIBUTING.md index a84e06061e..31f5be9066 100644 --- a/vendor/github.com/AlecAivazis/survey/v2/CONTRIBUTING.md +++ b/vendor/github.com/AlecAivazis/survey/v2/CONTRIBUTING.md @@ -4,48 +4,26 @@ The following is a set of guidelines to follow when contributing to this package. These are not hard rules, please use common sense and feel free to propose changes to this document in a pull request. -## Table of Contents - -1. [Code of Conduct](#code-of-conduct) -1. [Getting Help](#getting-help) -1. [Filing a Bug Report](#how-to-file-a-bug-report) -1. [Suggesting an API change](#suggesting-an-api-change) -1. [Submitting a Contribution](#submitting-a-contribution) -1. [Writing and Running Tests](#writing-and-running-tests) - ## Code of Conduct This project and its contibutors are expected to uphold the [Go Community Code of Conduct](https://golang.org/conduct). By participating, you are expected to follow these guidelines. ## Getting help -Feel free to [open up an issue](https://github.com/AlecAivazis/survey/v2/issues/new) on GitHub when asking a question so others will be able to find it. Please remember to tag the issue with the `Question` label so the maintainers can get to your question as soon as possible. If the question is urgent, feel free to reach out to `@AlecAivazis` directly in the gophers slack channel. - -## How to file a bug report - -Bugs are tracked using the Github Issue tracker. When filing a bug, please remember to label the issue as a `Bug` and answer/provide the following: - -1. What operating system and terminal are you using? -1. An example that showcases the bug. -1. What did you expect to see? -1. What did you see instead? - -## Suggesting an API change - -If you have an idea, I'm more than happy to discuss it. Please open an issue and we can work through it. In order to maintain some sense of stability, additions to the top-level API are taken just as seriously as changes that break it. Adding stuff is much easier than removing it. +* [Open an issue](https://github.com/AlecAivazis/survey/issues/new/choose) +* Reach out to `@AlecAivazis` or `@mislav` in the Gophers slack (please use only when urgent) ## Submitting a contribution -In order to maintain stability, most features get fully integrated in more than one PR. This allows for more opportunity to think through each API change without amassing large amounts of tech debt and API changes at once. If your feature can be broken into separate chunks, it will be able to be reviewed much quicker. For example, if the PR that implemented the `Validate` field was submitted in a PR separately from one that included `survey.Required`, it would be able to get merge without having to decide how many different `Validators` we want to provide as part of `survey`'s API. - When submitting a contribution, -- Provide a description of the feature or change -- Reference the ticket addressed by the PR if there is one -- Following community standards, add comments for all exported members so that all necessary information is available on godocs -- Remember to update the project README.md with changes to the high-level API -- Include both positive and negative unit tests (when applicable) -- Contributions with visual ramifications or interaction changes should be accompanied with the appropriate `go-expect` tests. For more information on writing these tests, see [Writing and Running Tests](#writing-and-running-tests) +- Try to make a series of smaller changes instead of one large change +- Provide a description of each change that you are proposing +- Reference the issue addressed by your pull request (if there is one) +- Document all new exported Go APIs +- Update the project's README when applicable +- Include unit tests if possible +- Contributions with visual ramifications or interaction changes should be accompanied with an integration test—see below for details. ## Writing and running tests diff --git a/vendor/github.com/AlecAivazis/survey/v2/Gopkg.lock b/vendor/github.com/AlecAivazis/survey/v2/Gopkg.lock deleted file mode 100644 index b764f30811..0000000000 --- a/vendor/github.com/AlecAivazis/survey/v2/Gopkg.lock +++ /dev/null @@ -1,78 +0,0 @@ -# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. - - -[[projects]] - branch = "master" - name = "github.com/Netflix/go-expect" - packages = ["."] - revision = "c93bf25de8e869da25cf26bcd2932b36141f61ae" - -[[projects]] - name = "github.com/davecgh/go-spew" - packages = ["spew"] - revision = "346938d642f2ec3594ed81d874461961cd0faa76" - version = "v1.1.0" - -[[projects]] - branch = "master" - name = "github.com/hinshun/vt10x" - packages = ["."] - revision = "1954e646417484a2a687ea344edade2c2b6523c8" - -[[projects]] - branch = "master" - name = "github.com/kballard/go-shellquote" - packages = ["."] - revision = "95032a82bc518f77982ea72343cc1ade730072f0" - -[[projects]] - name = "github.com/kr/pty" - packages = ["."] - revision = "282ce0e5322c82529687d609ee670fac7c7d917c" - version = "v1.1.1" - -[[projects]] - name = "github.com/mattn/go-colorable" - packages = ["."] - revision = "167de6bfdfba052fa6b2d3664c8f5272e23c9072" - version = "v0.0.9" - -[[projects]] - name = "github.com/mattn/go-isatty" - packages = ["."] - revision = "0360b2af4f38e8d38c7fce2a9f4e702702d73a39" - version = "v0.0.3" - -[[projects]] - branch = "master" - name = "github.com/mgutz/ansi" - packages = ["."] - revision = "9520e82c474b0a04dd04f8a40959027271bab992" - -[[projects]] - name = "github.com/pmezard/go-difflib" - packages = ["difflib"] - revision = "792786c7400a136282c1664665ae0a8db921c6c2" - version = "v1.0.0" - -[[projects]] - name = "github.com/stretchr/testify" - packages = [ - "assert", - "require" - ] - revision = "12b6f73e6084dad08a7c6e575284b177ecafbc71" - version = "v1.2.1" - -[[projects]] - branch = "master" - name = "golang.org/x/sys" - packages = ["unix"] - revision = "9527bec2660bd847c050fda93a0f0c6dee0800bb" - -[solve-meta] - analyzer-name = "dep" - analyzer-version = 1 - inputs-digest = "371508ebad4798adc38a118f858b5c17a65b58594203548f9feb74cb781dd907" - solver-name = "gps-cdcl" - solver-version = 1 diff --git a/vendor/github.com/AlecAivazis/survey/v2/Gopkg.toml b/vendor/github.com/AlecAivazis/survey/v2/Gopkg.toml deleted file mode 100644 index 8acb825aac..0000000000 --- a/vendor/github.com/AlecAivazis/survey/v2/Gopkg.toml +++ /dev/null @@ -1,54 +0,0 @@ -# Gopkg.toml example -# -# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md -# for detailed Gopkg.toml documentation. -# -# required = ["github.com/user/thing/cmd/thing"] -# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] -# -# [[constraint]] -# name = "github.com/user/project" -# version = "1.0.0" -# -# [[constraint]] -# name = "github.com/user/project2" -# branch = "dev" -# source = "github.com/myfork/project2" -# -# [[override]] -# name = "github.com/x/y" -# version = "2.4.0" -# -# [prune] -# non-go = false -# go-tests = true -# unused-packages = true - - -[[constraint]] - branch = "master" - name = "github.com/Netflix/go-expect" - -[[constraint]] - branch = "master" - name = "github.com/hinshun/vt10x" - -[[constraint]] - name = "github.com/mattn/go-isatty" - version = "0.0.3" - -[[constraint]] - branch = "master" - name = "github.com/mgutz/ansi" - -[[constraint]] - name = "github.com/stretchr/testify" - version = "1.2.1" - -[prune] - go-tests = true - unused-packages = true - -[[constraint]] - branch = "master" - name = "github.com/kballard/go-shellquote" diff --git a/vendor/github.com/AlecAivazis/survey/v2/README.md b/vendor/github.com/AlecAivazis/survey/v2/README.md index dad8f2dd28..ba75b329f4 100644 --- a/vendor/github.com/AlecAivazis/survey/v2/README.md +++ b/vendor/github.com/AlecAivazis/survey/v2/README.md @@ -1,9 +1,8 @@ # Survey -[![Build Status](https://travis-ci.org/AlecAivazis/survey.svg?branch=feature%2Fpretty)](https://travis-ci.org/AlecAivazis/survey) [![GoDoc](http://img.shields.io/badge/godoc-reference-5272B4.svg)](https://pkg.go.dev/github.com/AlecAivazis/survey/v2) -A library for building interactive prompts on terminals supporting ANSI escape sequences. +A library for building interactive and accessible prompts on terminals supporting ANSI escape sequences. @@ -56,39 +55,12 @@ func main() { } ``` -## Table of Contents - -1. [Examples](#examples) -1. [Running the Prompts](#running-the-prompts) -1. [Prompts](#prompts) - 1. [Input](#input) - 1. [Suggestion Options](#suggestion-options) - 1. [Multiline](#multiline) - 1. [Password](#password) - 1. [Confirm](#confirm) - 1. [Select](#select) - 1. [MultiSelect](#multiselect) - 1. [Editor](#editor) -1. [Filtering Options](#filtering-options) -1. [Validation](#validation) - 1. [Built-in Validators](#built-in-validators) -1. [Help Text](#help-text) - 1. [Changing the input rune](#changing-the-input-rune) -1. [Changing the Icons ](#changing-the-icons) -1. [Custom Types](#custom-types) -1. [Testing](#testing) -1. [FAQ](#faq) - ## Examples Examples can be found in the `examples/` directory. Run them to see basic behavior: ```bash -go get github.com/AlecAivazis/survey/v2 - -cd $GOPATH/src/github.com/AlecAivazis/survey - go run examples/simple.go go run examples/validation.go ``` @@ -221,6 +193,28 @@ prompt := &survey.MultiSelect{..., PageSize: 10} survey.AskOne(prompt, &days, survey.WithPageSize(10)) ``` +#### Select options description + +The optional description text can be used to add extra information to each option listed in the select prompt: + +```golang +color := "" +prompt := &survey.Select{ + Message: "Choose a color:", + Options: []string{"red", "blue", "green"}, + Description: func(value string, index int) string { + if value == "red" { + return "My favorite color" + } + return "" + }, +} +survey.AskOne(prompt, &color) + +// Assuming that the user chose "red - My favorite color": +fmt.Println(color) //=> "red" +``` + ### MultiSelect ![Example](img/multi-select-all-none.gif) @@ -295,7 +289,7 @@ survey.AskOne(prompt, &color, survey.WithFilter(myFilter)) ## Keeping the filter active -By default the filter will disappear if the user selects one of the filtered elements. Once the user selects one element the filter setting is gone. +By default the filter will disappear if the user selects one of the filtered elements. Once the user selects one element the filter setting is gone. However the user can prevent this from happening and keep the filter active for multiple selections in a e.g. MultiSelect: @@ -342,13 +336,13 @@ survey.AskOne(prompt, &color, survey.WithValidator(survey.Required)) `survey` comes prepackaged with a few validators to fit common situations. Currently these validators include: -| name | valid types | description | notes | -| ------------ | ----------- | ----------------------------------------------------------- | ------------------------------------------------------------------------------------- | -| Required | any | Rejects zero values of the response type | Boolean values pass straight through since the zero value (false) is a valid response | -| MinLength(n) | string | Enforces that a response is at least the given length | | -| MaxLength(n) | string | Enforces that a response is no longer than the given length | | -| MaxItems(n) | []OptionAnswer | Enforces that a response has no more selections of the indicated | | -| MinItems(n) | []OptionAnswer | Enforces that a response has no less selections of the indicated | | +| name | valid types | description | notes | +| ------------ | -------------- | ---------------------------------------------------------------- | ------------------------------------------------------------------------------------- | +| Required | any | Rejects zero values of the response type | Boolean values pass straight through since the zero value (false) is a valid response | +| MinLength(n) | string | Enforces that a response is at least the given length | | +| MaxLength(n) | string | Enforces that a response is no longer than the given length | | +| MaxItems(n) | []OptionAnswer | Enforces that a response has no more selections of the indicated | | +| MinItems(n) | []OptionAnswer | Enforces that a response has no less selections of the indicated | | ## Help Text @@ -363,6 +357,39 @@ All of the prompts have a `Help` field which can be defined to provide more info } ``` +## Removing the "Select All" and "Select None" options + +By default, users can select all of the multi-select options using the right arrow key. To prevent users from being able to do this (and remove the ` to all` message from the prompt), use the option `WithRemoveSelectAll`: + +```golang +import ( + "github.com/AlecAivazis/survey/v2" +) + +number := "" +prompt := &survey.Input{ + Message: "This question has the select all option removed", +} + +survey.AskOne(prompt, &number, survey.WithRemoveSelectAll()) +``` + +Also by default, users can use the left arrow key to unselect all of the options. To prevent users from being able to do this (and remove the ` to none` message from the prompt), use the option `WithRemoveSelectNone`: + +```golang +import ( + "github.com/AlecAivazis/survey/v2" +) + +number := "" +prompt := &survey.Input{ + Message: "This question has the select all option removed", +} + +survey.AskOne(prompt, &number, survey.WithRemoveSelectNone()) +``` + + ### Changing the input rune In some situations, `?` is a perfectly valid response. To handle this, you can change the rune that survey @@ -459,22 +486,25 @@ For some examples, you can see any of the tests in this repo. ## FAQ ### What kinds of IO are supported by `survey`? + survey aims to support most terminal emulators; it expects support for ANSI escape sequences. This means that reading from piped stdin or writing to piped stdout is **not supported**, and likely to break your application in these situations. See [#337](https://github.com/AlecAivazis/survey/pull/337#issue-581351617) -### Why isn't sending a SIGINT (aka. CTRL-C) signal working? +### Why isn't Ctrl-C working? -When you send an interrupt signal to the process, it only interrupts the current prompt instead of the entire process. This manifests in a `github.com/AlecAivazis/survey/v2/terminal.InterruptErr` being returned from `Ask` and `AskOne`. If you want to stop the process, handle the returned error in your code: +Ordinarily, when you type Ctrl-C, the terminal recognizes this as the QUIT button and delivers a SIGINT signal to the process, which terminates it. +However, Survey temporarily configures the terminal to deliver control codes as ordinary input bytes. +When Survey reads a ^C byte (ASCII \x03, "end of text"), it interrupts the current survey and returns a +`github.com/AlecAivazis/survey/v2/terminal.InterruptErr` from `Ask` or `AskOne`. +If you want to stop the process, handle the returned error in your code: ```go err := survey.AskOne(prompt, &myVar) -if err == terminal.InterruptErr { - fmt.Println("interrupted") - - os.Exit(0) -} else if err != nil { - panic(err) +if err != nil { + if err == terminal.InterruptErr { + log.Fatal("interrupted") + } + ... } ``` - diff --git a/vendor/github.com/AlecAivazis/survey/v2/_tasks.hcl b/vendor/github.com/AlecAivazis/survey/v2/_tasks.hcl deleted file mode 100644 index 0eefcb5486..0000000000 --- a/vendor/github.com/AlecAivazis/survey/v2/_tasks.hcl +++ /dev/null @@ -1,19 +0,0 @@ -task "install-deps" { - description = "Install all of package dependencies" - pipeline = [ - "go get -v {{.files}}", - ] -} - -task "tests" { - description = "Run the test suite" - command = "go test -v {{.files}}" - environment = { - GOFLAGS = "-mod=vendor" - } -} - -variables = { - files = "$(go list -v ./... | grep -iEv \"tests|examples\")" -} - diff --git a/vendor/github.com/AlecAivazis/survey/v2/confirm.go b/vendor/github.com/AlecAivazis/survey/v2/confirm.go index 8e5d7efaaf..1c23fb4d12 100644 --- a/vendor/github.com/AlecAivazis/survey/v2/confirm.go +++ b/vendor/github.com/AlecAivazis/survey/v2/confirm.go @@ -49,8 +49,10 @@ func yesNo(t bool) string { func (c *Confirm) getBool(showHelp bool, config *PromptConfig) (bool, error) { cursor := c.NewCursor() rr := c.NewRuneReader() - rr.SetTermMode() - defer rr.RestoreTermMode() + _ = rr.SetTermMode() + defer func() { + _ = rr.RestoreTermMode() + }() // start waiting for input for { @@ -88,6 +90,7 @@ func (c *Confirm) getBool(showHelp bool, config *PromptConfig) (bool, error) { continue default: // we didnt get a valid answer, so print error and prompt again + //lint:ignore ST1005 it should be fine for this error message to have punctuation if err := c.Error(config, fmt.Errorf("%q is not a valid answer, please try again.", val)); err != nil { return c.Default, err } @@ -107,8 +110,6 @@ func (c *Confirm) getBool(showHelp bool, config *PromptConfig) (bool, error) { } return answer, nil } - // should not get here - return c.Default, nil } /* diff --git a/vendor/github.com/AlecAivazis/survey/v2/core/template.go b/vendor/github.com/AlecAivazis/survey/v2/core/template.go index 24dade3388..02da879dcb 100644 --- a/vendor/github.com/AlecAivazis/survey/v2/core/template.go +++ b/vendor/github.com/AlecAivazis/survey/v2/core/template.go @@ -2,6 +2,7 @@ package core import ( "bytes" + "os" "sync" "text/template" @@ -23,13 +24,24 @@ var TemplateFuncsNoColor = map[string]interface{}{ }, } -//RunTemplate returns two formatted strings given a template and -//the data it requires. The first string returned is generated for -//user-facing output and may or may not contain ANSI escape codes -//for colored output. The second string does not contain escape codes -//and can be used by the renderer for layout purposes. +// envColorDisabled returns if output colors are forbid by environment variables +func envColorDisabled() bool { + return os.Getenv("NO_COLOR") != "" || os.Getenv("CLICOLOR") == "0" +} + +// envColorForced returns if output colors are forced from environment variables +func envColorForced() bool { + val, ok := os.LookupEnv("CLICOLOR_FORCE") + return ok && val != "0" +} + +// RunTemplate returns two formatted strings given a template and +// the data it requires. The first string returned is generated for +// user-facing output and may or may not contain ANSI escape codes +// for colored output. The second string does not contain escape codes +// and can be used by the renderer for layout purposes. func RunTemplate(tmpl string, data interface{}) (string, string, error) { - tPair, err := getTemplatePair(tmpl) + tPair, err := GetTemplatePair(tmpl) if err != nil { return "", "", err } @@ -52,12 +64,12 @@ var ( memoMutex = &sync.RWMutex{} ) -//getTemplatePair returns a pair of compiled templates where the -//first template is generated for user-facing output and the -//second is generated for use by the renderer. The second -//template does not contain any color escape codes, whereas -//the first template may or may not depending on DisableColor. -func getTemplatePair(tmpl string) ([2]*template.Template, error) { +// GetTemplatePair returns a pair of compiled templates where the +// first template is generated for user-facing output and the +// second is generated for use by the renderer. The second +// template does not contain any color escape codes, whereas +// the first template may or may not depending on DisableColor. +func GetTemplatePair(tmpl string) ([2]*template.Template, error) { memoMutex.RLock() if t, ok := memoizedGetTemplate[tmpl]; ok { memoMutex.RUnlock() @@ -74,7 +86,8 @@ func getTemplatePair(tmpl string) ([2]*template.Template, error) { templatePair[1] = templateNoColor - if DisableColor { + envColorHide := envColorDisabled() && !envColorForced() + if DisableColor || envColorHide { templatePair[0] = templatePair[1] } else { templateWithColor, err := template.New("prompt").Funcs(TemplateFuncsWithColor).Parse(tmpl) diff --git a/vendor/github.com/AlecAivazis/survey/v2/core/write.go b/vendor/github.com/AlecAivazis/survey/v2/core/write.go index 47d0e498ca..2225e3b223 100644 --- a/vendor/github.com/AlecAivazis/survey/v2/core/write.go +++ b/vendor/github.com/AlecAivazis/survey/v2/core/write.go @@ -24,6 +24,11 @@ type OptionAnswer struct { Index int } +type reflectField struct { + value reflect.Value + fieldType reflect.StructField +} + func OptionAnswerList(incoming []string) []OptionAnswer { list := []OptionAnswer{} for i, opt := range incoming { @@ -63,13 +68,12 @@ func WriteAnswer(t interface{}, name string, v interface{}) (err error) { } // get the name of the field that matches the string we were given - fieldIndex, err := findFieldIndex(elem, name) + field, _, err := findField(elem, name) // if something went wrong if err != nil { // bubble up return err } - field := elem.Field(fieldIndex) // handle references to the Settable interface aswell if s, ok := field.Interface().(Settable); ok { // use the interface method @@ -138,12 +142,12 @@ func (err errFieldNotMatch) Is(target error) bool { // implements the dynamic er // It returns the Question.Name that couldn't be matched with a destination field. // // Usage: -// err := survey.Ask(qs, &v); -// if err != nil { -// if name, ok := core.IsFieldNotMatch(err); ok { -// [...name is the not matched question name] -// } -// } +// +// if err := survey.Ask(qs, &v); err != nil { +// if name, ok := core.IsFieldNotMatch(err); ok { +// // name is the question name that did not match a field +// } +// } func IsFieldNotMatch(err error) (string, bool) { if err != nil { if v, ok := err.(errFieldNotMatch); ok { @@ -156,37 +160,49 @@ func IsFieldNotMatch(err error) (string, bool) { // BUG(AlecAivazis): the current implementation might cause weird conflicts if there are // two fields with same name that only differ by casing. -func findFieldIndex(s reflect.Value, name string) (int, error) { - // the type of the value - sType := s.Type() +func findField(s reflect.Value, name string) (reflect.Value, reflect.StructField, error) { - // first look for matching tags so we can overwrite matching field names - for i := 0; i < sType.NumField(); i++ { - // the field we are current scanning - field := sType.Field(i) + fields := flattenFields(s) + // first look for matching tags so we can overwrite matching field names + for _, f := range fields { // the value of the survey tag - tag := field.Tag.Get(tagName) + tag := f.fieldType.Tag.Get(tagName) // if the tag matches the name we are looking for if tag != "" && tag == name { // then we found our index - return i, nil + return f.value, f.fieldType, nil } } // then look for matching names - for i := 0; i < sType.NumField(); i++ { - // the field we are current scanning - field := sType.Field(i) - + for _, f := range fields { // if the name of the field matches what we're looking for - if strings.ToLower(field.Name) == strings.ToLower(name) { - return i, nil + if strings.EqualFold(f.fieldType.Name, name) { + return f.value, f.fieldType, nil } } // we didn't find the field - return -1, errFieldNotMatch{name} + return reflect.Value{}, reflect.StructField{}, errFieldNotMatch{name} +} + +func flattenFields(s reflect.Value) []reflectField { + sType := s.Type() + numField := sType.NumField() + fields := make([]reflectField, 0, numField) + for i := 0; i < numField; i++ { + fieldType := sType.Field(i) + field := s.Field(i) + + if field.Kind() == reflect.Struct && fieldType.Anonymous { + // field is a promoted structure + fields = append(fields, flattenFields(field)...) + continue + } + fields = append(fields, reflectField{field, fieldType}) + } + return fields } // isList returns true if the element is something we can Len() @@ -285,6 +301,7 @@ func copy(t reflect.Value, v reflect.Value) (err error) { case reflect.Float64: castVal, casterr = strconv.ParseFloat(vString, 64) default: + //lint:ignore ST1005 allow this error message to be capitalized return fmt.Errorf("Unable to convert from string to type %s", t.Kind()) } @@ -319,6 +336,7 @@ func copy(t reflect.Value, v reflect.Value) (err error) { } // we're copying an option answer to an incorrect type + //lint:ignore ST1005 allow this error message to be capitalized return fmt.Errorf("Unable to convert from OptionAnswer to type %s", t.Kind()) } @@ -343,7 +361,9 @@ func copy(t reflect.Value, v reflect.Value) (err error) { // otherwise it could be an array case reflect.Array: // set the index to the appropriate value - copy(t.Slice(i, i+1).Index(0), v.Index(i)) + if err := copy(t.Slice(i, i+1).Index(0), v.Index(i)); err != nil { + return err + } } } } else { diff --git a/vendor/github.com/AlecAivazis/survey/v2/editor.go b/vendor/github.com/AlecAivazis/survey/v2/editor.go index ec6a141782..20470f1195 100644 --- a/vendor/github.com/AlecAivazis/survey/v2/editor.go +++ b/vendor/github.com/AlecAivazis/survey/v2/editor.go @@ -101,8 +101,10 @@ func (e *Editor) prompt(initialValue string, config *PromptConfig) (interface{}, // start reading runes from the standard in rr := e.NewRuneReader() - rr.SetTermMode() - defer rr.RestoreTermMode() + _ = rr.SetTermMode() + defer func() { + _ = rr.RestoreTermMode() + }() cursor := e.NewCursor() cursor.Hide() @@ -147,7 +149,9 @@ func (e *Editor) prompt(initialValue string, config *PromptConfig) (interface{}, if err != nil { return "", err } - defer os.Remove(f.Name()) + defer func() { + _ = os.Remove(f.Name()) + }() // write utf8 BOM header // The reason why we do this is because notepad.exe on Windows determines the diff --git a/vendor/github.com/AlecAivazis/survey/v2/input.go b/vendor/github.com/AlecAivazis/survey/v2/input.go index a1abab1456..047476386f 100644 --- a/vendor/github.com/AlecAivazis/survey/v2/input.go +++ b/vendor/github.com/AlecAivazis/survey/v2/input.go @@ -127,14 +127,14 @@ func (i *Input) onRune(config *PromptConfig) terminal.OnRuneFn { ) if err == nil { - err = readLineAgain + err = errReadLineAgain } return []rune(i.typedAnswer), true, err }) } -var readLineAgain = errors.New("read line again") +var errReadLineAgain = errors.New("read line again") func (i *Input) Prompt(config *PromptConfig) (interface{}, error) { // render the template @@ -152,9 +152,10 @@ func (i *Input) Prompt(config *PromptConfig) (interface{}, error) { // start reading runes from the standard in rr := i.NewRuneReader() - rr.SetTermMode() - defer rr.RestoreTermMode() - + _ = rr.SetTermMode() + defer func() { + _ = rr.RestoreTermMode() + }() cursor := i.NewCursor() if !config.ShowCursor { cursor.Hide() // hide the cursor @@ -169,7 +170,7 @@ func (i *Input) Prompt(config *PromptConfig) (interface{}, error) { } line, err = rr.ReadLineWithDefault(0, line, i.onRune(config)) - if err == readLineAgain { + if err == errReadLineAgain { continue } @@ -206,20 +207,13 @@ func (i *Input) Prompt(config *PromptConfig) (interface{}, error) { } func (i *Input) Cleanup(config *PromptConfig, val interface{}) error { - // use the default answer when cleaning up the prompt if necessary - ans := i.answer - if ans == "" && i.Default != "" { - ans = i.Default - } - - // render the cleanup return i.Render( InputQuestionTemplate, InputTemplateData{ Input: *i, ShowAnswer: true, Config: config, - Answer: ans, + Answer: val.(string), }, ) } diff --git a/vendor/github.com/AlecAivazis/survey/v2/multiline.go b/vendor/github.com/AlecAivazis/survey/v2/multiline.go index d0523b7eb4..bff9622f63 100644 --- a/vendor/github.com/AlecAivazis/survey/v2/multiline.go +++ b/vendor/github.com/AlecAivazis/survey/v2/multiline.go @@ -50,8 +50,10 @@ func (i *Multiline) Prompt(config *PromptConfig) (interface{}, error) { // start reading runes from the standard in rr := i.NewRuneReader() - rr.SetTermMode() - defer rr.RestoreTermMode() + _ = rr.SetTermMode() + defer func() { + _ = rr.RestoreTermMode() + }() cursor := i.NewCursor() @@ -60,7 +62,7 @@ func (i *Multiline) Prompt(config *PromptConfig) (interface{}, error) { emptyOnce := false // get the next line for { - line := []rune{} + var line []rune line, err = rr.ReadLine(0) if err != nil { return string(line), err diff --git a/vendor/github.com/AlecAivazis/survey/v2/multiselect.go b/vendor/github.com/AlecAivazis/survey/v2/multiselect.go index 3d4f95b930..396169f3e8 100644 --- a/vendor/github.com/AlecAivazis/survey/v2/multiselect.go +++ b/vendor/github.com/AlecAivazis/survey/v2/multiselect.go @@ -29,6 +29,7 @@ type MultiSelect struct { VimMode bool FilterMessage string Filter func(filter string, value string, index int) bool + Description func(value string, index int) string filter string selectedIndex int checked map[int]bool @@ -43,23 +44,46 @@ type MultiSelectTemplateData struct { Checked map[int]bool SelectedIndex int ShowHelp bool + Description func(value string, index int) string PageEntries []core.OptionAnswer Config *PromptConfig + + // These fields are used when rendering an individual option + CurrentOpt core.OptionAnswer + CurrentIndex int +} + +// IterateOption sets CurrentOpt and CurrentIndex appropriately so a multiselect option can be rendered individually +func (m MultiSelectTemplateData) IterateOption(ix int, opt core.OptionAnswer) interface{} { + copy := m + copy.CurrentIndex = ix + copy.CurrentOpt = opt + return copy +} + +func (m MultiSelectTemplateData) GetDescription(opt core.OptionAnswer) string { + if m.Description == nil { + return "" + } + return m.Description(opt.Value, opt.Index) } var MultiSelectQuestionTemplate = ` +{{- define "option"}} + {{- if eq .SelectedIndex .CurrentIndex }}{{color .Config.Icons.SelectFocus.Format }}{{ .Config.Icons.SelectFocus.Text }}{{color "reset"}}{{else}} {{end}} + {{- if index .Checked .CurrentOpt.Index }}{{color .Config.Icons.MarkedOption.Format }} {{ .Config.Icons.MarkedOption.Text }} {{else}}{{color .Config.Icons.UnmarkedOption.Format }} {{ .Config.Icons.UnmarkedOption.Text }} {{end}} + {{- color "reset"}} + {{- " "}}{{- .CurrentOpt.Value}}{{ if ne ($.GetDescription .CurrentOpt) "" }} - {{color "cyan"}}{{ $.GetDescription .CurrentOpt }}{{color "reset"}}{{end}} +{{end}} {{- if .ShowHelp }}{{- color .Config.Icons.Help.Format }}{{ .Config.Icons.Help.Text }} {{ .Help }}{{color "reset"}}{{"\n"}}{{end}} {{- color .Config.Icons.Question.Format }}{{ .Config.Icons.Question.Text }} {{color "reset"}} {{- color "default+hb"}}{{ .Message }}{{ .FilterMessage }}{{color "reset"}} {{- if .ShowAnswer}}{{color "cyan"}} {{.Answer}}{{color "reset"}}{{"\n"}} {{- else }} - {{- " "}}{{- color "cyan"}}[Use arrows to move, space to select, to all, to none, type to filter{{- if and .Help (not .ShowHelp)}}, {{ .Config.HelpInput }} for more help{{end}}]{{color "reset"}} + {{- " "}}{{- color "cyan"}}[Use arrows to move, space to select,{{- if not .Config.RemoveSelectAll }} to all,{{end}}{{- if not .Config.RemoveSelectNone }} to none,{{end}} type to filter{{- if and .Help (not .ShowHelp)}}, {{ .Config.HelpInput }} for more help{{end}}]{{color "reset"}} {{- "\n"}} {{- range $ix, $option := .PageEntries}} - {{- if eq $ix $.SelectedIndex }}{{color $.Config.Icons.SelectFocus.Format }}{{ $.Config.Icons.SelectFocus.Text }}{{color "reset"}}{{else}} {{end}} - {{- if index $.Checked $option.Index }}{{color $.Config.Icons.MarkedOption.Format }} {{ $.Config.Icons.MarkedOption.Text }} {{else}}{{color $.Config.Icons.UnmarkedOption.Format }} {{ $.Config.Icons.UnmarkedOption.Text }} {{end}} - {{- color "reset"}} - {{- " "}}{{$option.Value}}{{"\n"}} + {{- template "option" $.IterateOption $ix $option}} {{- end}} {{- end}}` @@ -119,14 +143,14 @@ func (m *MultiSelect) OnChange(key rune, config *PromptConfig) { } else if key >= terminal.KeySpace { m.filter += string(key) m.VimMode = false - } else if key == terminal.KeyArrowRight { + } else if !config.RemoveSelectAll && key == terminal.KeyArrowRight { for _, v := range options { m.checked[v.Index] = true } if !config.KeepFilter { m.filter = "" } - } else if key == terminal.KeyArrowLeft { + } else if !config.RemoveSelectNone && key == terminal.KeyArrowLeft { for _, v := range options { m.checked[v.Index] = false } @@ -159,18 +183,18 @@ func (m *MultiSelect) OnChange(key rune, config *PromptConfig) { // and we have modified the filter then we should move the page back! opts, idx := paginate(pageSize, options, m.selectedIndex) + tmplData := MultiSelectTemplateData{ + MultiSelect: *m, + SelectedIndex: idx, + Checked: m.checked, + ShowHelp: m.showingHelp, + Description: m.Description, + PageEntries: opts, + Config: config, + } + // render the options - m.Render( - MultiSelectQuestionTemplate, - MultiSelectTemplateData{ - MultiSelect: *m, - SelectedIndex: idx, - Checked: m.checked, - ShowHelp: m.showingHelp, - PageEntries: opts, - Config: config, - }, - ) + _ = m.RenderWithCursorOffset(MultiSelectQuestionTemplate, tmplData, opts, idx) } func (m *MultiSelect) filterOptions(config *PromptConfig) []core.OptionAnswer { @@ -250,27 +274,31 @@ func (m *MultiSelect) Prompt(config *PromptConfig) (interface{}, error) { opts, idx := paginate(pageSize, core.OptionAnswerList(m.Options), m.selectedIndex) cursor := m.NewCursor() - cursor.Hide() // hide the cursor - defer cursor.Show() // show the cursor when we're done + cursor.Save() // for proper cursor placement during selection + cursor.Hide() // hide the cursor + defer cursor.Show() // show the cursor when we're done + defer cursor.Restore() // clear any accessibility offsetting on exit + + tmplData := MultiSelectTemplateData{ + MultiSelect: *m, + SelectedIndex: idx, + Description: m.Description, + Checked: m.checked, + PageEntries: opts, + Config: config, + } // ask the question - err := m.Render( - MultiSelectQuestionTemplate, - MultiSelectTemplateData{ - MultiSelect: *m, - SelectedIndex: idx, - Checked: m.checked, - PageEntries: opts, - Config: config, - }, - ) + err := m.RenderWithCursorOffset(MultiSelectQuestionTemplate, tmplData, opts, idx) if err != nil { return "", err } rr := m.NewRuneReader() - rr.SetTermMode() - defer rr.RestoreTermMode() + _ = rr.SetTermMode() + defer func() { + _ = rr.RestoreTermMode() + }() // start waiting for input for { @@ -325,6 +353,7 @@ func (m *MultiSelect) Cleanup(config *PromptConfig, val interface{}) error { Checked: m.checked, Answer: answer, ShowAnswer: true, + Description: m.Description, Config: config, }, ) diff --git a/vendor/github.com/AlecAivazis/survey/v2/password.go b/vendor/github.com/AlecAivazis/survey/v2/password.go index 285bff5e75..96a2ae89fe 100644 --- a/vendor/github.com/AlecAivazis/survey/v2/password.go +++ b/vendor/github.com/AlecAivazis/survey/v2/password.go @@ -44,27 +44,32 @@ func (p *Password) Prompt(config *PromptConfig) (interface{}, error) { Config: config, }, ) - fmt.Fprint(terminal.NewAnsiStdout(p.Stdio().Out), userOut) if err != nil { return "", err } + if _, err := fmt.Fprint(terminal.NewAnsiStdout(p.Stdio().Out), userOut); err != nil { + return "", err + } + rr := p.NewRuneReader() - rr.SetTermMode() - defer rr.RestoreTermMode() + _ = rr.SetTermMode() + defer func() { + _ = rr.RestoreTermMode() + }() // no help msg? Just return any response if p.Help == "" { - line, err := rr.ReadLine('*') + line, err := rr.ReadLine(config.HideCharacter) return string(line), err } cursor := p.NewCursor() - line := []rune{} + var line []rune // process answers looking for help prompt answer for { - line, err = rr.ReadLine('*') + line, err = rr.ReadLine(config.HideCharacter) if err != nil { return string(line), err } @@ -91,7 +96,7 @@ func (p *Password) Prompt(config *PromptConfig) (interface{}, error) { } lineStr := string(line) - p.AppendRenderedText(strings.Repeat("*", len(lineStr))) + p.AppendRenderedText(strings.Repeat(string(config.HideCharacter), len(lineStr))) return lineStr, err } diff --git a/vendor/github.com/AlecAivazis/survey/v2/renderer.go b/vendor/github.com/AlecAivazis/survey/v2/renderer.go index f49029a7c4..a16207de07 100644 --- a/vendor/github.com/AlecAivazis/survey/v2/renderer.go +++ b/vendor/github.com/AlecAivazis/survey/v2/renderer.go @@ -3,8 +3,6 @@ package survey import ( "bytes" "fmt" - "unicode/utf8" - "github.com/AlecAivazis/survey/v2/core" "github.com/AlecAivazis/survey/v2/terminal" "golang.org/x/term" @@ -61,7 +59,9 @@ func (r *Renderer) Error(config *PromptConfig, invalid error) error { } // send the message to the user - fmt.Fprint(terminal.NewAnsiStdout(r.stdio.Out), userOut) + if _, err := fmt.Fprint(terminal.NewAnsiStdout(r.stdio.Out), userOut); err != nil { + return err + } // add the printed text to the rendered error buffer so we can cleanup later r.appendRenderedError(layoutOut) @@ -69,6 +69,14 @@ func (r *Renderer) Error(config *PromptConfig, invalid error) error { return nil } +func (r *Renderer) OffsetCursor(offset int) { + cursor := r.NewCursor() + for offset > 0 { + cursor.PreviousLine(1) + offset-- + } +} + func (r *Renderer) Render(tmpl string, data interface{}) error { // cleanup the currently rendered text lineCount := r.countLines(r.renderedText) @@ -82,7 +90,9 @@ func (r *Renderer) Render(tmpl string, data interface{}) error { } // print the summary - fmt.Fprint(terminal.NewAnsiStdout(r.stdio.Out), userOut) + if _, err := fmt.Fprint(terminal.NewAnsiStdout(r.stdio.Out), userOut); err != nil { + return err + } // add the printed text to the rendered text buffer so we can cleanup later r.AppendRenderedText(layoutOut) @@ -91,6 +101,21 @@ func (r *Renderer) Render(tmpl string, data interface{}) error { return nil } +func (r *Renderer) RenderWithCursorOffset(tmpl string, data IterableOpts, opts []core.OptionAnswer, idx int) error { + cursor := r.NewCursor() + cursor.Restore() // clear any accessibility offsetting + + if err := r.Render(tmpl, data); err != nil { + return err + } + cursor.Save() + + offset := computeCursorOffset(MultiSelectQuestionTemplate, data, opts, idx, r.termWidthSafe()) + r.OffsetCursor(offset) + + return nil +} + // appendRenderedError appends text to the renderer's error buffer // which is used to track what has been printed. It is not exported // as errors should only be displayed via Error(config, error). @@ -123,22 +148,27 @@ func (r *Renderer) termWidth() (int, error) { return termWidth, err } -// countLines will return the count of `\n` with the addition of any -// lines that have wrapped due to narrow terminal width -func (r *Renderer) countLines(buf bytes.Buffer) int { +func (r *Renderer) termWidthSafe() int { w, err := r.termWidth() if err != nil || w == 0 { // if we got an error due to terminal.GetSize not being supported // on current platform then just assume a very wide terminal w = 10000 } + return w +} + +// countLines will return the count of `\n` with the addition of any +// lines that have wrapped due to narrow terminal width +func (r *Renderer) countLines(buf bytes.Buffer) int { + w := r.termWidthSafe() bufBytes := buf.Bytes() count := 0 curr := 0 - delim := -1 for curr < len(bufBytes) { + var delim int // read until the next newline or the end of the string relDelim := bytes.IndexRune(bufBytes[curr:], '\n') if relDelim != -1 { @@ -148,7 +178,8 @@ func (r *Renderer) countLines(buf bytes.Buffer) int { delim = len(bufBytes) // no new line found, read rest of text } - if lineWidth := utf8.RuneCount(bufBytes[curr:delim]); lineWidth > w { + str := string(bufBytes[curr:delim]) + if lineWidth := terminal.StringWidth(str); lineWidth > w { // account for word wrapping count += lineWidth / w if (lineWidth % w) == 0 { diff --git a/vendor/github.com/AlecAivazis/survey/v2/select.go b/vendor/github.com/AlecAivazis/survey/v2/select.go index fdce038173..1210122f40 100644 --- a/vendor/github.com/AlecAivazis/survey/v2/select.go +++ b/vendor/github.com/AlecAivazis/survey/v2/select.go @@ -2,6 +2,7 @@ package survey import ( "errors" + "fmt" "github.com/AlecAivazis/survey/v2/core" "github.com/AlecAivazis/survey/v2/terminal" @@ -28,9 +29,9 @@ type Select struct { VimMode bool FilterMessage string Filter func(filter string, value string, index int) bool + Description func(value string, index int) string filter string selectedIndex int - useDefault bool showingHelp bool } @@ -42,10 +43,35 @@ type SelectTemplateData struct { Answer string ShowAnswer bool ShowHelp bool + Description func(value string, index int) string Config *PromptConfig + + // These fields are used when rendering an individual option + CurrentOpt core.OptionAnswer + CurrentIndex int +} + +// IterateOption sets CurrentOpt and CurrentIndex appropriately so a select option can be rendered individually +func (s SelectTemplateData) IterateOption(ix int, opt core.OptionAnswer) interface{} { + copy := s + copy.CurrentIndex = ix + copy.CurrentOpt = opt + return copy +} + +func (s SelectTemplateData) GetDescription(opt core.OptionAnswer) string { + if s.Description == nil { + return "" + } + return s.Description(opt.Value, opt.Index) } var SelectQuestionTemplate = ` +{{- define "option"}} + {{- if eq .SelectedIndex .CurrentIndex }}{{color .Config.Icons.SelectFocus.Format }}{{ .Config.Icons.SelectFocus.Text }} {{else}}{{color "default"}} {{end}} + {{- .CurrentOpt.Value}}{{ if ne ($.GetDescription .CurrentOpt) "" }} - {{color "cyan"}}{{ $.GetDescription .CurrentOpt }}{{end}} + {{- color "reset"}} +{{end}} {{- if .ShowHelp }}{{- color .Config.Icons.Help.Format }}{{ .Config.Icons.Help.Text }} {{ .Help }}{{color "reset"}}{{"\n"}}{{end}} {{- color .Config.Icons.Question.Format }}{{ .Config.Icons.Question.Text }} {{color "reset"}} {{- color "default+hb"}}{{ .Message }}{{ .FilterMessage }}{{color "reset"}} @@ -53,10 +79,8 @@ var SelectQuestionTemplate = ` {{- else}} {{- " "}}{{- color "cyan"}}[Use arrows to move, type to filter{{- if and .Help (not .ShowHelp)}}, {{ .Config.HelpInput }} for more help{{end}}]{{color "reset"}} {{- "\n"}} - {{- range $ix, $choice := .PageEntries}} - {{- if eq $ix $.SelectedIndex }}{{color $.Config.Icons.SelectFocus.Format }}{{ $.Config.Icons.SelectFocus.Text }} {{else}}{{color "default"}} {{end}} - {{- $choice.Value}} - {{- color "reset"}}{{"\n"}} + {{- range $ix, $option := .PageEntries}} + {{- template "option" $.IterateOption $ix $option}} {{- end}} {{- end}}` @@ -79,8 +103,6 @@ func (s *Select) OnChange(key rune, config *PromptConfig) bool { // if the user pressed the up arrow or 'k' to emulate vim } else if (key == terminal.KeyArrowUp || (s.VimMode && key == 'k')) && len(options) > 0 { - s.useDefault = false - // if we are at the top of the list if s.selectedIndex == 0 { // start from the button @@ -92,7 +114,6 @@ func (s *Select) OnChange(key rune, config *PromptConfig) bool { // if the user pressed down or 'j' to emulate vim } else if (key == terminal.KeyTab || key == terminal.KeyArrowDown || (s.VimMode && key == 'j')) && len(options) > 0 { - s.useDefault = false // if we are at the bottom of the list if s.selectedIndex == len(options)-1 { // start from the top @@ -123,8 +144,6 @@ func (s *Select) OnChange(key rune, config *PromptConfig) bool { s.filter += string(key) // make sure vim mode is disabled s.VimMode = false - // make sure that we use the current value in the filtered list - s.useDefault = false } s.FilterMessage = "" @@ -152,17 +171,17 @@ func (s *Select) OnChange(key rune, config *PromptConfig) bool { // and we have modified the filter then we should move the page back! opts, idx := paginate(pageSize, options, s.selectedIndex) + tmplData := SelectTemplateData{ + Select: *s, + SelectedIndex: idx, + ShowHelp: s.showingHelp, + Description: s.Description, + PageEntries: opts, + Config: config, + } + // render the options - s.Render( - SelectQuestionTemplate, - SelectTemplateData{ - Select: *s, - SelectedIndex: idx, - ShowHelp: s.showingHelp, - PageEntries: opts, - Config: config, - }, - ) + _ = s.RenderWithCursorOffset(SelectQuestionTemplate, tmplData, opts, idx) // keep prompting return false @@ -183,7 +202,6 @@ func (s *Select) filterOptions(config *PromptConfig) []core.OptionAnswer { filter = config.Filter } - // for i, opt := range s.Options { // i the filter says to include the option if filter(s.filter, opt, i) { @@ -205,23 +223,29 @@ func (s *Select) Prompt(config *PromptConfig) (interface{}, error) { return "", errors.New("please provide options to select from") } - // start off with the first option selected - sel := 0 - // if there is a default - if s.Default != "" { - // find the choice - for i, opt := range s.Options { - // if the option corresponds to the default - if opt == s.Default { - // we found our initial value - sel = i - // stop looking - break + s.selectedIndex = 0 + if s.Default != nil { + switch defaultValue := s.Default.(type) { + case string: + var found bool + for i, opt := range s.Options { + if opt == defaultValue { + s.selectedIndex = i + found = true + } + } + if !found { + return "", fmt.Errorf("default value %q not found in options", defaultValue) } + case int: + if defaultValue >= len(s.Options) { + return "", fmt.Errorf("default index %d exceeds the number of options", defaultValue) + } + s.selectedIndex = defaultValue + default: + return "", errors.New("default value of select must be an int or string") } } - // save the selected index - s.selectedIndex = sel // figure out the page size pageSize := s.PageSize @@ -232,32 +256,34 @@ func (s *Select) Prompt(config *PromptConfig) (interface{}, error) { } // figure out the options and index to render - opts, idx := paginate(pageSize, core.OptionAnswerList(s.Options), sel) + opts, idx := paginate(pageSize, core.OptionAnswerList(s.Options), s.selectedIndex) + + cursor := s.NewCursor() + cursor.Save() // for proper cursor placement during selection + cursor.Hide() // hide the cursor + defer cursor.Show() // show the cursor when we're done + defer cursor.Restore() // clear any accessibility offsetting on exit + + tmplData := SelectTemplateData{ + Select: *s, + SelectedIndex: idx, + Description: s.Description, + ShowHelp: s.showingHelp, + PageEntries: opts, + Config: config, + } // ask the question - err := s.Render( - SelectQuestionTemplate, - SelectTemplateData{ - Select: *s, - PageEntries: opts, - SelectedIndex: idx, - Config: config, - }, - ) + err := s.RenderWithCursorOffset(SelectQuestionTemplate, tmplData, opts, idx) if err != nil { return "", err } - // by default, use the default value - s.useDefault = true - rr := s.NewRuneReader() - rr.SetTermMode() - defer rr.RestoreTermMode() - - cursor := s.NewCursor() - cursor.Hide() // hide the cursor - defer cursor.Show() // show the cursor when we're done + _ = rr.SetTermMode() + defer func() { + _ = rr.RestoreTermMode() + }() // start waiting for input for { @@ -275,55 +301,29 @@ func (s *Select) Prompt(config *PromptConfig) (interface{}, error) { break } } + options := s.filterOptions(config) s.filter = "" s.FilterMessage = "" - // the index to report - var val string - // if we are supposed to use the default value - if s.useDefault || s.selectedIndex >= len(options) { - // if there is a default value - if s.Default != nil { - // if the default is a string - if defaultString, ok := s.Default.(string); ok { - // use the default value - val = defaultString - // the default value could also be an interpret which is interpretted as the index - } else if defaultIndex, ok := s.Default.(int); ok { - val = s.Options[defaultIndex] - } else { - return val, errors.New("default value of select must be an int or string") - } - } else if len(options) > 0 { - // there is no default value so use the first - val = options[0].Value - } - // otherwise the selected index points to the value - } else if s.selectedIndex < len(options) { - // the - val = options[s.selectedIndex].Value - } - - // now that we have the value lets go hunt down the right index to return - idx = -1 - for i, optionValue := range s.Options { - if optionValue == val { - idx = i - } + if s.selectedIndex < len(options) { + return options[s.selectedIndex], err } - return core.OptionAnswer{Value: val, Index: idx}, err + return options[0], err } func (s *Select) Cleanup(config *PromptConfig, val interface{}) error { + cursor := s.NewCursor() + cursor.Restore() return s.Render( SelectQuestionTemplate, SelectTemplateData{ - Select: *s, - Answer: val.(core.OptionAnswer).Value, - ShowAnswer: true, - Config: config, + Select: *s, + Answer: val.(core.OptionAnswer).Value, + ShowAnswer: true, + Description: s.Description, + Config: config, }, ) } diff --git a/vendor/github.com/AlecAivazis/survey/v2/survey.go b/vendor/github.com/AlecAivazis/survey/v2/survey.go index 1944ffc5c6..aad73bbe70 100644 --- a/vendor/github.com/AlecAivazis/survey/v2/survey.go +++ b/vendor/github.com/AlecAivazis/survey/v2/survey.go @@ -1,10 +1,12 @@ package survey import ( + "bytes" "errors" "io" "os" "strings" + "unicode/utf8" "github.com/AlecAivazis/survey/v2/core" "github.com/AlecAivazis/survey/v2/terminal" @@ -54,8 +56,11 @@ func defaultAskOptions() *AskOptions { // include this option if it matches return strings.Contains(strings.ToLower(value), filter) }, - KeepFilter: false, - ShowCursor: false, + KeepFilter: false, + ShowCursor: false, + RemoveSelectAll: false, + RemoveSelectNone: false, + HideCharacter: '*', }, } } @@ -109,13 +114,16 @@ type Question struct { // PromptConfig holds the global configuration for a prompt type PromptConfig struct { - PageSize int - Icons IconSet - HelpInput string - SuggestInput string - Filter func(filter string, option string, index int) bool - KeepFilter bool - ShowCursor bool + PageSize int + Icons IconSet + HelpInput string + SuggestInput string + Filter func(filter string, option string, index int) bool + KeepFilter bool + ShowCursor bool + RemoveSelectAll bool + RemoveSelectNone bool + HideCharacter rune } // Prompt is the primary interface for the objects that can take user input @@ -173,6 +181,22 @@ func WithKeepFilter(KeepFilter bool) AskOpt { } } +// WithRemoveSelectAll remove the select all option in Multiselect +func WithRemoveSelectAll() AskOpt { + return func(options *AskOptions) error { + options.PromptConfig.RemoveSelectAll = true + return nil + } +} + +// WithRemoveSelectNone remove the select none/unselect all in Multiselect +func WithRemoveSelectNone() AskOpt { + return func(options *AskOptions) error { + options.PromptConfig.RemoveSelectNone = true + return nil + } +} + // WithValidator specifies a validator to use while prompting the user func WithValidator(v Validator) AskOpt { return func(options *AskOptions) error { @@ -232,6 +256,17 @@ func WithShowCursor(ShowCursor bool) AskOpt { } } +// WithHideCharacter sets the default character shown instead of the password for password inputs +func WithHideCharacter(char rune) AskOpt { + return func(options *AskOptions) error { + // set the hide character + options.PromptConfig.HideCharacter = char + + // nothing went wrong + return nil + } +} + /* AskOne performs the prompt for a single prompt and asks for validation if required. Response types should be something that can be casted from the response type designated @@ -243,7 +278,6 @@ in the documentation. For example: } survey.AskOne(prompt, &name) - */ func AskOne(p Prompt, response interface{}, opts ...AskOpt) error { err := Ask([]*Question{{Prompt: p}}, response, opts...) @@ -295,6 +329,20 @@ func Ask(qs []*Question, response interface{}, opts ...AskOpt) error { return errors.New("cannot call Ask() with a nil reference to record the answers") } + validate := func(q *Question, val interface{}) error { + if q.Validate != nil { + if err := q.Validate(val); err != nil { + return err + } + } + for _, v := range options.Validators { + if err := v(val); err != nil { + return err + } + } + return nil + } + // go over every question for _, q := range qs { // If Prompt implements controllable stdio, pass in specified stdio. @@ -302,46 +350,28 @@ func Ask(qs []*Question, response interface{}, opts ...AskOpt) error { p.WithStdio(options.Stdio) } - // grab the user input and save it - ans, err := q.Prompt.Prompt(&options.PromptConfig) - // if there was a problem - if err != nil { - return err - } - - // build up a list of validators that we have to apply to this question - validators := []Validator{} - - // make sure to include the question specific one - if q.Validate != nil { - validators = append(validators, q.Validate) - } - // add any "global" validators - for _, validator := range options.Validators { - validators = append(validators, validator) - } - - // apply every validator to thte response - for _, validator := range validators { - // wait for a valid response - for invalid := validator(ans); invalid != nil; invalid = validator(ans) { - err := q.Prompt.Error(&options.PromptConfig, invalid) - // if there was a problem - if err != nil { - return err - } - - // ask for more input - if promptAgainer, ok := q.Prompt.(PromptAgainer); ok { - ans, err = promptAgainer.PromptAgain(&options.PromptConfig, ans, invalid) - } else { - ans, err = q.Prompt.Prompt(&options.PromptConfig) - } - // if there was a problem - if err != nil { + var ans interface{} + var validationErr error + // prompt and validation loop + for { + if validationErr != nil { + if err := q.Prompt.Error(&options.PromptConfig, validationErr); err != nil { return err } } + var err error + if promptAgainer, ok := q.Prompt.(PromptAgainer); ok && validationErr != nil { + ans, err = promptAgainer.PromptAgain(&options.PromptConfig, ans, validationErr) + } else { + ans, err = q.Prompt.Prompt(&options.PromptConfig) + } + if err != nil { + return err + } + validationErr = validate(q, ans) + if validationErr == nil { + break + } } if q.Transform != nil { @@ -354,21 +384,14 @@ func Ask(qs []*Question, response interface{}, opts ...AskOpt) error { } // tell the prompt to cleanup with the validated value - q.Prompt.Cleanup(&options.PromptConfig, ans) - - // if something went wrong - if err != nil { - // stop listening + if err := q.Prompt.Cleanup(&options.PromptConfig, ans); err != nil { return err } // add it to the map - err = core.WriteAnswer(response, q.Name, ans) - // if something went wrong - if err != nil { + if err := core.WriteAnswer(response, q.Name, ans); err != nil { return err } - } // return the response @@ -411,3 +434,41 @@ func paginate(pageSize int, choices []core.OptionAnswer, sel int) ([]core.Option // return the subset we care about and the index return choices[start:end], cursor } + +type IterableOpts interface { + IterateOption(int, core.OptionAnswer) interface{} +} + +func computeCursorOffset(tmpl string, data IterableOpts, opts []core.OptionAnswer, idx, tWidth int) int { + tmpls, err := core.GetTemplatePair(tmpl) + if err != nil { + return 0 + } + + t := tmpls[0] + + renderOpt := func(ix int, opt core.OptionAnswer) string { + var buf bytes.Buffer + _ = t.ExecuteTemplate(&buf, "option", data.IterateOption(ix, opt)) + return buf.String() + } + + offset := len(opts) - idx + + for i, o := range opts { + if i < idx { + continue + } + renderedOpt := renderOpt(i, o) + valWidth := utf8.RuneCount([]byte(renderedOpt)) + if valWidth > tWidth { + splitCount := valWidth / tWidth + if valWidth%tWidth == 0 { + splitCount -= 1 + } + offset += splitCount + } + } + + return offset +} diff --git a/vendor/github.com/AlecAivazis/survey/v2/terminal/cursor.go b/vendor/github.com/AlecAivazis/survey/v2/terminal/cursor.go index 1ac74fd6f5..75117e0806 100644 --- a/vendor/github.com/AlecAivazis/survey/v2/terminal/cursor.go +++ b/vendor/github.com/AlecAivazis/survey/v2/terminal/cursor.go @@ -1,3 +1,4 @@ +//go:build !windows // +build !windows package terminal @@ -21,81 +22,99 @@ type Cursor struct { } // Up moves the cursor n cells to up. -func (c *Cursor) Up(n int) { - fmt.Fprintf(c.Out, "\x1b[%dA", n) +func (c *Cursor) Up(n int) error { + _, err := fmt.Fprintf(c.Out, "\x1b[%dA", n) + return err } // Down moves the cursor n cells to down. -func (c *Cursor) Down(n int) { - fmt.Fprintf(c.Out, "\x1b[%dB", n) +func (c *Cursor) Down(n int) error { + _, err := fmt.Fprintf(c.Out, "\x1b[%dB", n) + return err } // Forward moves the cursor n cells to right. -func (c *Cursor) Forward(n int) { - fmt.Fprintf(c.Out, "\x1b[%dC", n) +func (c *Cursor) Forward(n int) error { + _, err := fmt.Fprintf(c.Out, "\x1b[%dC", n) + return err } // Back moves the cursor n cells to left. -func (c *Cursor) Back(n int) { - fmt.Fprintf(c.Out, "\x1b[%dD", n) +func (c *Cursor) Back(n int) error { + _, err := fmt.Fprintf(c.Out, "\x1b[%dD", n) + return err } // NextLine moves cursor to beginning of the line n lines down. -func (c *Cursor) NextLine(n int) { - c.Down(1) - c.HorizontalAbsolute(0) +func (c *Cursor) NextLine(n int) error { + if err := c.Down(1); err != nil { + return err + } + return c.HorizontalAbsolute(0) } // PreviousLine moves cursor to beginning of the line n lines up. -func (c *Cursor) PreviousLine(n int) { - c.Up(1) - c.HorizontalAbsolute(0) +func (c *Cursor) PreviousLine(n int) error { + if err := c.Up(1); err != nil { + return err + } + return c.HorizontalAbsolute(0) } // HorizontalAbsolute moves cursor horizontally to x. -func (c *Cursor) HorizontalAbsolute(x int) { - fmt.Fprintf(c.Out, "\x1b[%dG", x) +func (c *Cursor) HorizontalAbsolute(x int) error { + _, err := fmt.Fprintf(c.Out, "\x1b[%dG", x) + return err } // Show shows the cursor. -func (c *Cursor) Show() { - fmt.Fprint(c.Out, "\x1b[?25h") +func (c *Cursor) Show() error { + _, err := fmt.Fprint(c.Out, "\x1b[?25h") + return err } // Hide hide the cursor. -func (c *Cursor) Hide() { - fmt.Fprint(c.Out, "\x1b[?25l") +func (c *Cursor) Hide() error { + _, err := fmt.Fprint(c.Out, "\x1b[?25l") + return err } -// Move moves the cursor to a specific x,y location. -func (c *Cursor) Move(x int, y int) { - fmt.Fprintf(c.Out, "\x1b[%d;%df", x, y) +// move moves the cursor to a specific x,y location. +func (c *Cursor) move(x int, y int) error { + _, err := fmt.Fprintf(c.Out, "\x1b[%d;%df", x, y) + return err } // Save saves the current position -func (c *Cursor) Save() { - fmt.Fprint(c.Out, "\x1b7") +func (c *Cursor) Save() error { + _, err := fmt.Fprint(c.Out, "\x1b7") + return err } // Restore restores the saved position of the cursor -func (c *Cursor) Restore() { - fmt.Fprint(c.Out, "\x1b8") +func (c *Cursor) Restore() error { + _, err := fmt.Fprint(c.Out, "\x1b8") + return err } // for comparability purposes between windows // in unix we need to print out a new line on some terminals -func (c *Cursor) MoveNextLine(cur *Coord, terminalSize *Coord) { +func (c *Cursor) MoveNextLine(cur *Coord, terminalSize *Coord) error { if cur.Y == terminalSize.Y { - fmt.Fprintln(c.Out) + if _, err := fmt.Fprintln(c.Out); err != nil { + return err + } } - c.NextLine(1) + return c.NextLine(1) } // Location returns the current location of the cursor in the terminal func (c *Cursor) Location(buf *bytes.Buffer) (*Coord, error) { // ANSI escape sequence for DSR - Device Status Report // https://en.wikipedia.org/wiki/ANSI_escape_code#CSI_sequences - fmt.Fprint(c.Out, "\x1b[6n") + if _, err := fmt.Fprint(c.Out, "\x1b[6n"); err != nil { + return nil, err + } // There may be input in Stdin prior to CursorLocation so make sure we don't // drop those bytes. @@ -176,7 +195,7 @@ func (c *Cursor) Size(buf *bytes.Buffer) (*Coord, error) { defer c.Restore() // move the cursor to the very bottom of the terminal - c.Move(999, 999) + c.move(999, 999) // ask for the current location bottom, err := c.Location(buf) diff --git a/vendor/github.com/AlecAivazis/survey/v2/terminal/cursor_windows.go b/vendor/github.com/AlecAivazis/survey/v2/terminal/cursor_windows.go index e24440e7c5..c264591995 100644 --- a/vendor/github.com/AlecAivazis/survey/v2/terminal/cursor_windows.go +++ b/vendor/github.com/AlecAivazis/survey/v2/terminal/cursor_windows.go @@ -16,31 +16,37 @@ type Cursor struct { Out FileWriter } -func (c *Cursor) Up(n int) { - c.cursorMove(0, n) +func (c *Cursor) Up(n int) error { + return c.cursorMove(0, n) } -func (c *Cursor) Down(n int) { - c.cursorMove(0, -1*n) +func (c *Cursor) Down(n int) error { + return c.cursorMove(0, -1*n) } -func (c *Cursor) Forward(n int) { - c.cursorMove(n, 0) +func (c *Cursor) Forward(n int) error { + return c.cursorMove(n, 0) } -func (c *Cursor) Back(n int) { - c.cursorMove(-1*n, 0) +func (c *Cursor) Back(n int) error { + return c.cursorMove(-1*n, 0) } // save the cursor location -func (c *Cursor) Save() { - cursorLoc, _ = c.Location(nil) +func (c *Cursor) Save() error { + loc, err := c.Location(nil) + if err != nil { + return err + } + cursorLoc = *loc + return nil } -func (c *Cursor) Restore() { +func (c *Cursor) Restore() error { handle := syscall.Handle(c.Out.Fd()) // restore it to the original position - procSetConsoleCursorPosition.Call(uintptr(handle), uintptr(*(*int32)(unsafe.Pointer(&cursorLoc)))) + _, _, err := procSetConsoleCursorPosition.Call(uintptr(handle), uintptr(*(*int32)(unsafe.Pointer(&cursorLoc)))) + return normalizeError(err) } func (cur Coord) CursorIsAtLineEnd(size *Coord) bool { @@ -51,40 +57,49 @@ func (cur Coord) CursorIsAtLineBegin() bool { return cur.X == 0 } -func (c *Cursor) cursorMove(x int, y int) { +func (c *Cursor) cursorMove(x int, y int) error { handle := syscall.Handle(c.Out.Fd()) var csbi consoleScreenBufferInfo - procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) + if _, _, err := procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))); normalizeError(err) != nil { + return err + } var cursor Coord cursor.X = csbi.cursorPosition.X + Short(x) cursor.Y = csbi.cursorPosition.Y + Short(y) - procSetConsoleCursorPosition.Call(uintptr(handle), uintptr(*(*int32)(unsafe.Pointer(&cursor)))) + _, _, err := procSetConsoleCursorPosition.Call(uintptr(handle), uintptr(*(*int32)(unsafe.Pointer(&cursor)))) + return normalizeError(err) } -func (c *Cursor) NextLine(n int) { - c.Up(n) - c.HorizontalAbsolute(0) +func (c *Cursor) NextLine(n int) error { + if err := c.Up(n); err != nil { + return err + } + return c.HorizontalAbsolute(0) } -func (c *Cursor) PreviousLine(n int) { - c.Down(n) - c.HorizontalAbsolute(0) +func (c *Cursor) PreviousLine(n int) error { + if err := c.Down(n); err != nil { + return err + } + return c.HorizontalAbsolute(0) } // for comparability purposes between windows // in windows we don't have to print out a new line -func (c *Cursor) MoveNextLine(cur Coord, terminalSize *Coord) { - c.NextLine(1) +func (c *Cursor) MoveNextLine(cur *Coord, terminalSize *Coord) error { + return c.NextLine(1) } -func (c *Cursor) HorizontalAbsolute(x int) { +func (c *Cursor) HorizontalAbsolute(x int) error { handle := syscall.Handle(c.Out.Fd()) var csbi consoleScreenBufferInfo - procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) + if _, _, err := procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))); normalizeError(err) != nil { + return err + } var cursor Coord cursor.X = Short(x) @@ -94,43 +109,54 @@ func (c *Cursor) HorizontalAbsolute(x int) { cursor.X = csbi.size.X } - procSetConsoleCursorPosition.Call(uintptr(handle), uintptr(*(*int32)(unsafe.Pointer(&cursor)))) + _, _, err := procSetConsoleCursorPosition.Call(uintptr(handle), uintptr(*(*int32)(unsafe.Pointer(&cursor)))) + return normalizeError(err) } -func (c *Cursor) Show() { +func (c *Cursor) Show() error { handle := syscall.Handle(c.Out.Fd()) var cci consoleCursorInfo - procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&cci))) + if _, _, err := procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&cci))); normalizeError(err) != nil { + return err + } cci.visible = 1 - procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&cci))) + _, _, err := procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&cci))) + return normalizeError(err) } -func (c *Cursor) Hide() { +func (c *Cursor) Hide() error { handle := syscall.Handle(c.Out.Fd()) var cci consoleCursorInfo - procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&cci))) + if _, _, err := procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&cci))); normalizeError(err) != nil { + return err + } cci.visible = 0 - procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&cci))) + _, _, err := procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&cci))) + return normalizeError(err) } -func (c *Cursor) Location(buf *bytes.Buffer) (Coord, error) { +func (c *Cursor) Location(buf *bytes.Buffer) (*Coord, error) { handle := syscall.Handle(c.Out.Fd()) var csbi consoleScreenBufferInfo - procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) + if _, _, err := procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))); normalizeError(err) != nil { + return nil, err + } - return csbi.cursorPosition, nil + return &csbi.cursorPosition, nil } func (c *Cursor) Size(buf *bytes.Buffer) (*Coord, error) { handle := syscall.Handle(c.Out.Fd()) var csbi consoleScreenBufferInfo - procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) + if _, _, err := procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))); normalizeError(err) != nil { + return nil, err + } // windows' coordinate system begins at (0, 0) csbi.size.X-- csbi.size.Y-- diff --git a/vendor/github.com/AlecAivazis/survey/v2/terminal/display_posix.go b/vendor/github.com/AlecAivazis/survey/v2/terminal/display_posix.go index 838dd6646e..fbd1b7947b 100644 --- a/vendor/github.com/AlecAivazis/survey/v2/terminal/display_posix.go +++ b/vendor/github.com/AlecAivazis/survey/v2/terminal/display_posix.go @@ -1,3 +1,4 @@ +//go:build !windows // +build !windows package terminal @@ -6,6 +7,7 @@ import ( "fmt" ) -func EraseLine(out FileWriter, mode EraseLineMode) { - fmt.Fprintf(out, "\x1b[%dK", mode) +func EraseLine(out FileWriter, mode EraseLineMode) error { + _, err := fmt.Fprintf(out, "\x1b[%dK", mode) + return err } diff --git a/vendor/github.com/AlecAivazis/survey/v2/terminal/display_windows.go b/vendor/github.com/AlecAivazis/survey/v2/terminal/display_windows.go index 0adc1ded38..fc9db9f74d 100644 --- a/vendor/github.com/AlecAivazis/survey/v2/terminal/display_windows.go +++ b/vendor/github.com/AlecAivazis/survey/v2/terminal/display_windows.go @@ -5,11 +5,13 @@ import ( "unsafe" ) -func EraseLine(out FileWriter, mode EraseLineMode) { +func EraseLine(out FileWriter, mode EraseLineMode) error { handle := syscall.Handle(out.Fd()) var csbi consoleScreenBufferInfo - procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) + if _, _, err := procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))); normalizeError(err) != nil { + return err + } var w uint32 var x Short @@ -23,5 +25,7 @@ func EraseLine(out FileWriter, mode EraseLineMode) { cursor.X = 0 x = csbi.size.X } - procFillConsoleOutputCharacter.Call(uintptr(handle), uintptr(' '), uintptr(x), uintptr(*(*int32)(unsafe.Pointer(&cursor))), uintptr(unsafe.Pointer(&w))) + + _, _, err := procFillConsoleOutputCharacter.Call(uintptr(handle), uintptr(' '), uintptr(x), uintptr(*(*int32)(unsafe.Pointer(&cursor))), uintptr(unsafe.Pointer(&w))) + return normalizeError(err) } diff --git a/vendor/github.com/AlecAivazis/survey/v2/terminal/error.go b/vendor/github.com/AlecAivazis/survey/v2/terminal/error.go index 710c361406..55eb66540c 100644 --- a/vendor/github.com/AlecAivazis/survey/v2/terminal/error.go +++ b/vendor/github.com/AlecAivazis/survey/v2/terminal/error.go @@ -5,5 +5,6 @@ import ( ) var ( + //lint:ignore ST1012 keeping old name for backwards compatibility InterruptErr = errors.New("interrupt") ) diff --git a/vendor/github.com/AlecAivazis/survey/v2/terminal/output.go b/vendor/github.com/AlecAivazis/survey/v2/terminal/output.go index 6fe11c089f..29102420c2 100644 --- a/vendor/github.com/AlecAivazis/survey/v2/terminal/output.go +++ b/vendor/github.com/AlecAivazis/survey/v2/terminal/output.go @@ -1,3 +1,4 @@ +//go:build !windows // +build !windows package terminal diff --git a/vendor/github.com/AlecAivazis/survey/v2/terminal/output_windows.go b/vendor/github.com/AlecAivazis/survey/v2/terminal/output_windows.go index 6622690f32..eaf5c4341f 100644 --- a/vendor/github.com/AlecAivazis/survey/v2/terminal/output_windows.go +++ b/vendor/github.com/AlecAivazis/survey/v2/terminal/output_windows.go @@ -12,18 +12,6 @@ import ( "github.com/mattn/go-isatty" ) -var ( - cursorFunctions = map[rune]func(c *Cursor) func(int){ - 'A': func(c *Cursor) func(int) { return c.Up }, - 'B': func(c *Cursor) func(int) { return c.Down }, - 'C': func(c *Cursor) func(int) { return c.Forward }, - 'D': func(c *Cursor) func(int) { return c.Back }, - 'E': func(c *Cursor) func(int) { return c.NextLine }, - 'F': func(c *Cursor) func(int) { return c.PreviousLine }, - 'G': func(c *Cursor) func(int) { return c.HorizontalAbsolute }, - } -) - const ( foregroundBlue = 0x1 foregroundGreen = 0x2 @@ -67,9 +55,14 @@ func (w *Writer) Write(data []byte) (n int, err error) { r := bytes.NewReader(data) for { - ch, size, err := r.ReadRune() + var ch rune + var size int + ch, size, err = r.ReadRune() if err != nil { - break + if err == io.EOF { + err = nil + } + return } n += size @@ -78,22 +71,29 @@ func (w *Writer) Write(data []byte) (n int, err error) { size, err = w.handleEscape(r) n += size if err != nil { - break + return } default: - fmt.Fprint(w.out, string(ch)) + _, err = fmt.Fprint(w.out, string(ch)) + if err != nil { + return + } } } - return } func (w *Writer) handleEscape(r *bytes.Reader) (n int, err error) { buf := make([]byte, 0, 10) buf = append(buf, "\x1b"...) + var ch rune + var size int // Check '[' continues after \x1b - ch, size, err := r.ReadRune() + ch, size, err = r.ReadRune() if err != nil { + if err == io.EOF { + err = nil + } fmt.Fprint(w.out, string(buf)) return } @@ -109,6 +109,9 @@ func (w *Writer) handleEscape(r *bytes.Reader) (n int, err error) { for { ch, size, err = r.ReadRune() if err != nil { + if err == io.EOF { + err = nil + } fmt.Fprint(w.out, string(buf)) return } @@ -120,47 +123,62 @@ func (w *Writer) handleEscape(r *bytes.Reader) (n int, err error) { argBuf = append(argBuf, string(ch)...) } - w.applyEscapeCode(buf, string(argBuf), code) + err = w.applyEscapeCode(buf, string(argBuf), code) return } -func (w *Writer) applyEscapeCode(buf []byte, arg string, code rune) { +func (w *Writer) applyEscapeCode(buf []byte, arg string, code rune) error { c := &Cursor{Out: w.out} switch arg + string(code) { case "?25h": - c.Show() - return + return c.Show() case "?25l": - c.Hide() - return + return c.Hide() } - if f, ok := cursorFunctions[code]; ok { + if code >= 'A' && code <= 'G' { if n, err := strconv.Atoi(arg); err == nil { - f(c)(n) - return + switch code { + case 'A': + return c.Up(n) + case 'B': + return c.Down(n) + case 'C': + return c.Forward(n) + case 'D': + return c.Back(n) + case 'E': + return c.NextLine(n) + case 'F': + return c.PreviousLine(n) + case 'G': + return c.HorizontalAbsolute(n) + } } } switch code { case 'm': - w.applySelectGraphicRendition(arg) + return w.applySelectGraphicRendition(arg) default: buf = append(buf, string(code)...) - fmt.Fprint(w.out, string(buf)) + _, err := fmt.Fprint(w.out, string(buf)) + return err } } // Original implementation: https://github.com/mattn/go-colorable -func (w *Writer) applySelectGraphicRendition(arg string) { +func (w *Writer) applySelectGraphicRendition(arg string) error { if arg == "" { - procSetConsoleTextAttribute.Call(uintptr(w.handle), uintptr(w.orgAttr)) - return + _, _, err := procSetConsoleTextAttribute.Call(uintptr(w.handle), uintptr(w.orgAttr)) + return normalizeError(err) } var csbi consoleScreenBufferInfo - procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) + if _, _, err := procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))); normalizeError(err) != nil { + return err + } attr := csbi.attributes for _, param := range strings.Split(arg, ";") { @@ -223,5 +241,13 @@ func (w *Writer) applySelectGraphicRendition(arg string) { } } - procSetConsoleTextAttribute.Call(uintptr(w.handle), uintptr(attr)) + _, _, err := procSetConsoleTextAttribute.Call(uintptr(w.handle), uintptr(attr)) + return normalizeError(err) +} + +func normalizeError(err error) error { + if syserr, ok := err.(syscall.Errno); ok && syserr == 0 { + return nil + } + return err } diff --git a/vendor/github.com/AlecAivazis/survey/v2/terminal/runereader.go b/vendor/github.com/AlecAivazis/survey/v2/terminal/runereader.go index 94c915c5de..998e415e57 100644 --- a/vendor/github.com/AlecAivazis/survey/v2/terminal/runereader.go +++ b/vendor/github.com/AlecAivazis/survey/v2/terminal/runereader.go @@ -8,9 +8,8 @@ import ( ) type RuneReader struct { - stdio Stdio - cursor *Cursor - state runeReaderState + stdio Stdio + state runeReaderState } func NewRuneReader(stdio Stdio) *RuneReader { @@ -20,15 +19,16 @@ func NewRuneReader(stdio Stdio) *RuneReader { } } -func (rr *RuneReader) printChar(char rune, mask rune) { +func (rr *RuneReader) printChar(char rune, mask rune) error { // if we don't need to mask the input if mask == 0 { // just print the character the user pressed - fmt.Fprintf(rr.stdio.Out, "%c", char) - } else { - // otherwise print the mask we were given - fmt.Fprintf(rr.stdio.Out, "%c", mask) + _, err := fmt.Fprintf(rr.stdio.Out, "%c", char) + return err } + // otherwise print the mask we were given + _, err := fmt.Fprintf(rr.stdio.Out, "%c", mask) + return err } type OnRuneFn func(rune, []rune) ([]rune, bool, error) @@ -80,7 +80,9 @@ func (rr *RuneReader) ReadLineWithDefault(mask rune, d []rune, onRunes ...OnRune if len(d) > 0 { index = len(d) - fmt.Fprint(rr.stdio.Out, string(d)) + if _, err := fmt.Fprint(rr.stdio.Out, string(d)); err != nil { + return d, err + } line = d for range d { increment() @@ -121,7 +123,9 @@ func (rr *RuneReader) ReadLineWithDefault(mask rune, d []rune, onRunes ...OnRune // if the user interrupts (ie with ctrl+c) if r == KeyInterrupt { // go to the beginning of the next line - fmt.Fprint(rr.stdio.Out, "\r\n") + if _, err := fmt.Fprint(rr.stdio.Out, "\r\n"); err != nil { + return line, err + } // we're done processing the input, and treat interrupt like an error return line, InterruptErr @@ -168,8 +172,9 @@ func (rr *RuneReader) ReadLineWithDefault(mask rune, d []rune, onRunes ...OnRune //Erase symbols which are left over from older print EraseLine(rr.stdio.Out, ERASE_LINE_END) // print characters to the new line appropriately - rr.printChar(char, mask) - + if err := rr.printChar(char, mask); err != nil { + return line, err + } } // erase what's left over from last print if cursorCurrent.Y < terminalSize.Y { @@ -191,7 +196,7 @@ func (rr *RuneReader) ReadLineWithDefault(mask rune, d []rune, onRunes ...OnRune decrement() } else { // otherwise the user pressed backspace while at the beginning of the line - soundBell(rr.stdio.Out) + _ = soundBell(rr.stdio.Out) } // we're done processing this key @@ -216,7 +221,7 @@ func (rr *RuneReader) ReadLineWithDefault(mask rune, d []rune, onRunes ...OnRune } else { // otherwise we are at the beginning of where we started reading lines // sound the bell - soundBell(rr.stdio.Out) + _ = soundBell(rr.stdio.Out) } // we're done processing this key press @@ -239,7 +244,7 @@ func (rr *RuneReader) ReadLineWithDefault(mask rune, d []rune, onRunes ...OnRune } else { // otherwise we are at the end of the word and can't go past // sound the bell - soundBell(rr.stdio.Out) + _ = soundBell(rr.stdio.Out) } // we're done processing this key press @@ -288,7 +293,9 @@ func (rr *RuneReader) ReadLineWithDefault(mask rune, d []rune, onRunes ...OnRune for _, char := range line[index:] { EraseLine(rr.stdio.Out, ERASE_LINE_END) // print out the character - rr.printChar(char, mask) + if err := rr.printChar(char, mask); err != nil { + return line, err + } } // erase what's left on last line if cursorCurrent.Y < terminalSize.Y { @@ -320,7 +327,9 @@ func (rr *RuneReader) ReadLineWithDefault(mask rune, d []rune, onRunes ...OnRune index++ increment() // print out the character - rr.printChar(r, mask) + if err := rr.printChar(r, mask); err != nil { + return line, err + } } else { // we are in the middle of the word so we need to insert the character the user pressed line = append(line[:index], append([]rune{r}, line[index:]...)...) @@ -334,13 +343,17 @@ func (rr *RuneReader) ReadLineWithDefault(mask rune, d []rune, onRunes ...OnRune for _, char := range line[index:] { EraseLine(rr.stdio.Out, ERASE_LINE_END) // print out the character - rr.printChar(char, mask) + if err := rr.printChar(char, mask); err != nil { + return line, err + } increment() } // if we are at the last line, we want to visually insert a new line and append to it. if cursorCurrent.CursorIsAtLineEnd(terminalSize) && cursorCurrent.Y == terminalSize.Y { // add a new line to the terminal - fmt.Fprintln(rr.stdio.Out) + if _, err := fmt.Fprintln(rr.stdio.Out); err != nil { + return line, err + } // restore the position of the cursor horizontally cursor.Restore() // restore the position of the cursor vertically @@ -364,10 +377,41 @@ func (rr *RuneReader) ReadLineWithDefault(mask rune, d []rune, onRunes ...OnRune } } +// runeWidth returns the number of columns spanned by a rune when printed to the terminal func runeWidth(r rune) int { switch width.LookupRune(r).Kind() { case width.EastAsianWide, width.EastAsianFullwidth: return 2 } + + if !unicode.IsPrint(r) { + return 0 + } return 1 } + +// isAnsiMarker returns if a rune denotes the start of an ANSI sequence +func isAnsiMarker(r rune) bool { + return r == '\x1B' +} + +// isAnsiTerminator returns if a rune denotes the end of an ANSI sequence +func isAnsiTerminator(r rune) bool { + return (r >= 0x40 && r <= 0x5a) || (r == 0x5e) || (r >= 0x60 && r <= 0x7e) +} + +// StringWidth returns the visible width of a string when printed to the terminal +func StringWidth(str string) int { + w := 0 + ansi := false + + for _, r := range str { + // increase width only when outside of ANSI escape sequences + if ansi || isAnsiMarker(r) { + ansi = !isAnsiTerminator(r) + } else { + w += runeWidth(r) + } + } + return w +} diff --git a/vendor/github.com/AlecAivazis/survey/v2/terminal/runereader_bsd.go b/vendor/github.com/AlecAivazis/survey/v2/terminal/runereader_bsd.go index 6ea340923a..57f1014257 100644 --- a/vendor/github.com/AlecAivazis/survey/v2/terminal/runereader_bsd.go +++ b/vendor/github.com/AlecAivazis/survey/v2/terminal/runereader_bsd.go @@ -3,6 +3,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build darwin || dragonfly || freebsd || netbsd || openbsd // +build darwin dragonfly freebsd netbsd openbsd package terminal diff --git a/vendor/github.com/AlecAivazis/survey/v2/terminal/runereader_linux.go b/vendor/github.com/AlecAivazis/survey/v2/terminal/runereader_linux.go index 6dd60ea697..dc7ec670ce 100644 --- a/vendor/github.com/AlecAivazis/survey/v2/terminal/runereader_linux.go +++ b/vendor/github.com/AlecAivazis/survey/v2/terminal/runereader_linux.go @@ -2,6 +2,7 @@ // Copyright 2013 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build linux && !ppc64le // +build linux,!ppc64le package terminal diff --git a/vendor/github.com/AlecAivazis/survey/v2/terminal/runereader_posix.go b/vendor/github.com/AlecAivazis/survey/v2/terminal/runereader_posix.go index a7e3842505..563a08115a 100644 --- a/vendor/github.com/AlecAivazis/survey/v2/terminal/runereader_posix.go +++ b/vendor/github.com/AlecAivazis/survey/v2/terminal/runereader_posix.go @@ -1,3 +1,4 @@ +//go:build !windows // +build !windows // The terminal mode manipulation code is derived heavily from: @@ -16,6 +17,11 @@ import ( "unsafe" ) +const ( + normalKeypad = '[' + applicationKeypad = 'O' +) + type runeReaderState struct { term syscall.Termios reader *bufio.Reader @@ -45,6 +51,11 @@ func (rr *RuneReader) SetTermMode() error { newState := rr.state.term newState.Lflag &^= syscall.ECHO | syscall.ECHONL | syscall.ICANON | syscall.ISIG + // Because we are clearing canonical mode, we need to ensure VMIN & VTIME are + // set to the values we expect. This combination puts things in standard + // "blocking read" mode (see termios(3)). + newState.Cc[syscall.VMIN] = 1 + newState.Cc[syscall.VTIME] = 0 if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(rr.stdio.In.Fd()), ioctlWriteTermios, uintptr(unsafe.Pointer(&newState)), 0, 0, 0); err != 0 { return err @@ -60,52 +71,62 @@ func (rr *RuneReader) RestoreTermMode() error { return nil } +// ReadRune Parse escape sequences such as ESC [ A for arrow keys. +// See https://vt100.net/docs/vt102-ug/appendixc.html func (rr *RuneReader) ReadRune() (rune, int, error) { r, size, err := rr.state.reader.ReadRune() if err != nil { return r, size, err } - // parse ^[ sequences to look for arrow keys - if r == '\033' { - if rr.state.reader.Buffered() == 0 { - // no more characters so must be `Esc` key - return KeyEscape, 1, nil - } - r, size, err = rr.state.reader.ReadRune() - if err != nil { - return r, size, err - } - if r != '[' { - return r, size, fmt.Errorf("Unexpected Escape Sequence: %q", []rune{'\033', r}) - } - r, size, err = rr.state.reader.ReadRune() - if err != nil { - return r, size, err - } - switch r { - case 'D': - return KeyArrowLeft, 1, nil - case 'C': - return KeyArrowRight, 1, nil - case 'A': - return KeyArrowUp, 1, nil - case 'B': - return KeyArrowDown, 1, nil - case 'H': // Home button - return SpecialKeyHome, 1, nil - case 'F': // End button - return SpecialKeyEnd, 1, nil - case '3': // Delete Button + if r != KeyEscape { + return r, size, err + } + + if rr.state.reader.Buffered() == 0 { + // no more characters so must be `Esc` key + return KeyEscape, 1, nil + } + + r, size, err = rr.state.reader.ReadRune() + if err != nil { + return r, size, err + } + + // ESC O ... or ESC [ ...? + if r != normalKeypad && r != applicationKeypad { + return r, size, fmt.Errorf("unexpected escape sequence from terminal: %q", []rune{KeyEscape, r}) + } + + keypad := r + + r, size, err = rr.state.reader.ReadRune() + if err != nil { + return r, size, err + } + + switch r { + case 'A': // ESC [ A or ESC O A + return KeyArrowUp, 1, nil + case 'B': // ESC [ B or ESC O B + return KeyArrowDown, 1, nil + case 'C': // ESC [ C or ESC O C + return KeyArrowRight, 1, nil + case 'D': // ESC [ D or ESC O D + return KeyArrowLeft, 1, nil + case 'F': // ESC [ F or ESC O F + return SpecialKeyEnd, 1, nil + case 'H': // ESC [ H or ESC O H + return SpecialKeyHome, 1, nil + case '3': // ESC [ 3 + if keypad == normalKeypad { // discard the following '~' key from buffer - rr.state.reader.Discard(1) + _, _ = rr.state.reader.Discard(1) return SpecialKeyDelete, 1, nil - default: - // discard the following '~' key from buffer - rr.state.reader.Discard(1) - return IgnoreKey, 1, nil } - return r, size, fmt.Errorf("Unknown Escape Sequence: %q", []rune{'\033', '[', r}) } - return r, size, err + + // discard the following '~' key from buffer + _, _ = rr.state.reader.Discard(1) + return IgnoreKey, 1, nil } diff --git a/vendor/github.com/AlecAivazis/survey/v2/terminal/runereader_ppc64le.go b/vendor/github.com/AlecAivazis/survey/v2/terminal/runereader_ppc64le.go index ae4eb09737..450f796c6a 100644 --- a/vendor/github.com/AlecAivazis/survey/v2/terminal/runereader_ppc64le.go +++ b/vendor/github.com/AlecAivazis/survey/v2/terminal/runereader_ppc64le.go @@ -1,3 +1,4 @@ +//go:build ppc64le && linux // +build ppc64le,linux package terminal diff --git a/vendor/github.com/AlecAivazis/survey/v2/terminal/sequences.go b/vendor/github.com/AlecAivazis/survey/v2/terminal/sequences.go index 6d9e87755b..5f61e2b65e 100644 --- a/vendor/github.com/AlecAivazis/survey/v2/terminal/sequences.go +++ b/vendor/github.com/AlecAivazis/survey/v2/terminal/sequences.go @@ -26,6 +26,7 @@ const ( KeyTab = '\t' ) -func soundBell(out io.Writer) { - fmt.Fprint(out, "\a") +func soundBell(out io.Writer) error { + _, err := fmt.Fprint(out, "\a") + return err } diff --git a/vendor/github.com/AlecAivazis/survey/v2/transform.go b/vendor/github.com/AlecAivazis/survey/v2/transform.go index 58d5193b03..a78ada3925 100644 --- a/vendor/github.com/AlecAivazis/survey/v2/transform.go +++ b/vendor/github.com/AlecAivazis/survey/v2/transform.go @@ -3,6 +3,9 @@ package survey import ( "reflect" "strings" + + "golang.org/x/text/cases" + "golang.org/x/text/language" ) // TransformString returns a `Transformer` based on the "f" @@ -62,7 +65,7 @@ func ToLower(ans interface{}) interface{} { // return a nil value, meaning that the above answer // will not be affected by this call at all. func Title(ans interface{}) interface{} { - transformer := TransformString(strings.Title) + transformer := TransformString(cases.Title(language.English).String) return transformer(ans) } diff --git a/vendor/github.com/AlecAivazis/survey/v2/validate.go b/vendor/github.com/AlecAivazis/survey/v2/validate.go index 462dc5e75c..7f03b23ac7 100644 --- a/vendor/github.com/AlecAivazis/survey/v2/validate.go +++ b/vendor/github.com/AlecAivazis/survey/v2/validate.go @@ -15,6 +15,7 @@ func Required(val interface{}) error { // if the value passed in is the zero value of the appropriate type if isZero(value) && value.Kind() != reflect.Bool { + //lint:ignore ST1005 this error message should render as capitalized return errors.New("Value is required") } return nil @@ -87,7 +88,7 @@ func MinItems(numberItems int) Validator { // if the list is shorter than the given value if len(list) < numberItems { // yell loudly - return fmt.Errorf("value is too long. Min items is %v", numberItems) + return fmt.Errorf("value is too short. Min items is %v", numberItems) } } else { // otherwise we cannot convert the value into a list of answer and cannot enforce length diff --git a/vendor/github.com/sirupsen/logrus/.golangci.yml b/vendor/github.com/sirupsen/logrus/.golangci.yml index 65dc285037..792db36181 100644 --- a/vendor/github.com/sirupsen/logrus/.golangci.yml +++ b/vendor/github.com/sirupsen/logrus/.golangci.yml @@ -1,40 +1,67 @@ +version: "2" run: - # do not run on test files yet tests: false - -# all available settings of specific linters -linters-settings: - errcheck: - # report about not checking of errors in type assetions: `a := b.(MyStruct)`; - # default is false: such cases aren't reported by default. - check-type-assertions: false - - # report about assignment of errors to blank identifier: `num, _ := strconv.Atoi(numStr)`; - # default is false: such cases aren't reported by default. - check-blank: false - - lll: - line-length: 100 - tab-width: 4 - - prealloc: - simple: false - range-loops: false - for-loops: false - - whitespace: - multi-if: false # Enforces newlines (or comments) after every multi-line if statement - multi-func: false # Enforces newlines (or comments) after every multi-line function signature - linters: enable: - - megacheck - - govet + - asasalint + - asciicheck + - bidichk + - bodyclose + - contextcheck + - durationcheck + - errchkjson + - errorlint + - exhaustive + - gocheckcompilerdirectives + - gochecksumtype + - gosec + - gosmopolitan + - loggercheck + - makezero + - musttag + - nilerr + - nilnesserr + - noctx + - protogetter + - reassign + - recvcheck + - rowserrcheck + - spancheck + - sqlclosecheck + - testifylint + - unparam + - zerologlint disable: - - maligned - prealloc - disable-all: false - presets: - - bugs - - unused - fast: false + settings: + errcheck: + check-type-assertions: false + check-blank: false + lll: + line-length: 100 + tab-width: 4 + prealloc: + simple: false + range-loops: false + for-loops: false + whitespace: + multi-if: false + multi-func: false + exclusions: + generated: lax + presets: + - comments + - common-false-positives + - legacy + - std-error-handling + paths: + - third_party$ + - builtin$ + - examples$ +formatters: + exclusions: + generated: lax + paths: + - third_party$ + - builtin$ + - examples$ diff --git a/vendor/github.com/sirupsen/logrus/CHANGELOG.md b/vendor/github.com/sirupsen/logrus/CHANGELOG.md index 7567f61289..098608ff4b 100644 --- a/vendor/github.com/sirupsen/logrus/CHANGELOG.md +++ b/vendor/github.com/sirupsen/logrus/CHANGELOG.md @@ -37,7 +37,7 @@ Features: # 1.6.0 Fixes: * end of line cleanup - * revert the entry concurrency bug fix whic leads to deadlock under some circumstances + * revert the entry concurrency bug fix which leads to deadlock under some circumstances * update dependency on go-windows-terminal-sequences to fix a crash with go 1.14 Features: @@ -129,7 +129,7 @@ This new release introduces: which is mostly useful for logger wrapper * a fix reverting the immutability of the entry given as parameter to the hooks a new configuration field of the json formatter in order to put all the fields - in a nested dictionnary + in a nested dictionary * a new SetOutput method in the Logger * a new configuration of the textformatter to configure the name of the default keys * a new configuration of the text formatter to disable the level truncation diff --git a/vendor/github.com/sirupsen/logrus/README.md b/vendor/github.com/sirupsen/logrus/README.md index d1d4a85fd7..cc5dab7eb7 100644 --- a/vendor/github.com/sirupsen/logrus/README.md +++ b/vendor/github.com/sirupsen/logrus/README.md @@ -1,4 +1,4 @@ -# Logrus :walrus: [![Build Status](https://github.com/sirupsen/logrus/workflows/CI/badge.svg)](https://github.com/sirupsen/logrus/actions?query=workflow%3ACI) [![Build Status](https://travis-ci.org/sirupsen/logrus.svg?branch=master)](https://travis-ci.org/sirupsen/logrus) [![Go Reference](https://pkg.go.dev/badge/github.com/sirupsen/logrus.svg)](https://pkg.go.dev/github.com/sirupsen/logrus) +# Logrus :walrus: [![Build Status](https://github.com/sirupsen/logrus/workflows/CI/badge.svg)](https://github.com/sirupsen/logrus/actions?query=workflow%3ACI) [![Go Reference](https://pkg.go.dev/badge/github.com/sirupsen/logrus.svg)](https://pkg.go.dev/github.com/sirupsen/logrus) Logrus is a structured logger for Go (golang), completely API compatible with the standard library logger. @@ -40,7 +40,7 @@ plain text): ![Colored](http://i.imgur.com/PY7qMwd.png) -With `log.SetFormatter(&log.JSONFormatter{})`, for easy parsing by logstash +With `logrus.SetFormatter(&logrus.JSONFormatter{})`, for easy parsing by logstash or Splunk: ```text @@ -60,9 +60,9 @@ ocean","size":10,"time":"2014-03-10 19:57:38.562264131 -0400 EDT"} "time":"2014-03-10 19:57:38.562543128 -0400 EDT"} ``` -With the default `log.SetFormatter(&log.TextFormatter{})` when a TTY is not +With the default `logrus.SetFormatter(&logrus.TextFormatter{})` when a TTY is not attached, the output is compatible with the -[logfmt](http://godoc.org/github.com/kr/logfmt) format: +[logfmt](https://pkg.go.dev/github.com/kr/logfmt) format: ```text time="2015-03-26T01:27:38-04:00" level=debug msg="Started observing beach" animal=walrus number=8 @@ -75,17 +75,18 @@ time="2015-03-26T01:27:38-04:00" level=fatal msg="The ice breaks!" err=&{0x20822 To ensure this behaviour even if a TTY is attached, set your formatter as follows: ```go - log.SetFormatter(&log.TextFormatter{ - DisableColors: true, - FullTimestamp: true, - }) +logrus.SetFormatter(&logrus.TextFormatter{ + DisableColors: true, + FullTimestamp: true, +}) ``` #### Logging Method Name If you wish to add the calling method as a field, instruct the logger via: + ```go -log.SetReportCaller(true) +logrus.SetReportCaller(true) ``` This adds the caller as 'method' like so: @@ -100,11 +101,11 @@ time="2015-03-26T01:27:38-04:00" level=fatal method=github.com/sirupsen/arcticcr Note that this does add measurable overhead - the cost will depend on the version of Go, but is between 20 and 40% in recent tests with 1.6 and 1.7. You can validate this in your environment via benchmarks: -``` + +```bash go test -bench=.*CallerTracing ``` - #### Case-sensitivity The organization's name was changed to lower-case--and this will not be changed @@ -118,12 +119,10 @@ The simplest way to use Logrus is simply the package-level exported logger: ```go package main -import ( - log "github.com/sirupsen/logrus" -) +import "github.com/sirupsen/logrus" func main() { - log.WithFields(log.Fields{ + logrus.WithFields(logrus.Fields{ "animal": "walrus", }).Info("A walrus appears") } @@ -139,6 +138,7 @@ package main import ( "os" + log "github.com/sirupsen/logrus" ) @@ -190,26 +190,27 @@ package main import ( "os" + "github.com/sirupsen/logrus" ) // Create a new instance of the logger. You can have any number of instances. -var log = logrus.New() +var logger = logrus.New() func main() { // The API for setting attributes is a little different than the package level - // exported logger. See Godoc. - log.Out = os.Stdout + // exported logger. See Godoc. + logger.Out = os.Stdout // You could set this to any `io.Writer` such as a file // file, err := os.OpenFile("logrus.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) // if err == nil { - // log.Out = file + // logger.Out = file // } else { - // log.Info("Failed to log to file, using default stderr") + // logger.Info("Failed to log to file, using default stderr") // } - log.WithFields(logrus.Fields{ + logger.WithFields(logrus.Fields{ "animal": "walrus", "size": 10, }).Info("A group of walrus emerges from the ocean") @@ -219,12 +220,12 @@ func main() { #### Fields Logrus encourages careful, structured logging through logging fields instead of -long, unparseable error messages. For example, instead of: `log.Fatalf("Failed +long, unparseable error messages. For example, instead of: `logrus.Fatalf("Failed to send event %s to topic %s with key %d")`, you should log the much more discoverable: ```go -log.WithFields(log.Fields{ +logrus.WithFields(logrus.Fields{ "event": event, "topic": topic, "key": key, @@ -245,12 +246,12 @@ seen as a hint you should add a field, however, you can still use the Often it's helpful to have fields _always_ attached to log statements in an application or parts of one. For example, you may want to always log the `request_id` and `user_ip` in the context of a request. Instead of writing -`log.WithFields(log.Fields{"request_id": request_id, "user_ip": user_ip})` on +`logger.WithFields(logrus.Fields{"request_id": request_id, "user_ip": user_ip})` on every line, you can create a `logrus.Entry` to pass around instead: ```go -requestLogger := log.WithFields(log.Fields{"request_id": request_id, "user_ip": user_ip}) -requestLogger.Info("something happened on that request") # will log request_id and user_ip +requestLogger := logger.WithFields(logrus.Fields{"request_id": request_id, "user_ip": user_ip}) +requestLogger.Info("something happened on that request") // will log request_id and user_ip requestLogger.Warn("something not great happened") ``` @@ -264,28 +265,31 @@ Logrus comes with [built-in hooks](hooks/). Add those, or your custom hook, in `init`: ```go +package main + import ( - log "github.com/sirupsen/logrus" - "gopkg.in/gemnasium/logrus-airbrake-hook.v2" // the package is named "airbrake" - logrus_syslog "github.com/sirupsen/logrus/hooks/syslog" "log/syslog" + + "github.com/sirupsen/logrus" + airbrake "gopkg.in/gemnasium/logrus-airbrake-hook.v2" + logrus_syslog "github.com/sirupsen/logrus/hooks/syslog" ) func init() { // Use the Airbrake hook to report errors that have Error severity or above to // an exception tracker. You can create custom hooks, see the Hooks section. - log.AddHook(airbrake.NewHook(123, "xyz", "production")) + logrus.AddHook(airbrake.NewHook(123, "xyz", "production")) hook, err := logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "") if err != nil { - log.Error("Unable to connect to local syslog daemon") + logrus.Error("Unable to connect to local syslog daemon") } else { - log.AddHook(hook) + logrus.AddHook(hook) } } ``` -Note: Syslog hook also support connecting to local syslog (Ex. "/dev/log" or "/var/run/syslog" or "/var/run/log"). For the detail, please check the [syslog hook README](hooks/syslog/README.md). +Note: Syslog hooks also support connecting to local syslog (Ex. "/dev/log" or "/var/run/syslog" or "/var/run/log"). For the detail, please check the [syslog hook README](hooks/syslog/README.md). A list of currently known service hooks can be found in this wiki [page](https://github.com/sirupsen/logrus/wiki/Hooks) @@ -295,15 +299,15 @@ A list of currently known service hooks can be found in this wiki [page](https:/ Logrus has seven logging levels: Trace, Debug, Info, Warning, Error, Fatal and Panic. ```go -log.Trace("Something very low level.") -log.Debug("Useful debugging information.") -log.Info("Something noteworthy happened!") -log.Warn("You should probably take a look at this.") -log.Error("Something failed but I'm not quitting.") +logrus.Trace("Something very low level.") +logrus.Debug("Useful debugging information.") +logrus.Info("Something noteworthy happened!") +logrus.Warn("You should probably take a look at this.") +logrus.Error("Something failed but I'm not quitting.") // Calls os.Exit(1) after logging -log.Fatal("Bye.") +logrus.Fatal("Bye.") // Calls panic() after logging -log.Panic("I'm bailing.") +logrus.Panic("I'm bailing.") ``` You can set the logging level on a `Logger`, then it will only log entries with @@ -311,13 +315,13 @@ that severity or anything above it: ```go // Will log anything that is info or above (warn, error, fatal, panic). Default. -log.SetLevel(log.InfoLevel) +logrus.SetLevel(logrus.InfoLevel) ``` -It may be useful to set `log.Level = logrus.DebugLevel` in a debug or verbose +It may be useful to set `logrus.Level = logrus.DebugLevel` in a debug or verbose environment if your application has that. -Note: If you want different log levels for global (`log.SetLevel(...)`) and syslog logging, please check the [syslog hook README](hooks/syslog/README.md#different-log-levels-for-local-and-remote-logging). +Note: If you want different log levels for global (`logrus.SetLevel(...)`) and syslog logging, please check the [syslog hook README](hooks/syslog/README.md#different-log-levels-for-local-and-remote-logging). #### Entries @@ -340,17 +344,17 @@ could do: ```go import ( - log "github.com/sirupsen/logrus" + "github.com/sirupsen/logrus" ) func init() { // do something here to set environment depending on an environment variable // or command-line flag if Environment == "production" { - log.SetFormatter(&log.JSONFormatter{}) + logrus.SetFormatter(&logrus.JSONFormatter{}) } else { // The TextFormatter is default, you don't actually have to do this. - log.SetFormatter(&log.TextFormatter{}) + logrus.SetFormatter(&logrus.TextFormatter{}) } } ``` @@ -372,11 +376,11 @@ The built-in logging formatters are: * When colors are enabled, levels are truncated to 4 characters by default. To disable truncation set the `DisableLevelTruncation` field to `true`. * When outputting to a TTY, it's often helpful to visually scan down a column where all the levels are the same width. Setting the `PadLevelText` field to `true` enables this behavior, by adding padding to the level text. - * All options are listed in the [generated docs](https://godoc.org/github.com/sirupsen/logrus#TextFormatter). + * All options are listed in the [generated docs](https://pkg.go.dev/github.com/sirupsen/logrus#TextFormatter). * `logrus.JSONFormatter`. Logs fields as JSON. - * All options are listed in the [generated docs](https://godoc.org/github.com/sirupsen/logrus#JSONFormatter). + * All options are listed in the [generated docs](https://pkg.go.dev/github.com/sirupsen/logrus#JSONFormatter). -Third party logging formatters: +Third-party logging formatters: * [`FluentdFormatter`](https://github.com/joonix/log). Formats entries that can be parsed by Kubernetes and Google Container Engine. * [`GELF`](https://github.com/fabienm/go-logrus-formatters). Formats entries so they comply to Graylog's [GELF 1.1 specification](http://docs.graylog.org/en/2.4/pages/gelf.html). @@ -384,7 +388,7 @@ Third party logging formatters: * [`prefixed`](https://github.com/x-cray/logrus-prefixed-formatter). Displays log entry source along with alternative layout. * [`zalgo`](https://github.com/aybabtme/logzalgo). Invoking the Power of Zalgo. * [`nested-logrus-formatter`](https://github.com/antonfisher/nested-logrus-formatter). Converts logrus fields to a nested structure. -* [`powerful-logrus-formatter`](https://github.com/zput/zxcTool). get fileName, log's line number and the latest function's name when print log; Sava log to files. +* [`powerful-logrus-formatter`](https://github.com/zput/zxcTool). get fileName, log's line number and the latest function's name when print log; Save log to files. * [`caption-json-formatter`](https://github.com/nolleh/caption_json_formatter). logrus's message json formatter with human-readable caption added. You can define your formatter by implementing the `Formatter` interface, @@ -393,10 +397,9 @@ requiring a `Format` method. `Format` takes an `*Entry`. `entry.Data` is a default ones (see Entries section above): ```go -type MyJSONFormatter struct { -} +type MyJSONFormatter struct{} -log.SetFormatter(new(MyJSONFormatter)) +logrus.SetFormatter(new(MyJSONFormatter)) func (f *MyJSONFormatter) Format(entry *Entry) ([]byte, error) { // Note this doesn't include Time, Level and Message which are available on @@ -455,17 +458,18 @@ entries. It should not be a feature of the application-level logger. #### Testing -Logrus has a built in facility for asserting the presence of log messages. This is implemented through the `test` hook and provides: +Logrus has a built-in facility for asserting the presence of log messages. This is implemented through the `test` hook and provides: * decorators for existing logger (`test.NewLocal` and `test.NewGlobal`) which basically just adds the `test` hook * a test logger (`test.NewNullLogger`) that just records log messages (and does not output any): ```go import( + "testing" + "github.com/sirupsen/logrus" "github.com/sirupsen/logrus/hooks/test" "github.com/stretchr/testify/assert" - "testing" ) func TestSomething(t*testing.T){ @@ -486,15 +490,15 @@ func TestSomething(t*testing.T){ Logrus can register one or more functions that will be called when any `fatal` level message is logged. The registered handlers will be executed before logrus performs an `os.Exit(1)`. This behavior may be helpful if callers need -to gracefully shutdown. Unlike a `panic("Something went wrong...")` call which can be intercepted with a deferred `recover` a call to `os.Exit(1)` can not be intercepted. +to gracefully shut down. Unlike a `panic("Something went wrong...")` call which can be intercepted with a deferred `recover` a call to `os.Exit(1)` can not be intercepted. -``` -... +```go +// ... handler := func() { - // gracefully shutdown something... + // gracefully shut down something... } logrus.RegisterExitHandler(handler) -... +// ... ``` #### Thread safety @@ -502,7 +506,7 @@ logrus.RegisterExitHandler(handler) By default, Logger is protected by a mutex for concurrent writes. The mutex is held when calling hooks and writing logs. If you are sure such locking is not needed, you can call logger.SetNoLock() to disable the locking. -Situation when locking is not needed includes: +Situations when locking is not needed include: * You have no hooks registered, or hooks calling is already thread-safe. diff --git a/vendor/github.com/sirupsen/logrus/appveyor.yml b/vendor/github.com/sirupsen/logrus/appveyor.yml index df9d65c3a5..e90f09ea68 100644 --- a/vendor/github.com/sirupsen/logrus/appveyor.yml +++ b/vendor/github.com/sirupsen/logrus/appveyor.yml @@ -1,14 +1,12 @@ -version: "{build}" +# Minimal stub to satisfy AppVeyor CI +version: 1.0.{build} platform: x64 -clone_folder: c:\gopath\src\github.com\sirupsen\logrus -environment: - GOPATH: c:\gopath +shallow_clone: true + branches: only: - master -install: - - set PATH=%GOPATH%\bin;c:\go\bin;%PATH% - - go version + - main + build_script: - - go get -t - - go test + - echo "No-op build to satisfy AppVeyor CI" diff --git a/vendor/github.com/sirupsen/logrus/entry.go b/vendor/github.com/sirupsen/logrus/entry.go index 71cdbbc35d..71d796d0b1 100644 --- a/vendor/github.com/sirupsen/logrus/entry.go +++ b/vendor/github.com/sirupsen/logrus/entry.go @@ -34,13 +34,15 @@ func init() { minimumCallerDepth = 1 } -// Defines the key when adding errors using WithError. +// ErrorKey defines the key when adding errors using [WithError], [Logger.WithError]. var ErrorKey = "error" -// An entry is the final or intermediate Logrus logging entry. It contains all +// Entry is the final or intermediate Logrus logging entry. It contains all // the fields passed with WithField{,s}. It's finally logged when Trace, Debug, // Info, Warn, Error, Fatal or Panic is called on it. These objects can be // reused and passed around as much as you wish to avoid field duplication. +// +//nolint:recvcheck // the methods of "Entry" use pointer receiver and non-pointer receiver. type Entry struct { Logger *Logger @@ -86,12 +88,12 @@ func (entry *Entry) Dup() *Entry { return &Entry{Logger: entry.Logger, Data: data, Time: entry.Time, Context: entry.Context, err: entry.err} } -// Returns the bytes representation of this entry from the formatter. +// Bytes returns the bytes representation of this entry from the formatter. func (entry *Entry) Bytes() ([]byte, error) { return entry.Logger.Formatter.Format(entry) } -// Returns the string representation from the reader and ultimately the +// String returns the string representation from the reader and ultimately the // formatter. func (entry *Entry) String() (string, error) { serialized, err := entry.Bytes() @@ -102,12 +104,13 @@ func (entry *Entry) String() (string, error) { return str, nil } -// Add an error as single field (using the key defined in ErrorKey) to the Entry. +// WithError adds an error as single field (using the key defined in [ErrorKey]) +// to the Entry. func (entry *Entry) WithError(err error) *Entry { return entry.WithField(ErrorKey, err) } -// Add a context to the Entry. +// WithContext adds a context to the Entry. func (entry *Entry) WithContext(ctx context.Context) *Entry { dataCopy := make(Fields, len(entry.Data)) for k, v := range entry.Data { @@ -116,12 +119,12 @@ func (entry *Entry) WithContext(ctx context.Context) *Entry { return &Entry{Logger: entry.Logger, Data: dataCopy, Time: entry.Time, err: entry.err, Context: ctx} } -// Add a single field to the Entry. +// WithField adds a single field to the Entry. func (entry *Entry) WithField(key string, value interface{}) *Entry { return entry.WithFields(Fields{key: value}) } -// Add a map of fields to the Entry. +// WithFields adds a map of fields to the Entry. func (entry *Entry) WithFields(fields Fields) *Entry { data := make(Fields, len(entry.Data)+len(fields)) for k, v := range entry.Data { @@ -150,7 +153,7 @@ func (entry *Entry) WithFields(fields Fields) *Entry { return &Entry{Logger: entry.Logger, Data: data, Time: entry.Time, err: fieldErr, Context: entry.Context} } -// Overrides the time of the Entry. +// WithTime overrides the time of the Entry. func (entry *Entry) WithTime(t time.Time) *Entry { dataCopy := make(Fields, len(entry.Data)) for k, v := range entry.Data { @@ -204,7 +207,7 @@ func getCaller() *runtime.Frame { // If the caller isn't part of this package, we're done if pkg != logrusPackage { - return &f //nolint:scopelint + return &f } } @@ -432,7 +435,7 @@ func (entry *Entry) Panicln(args ...interface{}) { entry.Logln(PanicLevel, args...) } -// Sprintlnn => Sprint no newline. This is to get the behavior of how +// sprintlnn => Sprint no newline. This is to get the behavior of how // fmt.Sprintln where spaces are always added between operands, regardless of // their type. Instead of vendoring the Sprintln implementation to spare a // string allocation, we do the simplest thing. diff --git a/vendor/github.com/sirupsen/logrus/hooks.go b/vendor/github.com/sirupsen/logrus/hooks.go index 3f151cdc39..9ab978a457 100644 --- a/vendor/github.com/sirupsen/logrus/hooks.go +++ b/vendor/github.com/sirupsen/logrus/hooks.go @@ -1,16 +1,16 @@ package logrus -// A hook to be fired when logging on the logging levels returned from -// `Levels()` on your implementation of the interface. Note that this is not +// Hook describes hooks to be fired when logging on the logging levels returned from +// [Hook.Levels] on your implementation of the interface. Note that this is not // fired in a goroutine or a channel with workers, you should handle such -// functionality yourself if your call is non-blocking and you don't wish for +// functionality yourself if your call is non-blocking, and you don't wish for // the logging calls for levels returned from `Levels()` to block. type Hook interface { Levels() []Level Fire(*Entry) error } -// Internal type for storing the hooks on a logger instance. +// LevelHooks is an internal type for storing the hooks on a logger instance. type LevelHooks map[Level][]Hook // Add a hook to an instance of logger. This is called with diff --git a/vendor/github.com/sirupsen/logrus/logger.go b/vendor/github.com/sirupsen/logrus/logger.go index 5ff0aef6d3..f5b8c439ee 100644 --- a/vendor/github.com/sirupsen/logrus/logger.go +++ b/vendor/github.com/sirupsen/logrus/logger.go @@ -72,16 +72,16 @@ func (mw *MutexWrap) Disable() { mw.disabled = true } -// Creates a new logger. Configuration should be set by changing `Formatter`, -// `Out` and `Hooks` directly on the default logger instance. You can also just +// New Creates a new logger. Configuration should be set by changing [Formatter], +// Out and Hooks directly on the default Logger instance. You can also just // instantiate your own: // -// var log = &logrus.Logger{ -// Out: os.Stderr, -// Formatter: new(logrus.TextFormatter), -// Hooks: make(logrus.LevelHooks), -// Level: logrus.DebugLevel, -// } +// var log = &logrus.Logger{ +// Out: os.Stderr, +// Formatter: new(logrus.TextFormatter), +// Hooks: make(logrus.LevelHooks), +// Level: logrus.DebugLevel, +// } // // It's recommended to make this a global instance called `log`. func New() *Logger { @@ -118,30 +118,30 @@ func (logger *Logger) WithField(key string, value interface{}) *Entry { return entry.WithField(key, value) } -// Adds a struct of fields to the log entry. All it does is call `WithField` for -// each `Field`. +// WithFields adds a struct of fields to the log entry. It calls [Entry.WithField] +// for each Field. func (logger *Logger) WithFields(fields Fields) *Entry { entry := logger.newEntry() defer logger.releaseEntry(entry) return entry.WithFields(fields) } -// Add an error as single field to the log entry. All it does is call -// `WithError` for the given `error`. +// WithError adds an error as single field to the log entry. It calls +// [Entry.WithError] for the given error. func (logger *Logger) WithError(err error) *Entry { entry := logger.newEntry() defer logger.releaseEntry(entry) return entry.WithError(err) } -// Add a context to the log entry. +// WithContext add a context to the log entry. func (logger *Logger) WithContext(ctx context.Context) *Entry { entry := logger.newEntry() defer logger.releaseEntry(entry) return entry.WithContext(ctx) } -// Overrides the time of the log entry. +// WithTime overrides the time of the log entry. func (logger *Logger) WithTime(t time.Time) *Entry { entry := logger.newEntry() defer logger.releaseEntry(entry) @@ -347,9 +347,9 @@ func (logger *Logger) Exit(code int) { logger.ExitFunc(code) } -//When file is opened with appending mode, it's safe to -//write concurrently to a file (within 4k message on Linux). -//In these cases user can choose to disable the lock. +// SetNoLock disables the lock for situations where a file is opened with +// appending mode, and safe for concurrent writes to the file (within 4k +// message on Linux). In these cases user can choose to disable the lock. func (logger *Logger) SetNoLock() { logger.mu.Disable() } diff --git a/vendor/github.com/sirupsen/logrus/logrus.go b/vendor/github.com/sirupsen/logrus/logrus.go index 2f16224cb9..37fc4fef85 100644 --- a/vendor/github.com/sirupsen/logrus/logrus.go +++ b/vendor/github.com/sirupsen/logrus/logrus.go @@ -6,13 +6,15 @@ import ( "strings" ) -// Fields type, used to pass to `WithFields`. +// Fields type, used to pass to [WithFields]. type Fields map[string]interface{} // Level type +// +//nolint:recvcheck // the methods of "Entry" use pointer receiver and non-pointer receiver. type Level uint32 -// Convert the Level to a string. E.g. PanicLevel becomes "panic". +// Convert the Level to a string. E.g. [PanicLevel] becomes "panic". func (level Level) String() string { if b, err := level.MarshalText(); err == nil { return string(b) @@ -77,7 +79,7 @@ func (level Level) MarshalText() ([]byte, error) { return nil, fmt.Errorf("not a valid logrus level %d", level) } -// A constant exposing all logging levels +// AllLevels exposing all logging levels. var AllLevels = []Level{ PanicLevel, FatalLevel, @@ -119,8 +121,8 @@ var ( ) // StdLogger is what your logrus-enabled library should take, that way -// it'll accept a stdlib logger and a logrus logger. There's no standard -// interface, this is the closest we get, unfortunately. +// it'll accept a stdlib logger ([log.Logger]) and a logrus logger. +// There's no standard interface, so this is the closest we get, unfortunately. type StdLogger interface { Print(...interface{}) Printf(string, ...interface{}) @@ -135,7 +137,8 @@ type StdLogger interface { Panicln(...interface{}) } -// The FieldLogger interface generalizes the Entry and Logger types +// FieldLogger extends the [StdLogger] interface, generalizing +// the [Entry] and [Logger] types. type FieldLogger interface { WithField(key string, value interface{}) *Entry WithFields(fields Fields) *Entry @@ -176,8 +179,9 @@ type FieldLogger interface { // IsPanicEnabled() bool } -// Ext1FieldLogger (the first extension to FieldLogger) is superfluous, it is -// here for consistancy. Do not use. Use Logger or Entry instead. +// Ext1FieldLogger (the first extension to [FieldLogger]) is superfluous, it is +// here for consistency. Do not use. Use [FieldLogger], [Logger] or [Entry] +// instead. type Ext1FieldLogger interface { FieldLogger Tracef(format string, args ...interface{}) diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_bsd.go b/vendor/github.com/sirupsen/logrus/terminal_check_bsd.go index 499789984d..69956b425a 100644 --- a/vendor/github.com/sirupsen/logrus/terminal_check_bsd.go +++ b/vendor/github.com/sirupsen/logrus/terminal_check_bsd.go @@ -1,4 +1,4 @@ -// +build darwin dragonfly freebsd netbsd openbsd +// +build darwin dragonfly freebsd netbsd openbsd hurd // +build !js package logrus diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_unix.go b/vendor/github.com/sirupsen/logrus/terminal_check_unix.go index 04748b8515..c9aed267a4 100644 --- a/vendor/github.com/sirupsen/logrus/terminal_check_unix.go +++ b/vendor/github.com/sirupsen/logrus/terminal_check_unix.go @@ -1,5 +1,7 @@ +//go:build (linux || aix || zos) && !js && !wasi // +build linux aix zos // +build !js +// +build !wasi package logrus diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_wasi.go b/vendor/github.com/sirupsen/logrus/terminal_check_wasi.go new file mode 100644 index 0000000000..2822b212fb --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/terminal_check_wasi.go @@ -0,0 +1,8 @@ +//go:build wasi +// +build wasi + +package logrus + +func isTerminal(fd int) bool { + return false +} diff --git a/vendor/github.com/sirupsen/logrus/terminal_check_wasip1.go b/vendor/github.com/sirupsen/logrus/terminal_check_wasip1.go new file mode 100644 index 0000000000..108a6be12b --- /dev/null +++ b/vendor/github.com/sirupsen/logrus/terminal_check_wasip1.go @@ -0,0 +1,8 @@ +//go:build wasip1 +// +build wasip1 + +package logrus + +func isTerminal(fd int) bool { + return false +} diff --git a/vendor/github.com/sirupsen/logrus/text_formatter.go b/vendor/github.com/sirupsen/logrus/text_formatter.go index be2c6efe5e..6dfeb18b10 100644 --- a/vendor/github.com/sirupsen/logrus/text_formatter.go +++ b/vendor/github.com/sirupsen/logrus/text_formatter.go @@ -306,6 +306,7 @@ func (f *TextFormatter) needsQuoting(text string) bool { return false } for _, ch := range text { + //nolint:staticcheck // QF1001: could apply De Morgan's law if !((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || @@ -334,6 +335,6 @@ func (f *TextFormatter) appendValue(b *bytes.Buffer, value interface{}) { if !f.needsQuoting(stringVal) { b.WriteString(stringVal) } else { - b.WriteString(fmt.Sprintf("%q", stringVal)) + fmt.Fprintf(b, "%q", stringVal) } } diff --git a/vendor/github.com/zgalor/weberr/README.md b/vendor/github.com/zgalor/weberr/README.md index 37c5f35525..2636322394 100644 --- a/vendor/github.com/zgalor/weberr/README.md +++ b/vendor/github.com/zgalor/weberr/README.md @@ -6,6 +6,7 @@ Package weberr based on https://github.com/pkg/errors with a few additions: * Set an error type that corresponds to HTTP status returned by this error * Set a user friendly error message (in addition to the error message that will be logged) +* Add arbitrary details to the error [![Go Report Card](https://goreportcard.com/badge/github.com/zgalor/weberr)](https://goreportcard.com/report/github.com/zgalor/weberr) [![Build Status](https://travis-ci.org/zgalor/weberr.svg?branch=master)](https://travis-ci.org/zgalor/weberr) @@ -16,6 +17,10 @@ Package weberr based on https://github.com/pkg/errors with a few additions: [Read the package documentation for more information](https://godoc.org/github.com/zgalor/weberr). +## Divergences from pkg/errors + +* We chose `weberr.Wrapf(nil, ...)` and similar wrapping functions should return a new error, whereas `errors.Wrapf(nil, ...)` historically returns nil. + ## License BSD-2-Clause diff --git a/vendor/github.com/zgalor/weberr/errors.go b/vendor/github.com/zgalor/weberr/errors.go index c1d462d203..9e9e4a57df 100644 --- a/vendor/github.com/zgalor/weberr/errors.go +++ b/vendor/github.com/zgalor/weberr/errors.go @@ -1,6 +1,7 @@ package weberr import ( + goerrors "errors" "fmt" "net/http" @@ -11,7 +12,9 @@ import ( type ErrorType uint const ( - // NoType error - Default placeholder for un-typed errors + // NoType error - Default placeholder for un-typed errors. + // Methods on NoType behave differently than other types - they + // will preserve an existing type when wrapping a typed error. NoType ErrorType = iota // 4xx Client errors @@ -99,7 +102,7 @@ const ( NetworkAuthenticationRequired ErrorType = http.StatusNetworkAuthenticationRequired ) -// customError wraps an error with type and user message +// customError wraps an error with type, separate user message, and details. type customError struct { error errorType ErrorType @@ -113,9 +116,12 @@ type causer interface { Cause() error } -// Cause unwrappes error +// Cause unwraps error func (c *customError) Cause() error { return c.error } +// Unwrap error +func (c *customError) Unwrap() error { return c.error } + // typed interface identifies error with a type type typed interface { Type() ErrorType @@ -124,8 +130,8 @@ type typed interface { // Type returns the error type func (c *customError) Type() ErrorType { return c.errorType } -// GetType returns the error type for all errors -// if error is not `typed` - it returns NoType +// GetType returns the error type for all errors. +// If error is not `typed` - it returns NoType. func GetType(err error) ErrorType { if typeErr, ok := err.(typed); ok { return typeErr.Type() @@ -142,8 +148,8 @@ type userMessager interface { // UserMessage returns the user message func (c *customError) UserMessage() string { return c.userMessage } -// GetUserMessage returns user readable error message for all errors -// If error is not `userMessager` returns empty string +// GetUserMessage returns user readable error message for all errors. +// If error is not `userMessager` returns empty string. func GetUserMessage(err error) string { if msgErr, ok := err.(userMessager); ok { return msgErr.UserMessage() @@ -152,7 +158,6 @@ func GetUserMessage(err error) string { return "" } - // errorDetailer identifies an error with details type errorDetailer interface { Details() []interface{} @@ -161,8 +166,8 @@ type errorDetailer interface { // Details returns the error details func (c *customError) Details() []interface{} { return c.details } -// GetDetails returns a slice of arbitrary details for all errors -// If error is not `errorDetailer` returns nil +// GetDetails returns a slice of arbitrary details for all errors. +// If error is not `errorDetailer` returns nil. func GetDetails(err error) []interface{} { if detailedError, ok := err.(errorDetailer); ok { return detailedError.Details() @@ -171,7 +176,7 @@ func GetDetails(err error) []interface{} { return nil } -// Errorf creates a new customError with formatted message +// Errorf creates a new error of this type with formatted string. func (errorType ErrorType) Errorf(msg string, args ...interface{}) error { return &customError{ error: errors.WithStack(errors.Errorf(msg, args...)), @@ -179,7 +184,9 @@ func (errorType ErrorType) Errorf(msg string, args ...interface{}) error { } } -// Wrapf creates a new wrapped error with formatted message +// Wrapf creates a wrapping error of this type, with formatted string. +// The relation to the wrapped err is implicit, do not add a %s for it (like you would with fmt.Errorf). +// If wrapped err is nil, still returns a new error. func (errorType ErrorType) Wrapf(err error, msg string, args ...interface{}) error { if err == nil { return errorType.Errorf(msg, args...) @@ -199,7 +206,10 @@ func (errorType ErrorType) Wrapf(err error, msg string, args ...interface{}) err return c } -// UserWrapf adds a user readable to an error +// UserWrapf adds a formatted user readable message to an error. +// If wrapped err already had a user message, combines them with a colon, you should not add a %s for it. +// Also sets error type (or preserves existing type if called on NoType). +// If wrapped err is nil, still returns a new error. func (errorType ErrorType) UserWrapf(err error, msg string, args ...interface{}) error { if err == nil { return errorType.UserErrorf(msg, args...) @@ -226,7 +236,7 @@ func (errorType ErrorType) UserWrapf(err error, msg string, args ...interface{}) return c } -// UserErrorf creates a new error with a user message +// UserErrorf creates a new error with a user readable message. func (errorType ErrorType) UserErrorf(msg string, args ...interface{}) error { message := fmt.Sprintf(msg, args...) return &customError{ @@ -236,7 +246,8 @@ func (errorType ErrorType) UserErrorf(msg string, args ...interface{}) error { } } -// AddDetails adds a details element to an error +// AddDetails adds a details element to an error. +// Also sets error type (or preserves existing type if called on NoType). func (errorType ErrorType) AddDetails(err error, details interface{}) error { if details == nil { return err @@ -304,27 +315,29 @@ func (errorType ErrorType) SetUserMessage(err error, msg string) error { } } -// Errorf returns an error with format string +// Errorf returns a new NoType error with formatted string. func Errorf(msg string, args ...interface{}) error { return NoType.Errorf(msg, args...) } -// Wrapf return an error with format string +// Wrapf creates a wrapping error, with unmodified type and formatted string. +// The relation to the wrapped err is implicit, do not add a %s for it (like you would with fmt.Errorf). +// If wrapped err is nil, still returns a new error. func Wrapf(err error, msg string, args ...interface{}) error { return NoType.Wrapf(err, msg, args...) } -// UserErrorf returns an error with format string +// UserErrorf returns an error with formatted user message. func UserErrorf(msg string, args ...interface{}) error { return NoType.UserErrorf(msg, args...) } -// UserWrapf adds a user readable to an error +// UserWrapf adds a user readable message to an error. func UserWrapf(err error, msg string, args ...interface{}) error { return NoType.UserWrapf(err, msg, args...) } -// AddDetails adds arbitrary details to an error +// AddDetails adds arbitrary details to an error. func AddDetails(err error, details interface{}) error { return NoType.AddDetails(err, details) } @@ -374,3 +387,20 @@ func GetStackTrace(err error) string { st := x.StackTrace() return fmt.Sprintf("%+v\n", st[1:]) } + +// As finds the first error in err's chain that matches target, +// and if so, sets target to that error value and returns true. Otherwise, it returns false. +func As(err error, target interface{}) bool { + return goerrors.As(err, target) +} + +// Is finds the first error in err's chain that matches target, +// and if so, sets target to that error value and returns true. Otherwise, it returns false. +func Is(err error, target error) bool { + return goerrors.Is(err, target) +} + +// Join returns an error that wraps the given errors into one. +func Join(errs ...error) error { + return goerrors.Join(errs...) +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 00b34cc628..ffddc22665 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -4,7 +4,7 @@ github.com/99designs/go-keychain # github.com/99designs/keyring v1.2.2 ## explicit; go 1.19 github.com/99designs/keyring -# github.com/AlecAivazis/survey/v2 v2.2.15 +# github.com/AlecAivazis/survey/v2 v2.3.7 ## explicit; go 1.13 github.com/AlecAivazis/survey/v2 github.com/AlecAivazis/survey/v2/core @@ -329,8 +329,6 @@ github.com/json-iterator/go # github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 ## explicit github.com/kballard/go-shellquote -# github.com/kr/pty v1.1.8 -## explicit; go 1.12 # github.com/lib/pq v1.10.5 ## explicit; go 1.13 github.com/lib/pq @@ -526,8 +524,8 @@ github.com/robfig/cron/v3 # github.com/russross/blackfriday/v2 v2.1.0 ## explicit github.com/russross/blackfriday/v2 -# github.com/sirupsen/logrus v1.9.3 -## explicit; go 1.13 +# github.com/sirupsen/logrus v1.9.4 +## explicit; go 1.17 github.com/sirupsen/logrus # github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 ## explicit @@ -546,7 +544,7 @@ github.com/x448/float16 ## explicit; go 1.18 github.com/zalando/go-keyring github.com/zalando/go-keyring/secret_service -# github.com/zgalor/weberr v0.6.0 +# github.com/zgalor/weberr v0.9.0 ## explicit github.com/zgalor/weberr # gitlab.com/c0b/go-ordered-json v0.0.0-20201030195603-febf46534d5a