This commit is contained in:
parent
9264193cd8
commit
8e7365b93f
212 changed files with 13881 additions and 9534 deletions
25
go.mod
25
go.mod
|
|
@ -1,6 +1,8 @@
|
|||
module batmon
|
||||
|
||||
go 1.21.5
|
||||
go 1.22.0
|
||||
|
||||
toolchain go1.23.4
|
||||
|
||||
require (
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
|
|
@ -9,24 +11,23 @@ require (
|
|||
)
|
||||
|
||||
require (
|
||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||
github.com/fsnotify/fsnotify v1.8.0 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/magiconair/properties v1.8.7 // indirect
|
||||
github.com/magiconair/properties v1.8.9 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
||||
github.com/sagikazarmark/locafero v0.4.0 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
|
||||
github.com/sagikazarmark/locafero v0.7.0 // indirect
|
||||
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
|
||||
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||
github.com/spf13/afero v1.11.0 // indirect
|
||||
github.com/spf13/cast v1.6.0 // indirect
|
||||
github.com/spf13/afero v1.12.0 // indirect
|
||||
github.com/spf13/cast v1.7.1 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/subosito/gotenv v1.6.0 // indirect
|
||||
go.uber.org/atomic v1.9.0 // indirect
|
||||
go.uber.org/multierr v1.9.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
|
||||
golang.org/x/sys v0.18.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 // indirect
|
||||
golang.org/x/sys v0.29.0 // indirect
|
||||
golang.org/x/text v0.21.0 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
|
|
|||
57
go.sum
57
go.sum
|
|
@ -5,10 +5,10 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1
|
|||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
|
||||
github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
|
|
@ -17,30 +17,30 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
|||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
|
||||
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||
github.com/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM=
|
||||
github.com/magiconair/properties v1.8.9/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
|
||||
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
|
||||
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
|
||||
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ=
|
||||
github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
|
||||
github.com/sagikazarmark/locafero v0.7.0 h1:5MqpDsTGNDhY8sGp0Aowyf0qKsPrhewaLSsFaodPcyo=
|
||||
github.com/sagikazarmark/locafero v0.7.0/go.mod h1:2za3Cg5rMaTMoG/2Ulr9AwtFaIppKXTRYnozin4aB5k=
|
||||
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
|
||||
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
|
||||
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
|
||||
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
|
||||
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
|
||||
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
|
||||
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
||||
github.com/spf13/afero v1.12.0 h1:UcOPyRBYczmFn6yvphxkn9ZEOY65cpwGKb5mL36mrqs=
|
||||
github.com/spf13/afero v1.12.0/go.mod h1:ZTlWwG4/ahT8W7T0WQ5uYmjI9duaLQGy3Q2OAl4sk/4=
|
||||
github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y=
|
||||
github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
||||
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
|
||||
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
|
|
@ -48,29 +48,20 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An
|
|||
github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI=
|
||||
github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||
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.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
||||
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
|
||||
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
|
||||
go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
|
||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
|
||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||
golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 h1:yqrTHse8TCMW1M1ZCP+VAR/l0kKxwaAIqN/il7x4voA=
|
||||
golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
|
||||
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
|
||||
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
|
|
|||
7
vendor/github.com/fsnotify/fsnotify/.cirrus.yml
generated
vendored
7
vendor/github.com/fsnotify/fsnotify/.cirrus.yml
generated
vendored
|
|
@ -1,7 +1,7 @@
|
|||
freebsd_task:
|
||||
name: 'FreeBSD'
|
||||
freebsd_instance:
|
||||
image_family: freebsd-13-2
|
||||
image_family: freebsd-14-1
|
||||
install_script:
|
||||
- pkg update -f
|
||||
- pkg install -y go
|
||||
|
|
@ -9,5 +9,6 @@ freebsd_task:
|
|||
# run tests as user "cirrus" instead of root
|
||||
- pw useradd cirrus -m
|
||||
- chown -R cirrus:cirrus .
|
||||
- FSNOTIFY_BUFFER=4096 sudo --preserve-env=FSNOTIFY_BUFFER -u cirrus go test -parallel 1 -race ./...
|
||||
- sudo --preserve-env=FSNOTIFY_BUFFER -u cirrus go test -parallel 1 -race ./...
|
||||
- FSNOTIFY_BUFFER=4096 sudo --preserve-env=FSNOTIFY_BUFFER -u cirrus go test -parallel 1 -race ./...
|
||||
- sudo --preserve-env=FSNOTIFY_BUFFER -u cirrus go test -parallel 1 -race ./...
|
||||
- FSNOTIFY_DEBUG=1 sudo --preserve-env=FSNOTIFY_BUFFER -u cirrus go test -parallel 1 -race -v ./...
|
||||
|
|
|
|||
1
vendor/github.com/fsnotify/fsnotify/.gitattributes
generated
vendored
1
vendor/github.com/fsnotify/fsnotify/.gitattributes
generated
vendored
|
|
@ -1 +0,0 @@
|
|||
go.sum linguist-generated
|
||||
3
vendor/github.com/fsnotify/fsnotify/.gitignore
generated
vendored
3
vendor/github.com/fsnotify/fsnotify/.gitignore
generated
vendored
|
|
@ -5,3 +5,6 @@
|
|||
# Output of go build ./cmd/fsnotify
|
||||
/fsnotify
|
||||
/fsnotify.exe
|
||||
|
||||
/test/kqueue
|
||||
/test/a.out
|
||||
|
|
|
|||
34
vendor/github.com/fsnotify/fsnotify/CHANGELOG.md
generated
vendored
34
vendor/github.com/fsnotify/fsnotify/CHANGELOG.md
generated
vendored
|
|
@ -1,8 +1,36 @@
|
|||
# Changelog
|
||||
|
||||
Unreleased
|
||||
----------
|
||||
Nothing yet.
|
||||
1.8.0 2023-10-31
|
||||
----------------
|
||||
|
||||
### Additions
|
||||
|
||||
- all: add `FSNOTIFY_DEBUG` to print debug logs to stderr ([#619])
|
||||
|
||||
### Changes and fixes
|
||||
|
||||
- windows: fix behaviour of `WatchList()` to be consistent with other platforms ([#610])
|
||||
|
||||
- kqueue: ignore events with Ident=0 ([#590])
|
||||
|
||||
- kqueue: set O_CLOEXEC to prevent passing file descriptors to children ([#617])
|
||||
|
||||
- kqueue: emit events as "/path/dir/file" instead of "path/link/file" when watching a symlink ([#625])
|
||||
|
||||
- inotify: don't send event for IN_DELETE_SELF when also watching the parent ([#620])
|
||||
|
||||
- inotify: fix panic when calling Remove() in a goroutine ([#650])
|
||||
|
||||
- fen: allow watching subdirectories of watched directories ([#621])
|
||||
|
||||
[#590]: https://github.com/fsnotify/fsnotify/pull/590
|
||||
[#610]: https://github.com/fsnotify/fsnotify/pull/610
|
||||
[#617]: https://github.com/fsnotify/fsnotify/pull/617
|
||||
[#619]: https://github.com/fsnotify/fsnotify/pull/619
|
||||
[#620]: https://github.com/fsnotify/fsnotify/pull/620
|
||||
[#621]: https://github.com/fsnotify/fsnotify/pull/621
|
||||
[#625]: https://github.com/fsnotify/fsnotify/pull/625
|
||||
[#650]: https://github.com/fsnotify/fsnotify/pull/650
|
||||
|
||||
1.7.0 - 2023-10-22
|
||||
------------------
|
||||
|
|
|
|||
120
vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md
generated
vendored
120
vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md
generated
vendored
|
|
@ -1,7 +1,7 @@
|
|||
Thank you for your interest in contributing to fsnotify! We try to review and
|
||||
merge PRs in a reasonable timeframe, but please be aware that:
|
||||
|
||||
- To avoid "wasted" work, please discus changes on the issue tracker first. You
|
||||
- To avoid "wasted" work, please discuss changes on the issue tracker first. You
|
||||
can just send PRs, but they may end up being rejected for one reason or the
|
||||
other.
|
||||
|
||||
|
|
@ -20,6 +20,124 @@ platforms. Testing different platforms locally can be done with something like
|
|||
|
||||
Use the `-short` flag to make the "stress test" run faster.
|
||||
|
||||
Writing new tests
|
||||
-----------------
|
||||
Scripts in the testdata directory allow creating test cases in a "shell-like"
|
||||
syntax. The basic format is:
|
||||
|
||||
script
|
||||
|
||||
Output:
|
||||
desired output
|
||||
|
||||
For example:
|
||||
|
||||
# Create a new empty file with some data.
|
||||
watch /
|
||||
echo data >/file
|
||||
|
||||
Output:
|
||||
create /file
|
||||
write /file
|
||||
|
||||
Just create a new file to add a new test; select which tests to run with
|
||||
`-run TestScript/[path]`.
|
||||
|
||||
script
|
||||
------
|
||||
The script is a "shell-like" script:
|
||||
|
||||
cmd arg arg
|
||||
|
||||
Comments are supported with `#`:
|
||||
|
||||
# Comment
|
||||
cmd arg arg # Comment
|
||||
|
||||
All operations are done in a temp directory; a path like "/foo" is rewritten to
|
||||
"/tmp/TestFoo/foo".
|
||||
|
||||
Arguments can be quoted with `"` or `'`; there are no escapes and they're
|
||||
functionally identical right now, but this may change in the future, so best to
|
||||
assume shell-like rules.
|
||||
|
||||
touch "/file with spaces"
|
||||
|
||||
End-of-line escapes with `\` are not supported.
|
||||
|
||||
### Supported commands
|
||||
|
||||
watch path [ops] # Watch the path, reporting events for it. Nothing is
|
||||
# watched by default. Optionally a list of ops can be
|
||||
# given, as with AddWith(path, WithOps(...)).
|
||||
unwatch path # Stop watching the path.
|
||||
watchlist n # Assert watchlist length.
|
||||
|
||||
stop # Stop running the script; for debugging.
|
||||
debug [yes/no] # Enable/disable FSNOTIFY_DEBUG (tests are run in
|
||||
parallel by default, so -parallel=1 is probably a good
|
||||
idea).
|
||||
|
||||
touch path
|
||||
mkdir [-p] dir
|
||||
ln -s target link # Only ln -s supported.
|
||||
mkfifo path
|
||||
mknod dev path
|
||||
mv src dst
|
||||
rm [-r] path
|
||||
chmod mode path # Octal only
|
||||
sleep time-in-ms
|
||||
|
||||
cat path # Read path (does nothing with the data; just reads it).
|
||||
echo str >>path # Append "str" to "path".
|
||||
echo str >path # Truncate "path" and write "str".
|
||||
|
||||
require reason # Skip the test if "reason" is true; "skip" and
|
||||
skip reason # "require" behave identical; it supports both for
|
||||
# readability. Possible reasons are:
|
||||
#
|
||||
# always Always skip this test.
|
||||
# symlink Symlinks are supported (requires admin
|
||||
# permissions on Windows).
|
||||
# mkfifo Platform doesn't support FIFO named sockets.
|
||||
# mknod Platform doesn't support device nodes.
|
||||
|
||||
|
||||
output
|
||||
------
|
||||
After `Output:` the desired output is given; this is indented by convention, but
|
||||
that's not required.
|
||||
|
||||
The format of that is:
|
||||
|
||||
# Comment
|
||||
event path # Comment
|
||||
|
||||
system:
|
||||
event path
|
||||
system2:
|
||||
event path
|
||||
|
||||
Every event is one line, and any whitespace between the event and path are
|
||||
ignored. The path can optionally be surrounded in ". Anything after a "#" is
|
||||
ignored.
|
||||
|
||||
Platform-specific tests can be added after GOOS; for example:
|
||||
|
||||
watch /
|
||||
touch /file
|
||||
|
||||
Output:
|
||||
# Tested if nothing else matches
|
||||
create /file
|
||||
|
||||
# Windows-specific test.
|
||||
windows:
|
||||
write /file
|
||||
|
||||
You can specify multiple platforms with a comma (e.g. "windows, linux:").
|
||||
"kqueue" is a shortcut for all kqueue systems (BSD, macOS).
|
||||
|
||||
|
||||
[goon]: https://github.com/arp242/goon
|
||||
[Vagrant]: https://www.vagrantup.com/
|
||||
|
|
|
|||
324
vendor/github.com/fsnotify/fsnotify/backend_fen.go
generated
vendored
324
vendor/github.com/fsnotify/fsnotify/backend_fen.go
generated
vendored
|
|
@ -1,8 +1,8 @@
|
|||
//go:build solaris
|
||||
// +build solaris
|
||||
|
||||
// Note: the documentation on the Watcher type and methods is generated from
|
||||
// mkdoc.zsh
|
||||
// FEN backend for illumos (supported) and Solaris (untested, but should work).
|
||||
//
|
||||
// See port_create(3c) etc. for docs. https://www.illumos.org/man/3C/port_create
|
||||
|
||||
package fsnotify
|
||||
|
||||
|
|
@ -12,150 +12,33 @@ import (
|
|||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/fsnotify/fsnotify/internal"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// Watcher watches a set of paths, delivering events on a channel.
|
||||
//
|
||||
// A watcher should not be copied (e.g. pass it by pointer, rather than by
|
||||
// value).
|
||||
//
|
||||
// # Linux notes
|
||||
//
|
||||
// When a file is removed a Remove event won't be emitted until all file
|
||||
// descriptors are closed, and deletes will always emit a Chmod. For example:
|
||||
//
|
||||
// fp := os.Open("file")
|
||||
// os.Remove("file") // Triggers Chmod
|
||||
// fp.Close() // Triggers Remove
|
||||
//
|
||||
// This is the event that inotify sends, so not much can be changed about this.
|
||||
//
|
||||
// The fs.inotify.max_user_watches sysctl variable specifies the upper limit
|
||||
// for the number of watches per user, and fs.inotify.max_user_instances
|
||||
// specifies the maximum number of inotify instances per user. Every Watcher you
|
||||
// create is an "instance", and every path you add is a "watch".
|
||||
//
|
||||
// These are also exposed in /proc as /proc/sys/fs/inotify/max_user_watches and
|
||||
// /proc/sys/fs/inotify/max_user_instances
|
||||
//
|
||||
// To increase them you can use sysctl or write the value to the /proc file:
|
||||
//
|
||||
// # Default values on Linux 5.18
|
||||
// sysctl fs.inotify.max_user_watches=124983
|
||||
// sysctl fs.inotify.max_user_instances=128
|
||||
//
|
||||
// To make the changes persist on reboot edit /etc/sysctl.conf or
|
||||
// /usr/lib/sysctl.d/50-default.conf (details differ per Linux distro; check
|
||||
// your distro's documentation):
|
||||
//
|
||||
// fs.inotify.max_user_watches=124983
|
||||
// fs.inotify.max_user_instances=128
|
||||
//
|
||||
// Reaching the limit will result in a "no space left on device" or "too many open
|
||||
// files" error.
|
||||
//
|
||||
// # kqueue notes (macOS, BSD)
|
||||
//
|
||||
// kqueue requires opening a file descriptor for every file that's being watched;
|
||||
// so if you're watching a directory with five files then that's six file
|
||||
// descriptors. You will run in to your system's "max open files" limit faster on
|
||||
// these platforms.
|
||||
//
|
||||
// The sysctl variables kern.maxfiles and kern.maxfilesperproc can be used to
|
||||
// control the maximum number of open files, as well as /etc/login.conf on BSD
|
||||
// systems.
|
||||
//
|
||||
// # Windows notes
|
||||
//
|
||||
// Paths can be added as "C:\path\to\dir", but forward slashes
|
||||
// ("C:/path/to/dir") will also work.
|
||||
//
|
||||
// When a watched directory is removed it will always send an event for the
|
||||
// directory itself, but may not send events for all files in that directory.
|
||||
// Sometimes it will send events for all times, sometimes it will send no
|
||||
// events, and often only for some files.
|
||||
//
|
||||
// The default ReadDirectoryChangesW() buffer size is 64K, which is the largest
|
||||
// value that is guaranteed to work with SMB filesystems. If you have many
|
||||
// events in quick succession this may not be enough, and you will have to use
|
||||
// [WithBufferSize] to increase the value.
|
||||
type Watcher struct {
|
||||
// Events sends the filesystem change events.
|
||||
//
|
||||
// fsnotify can send the following events; a "path" here can refer to a
|
||||
// file, directory, symbolic link, or special file like a FIFO.
|
||||
//
|
||||
// fsnotify.Create A new path was created; this may be followed by one
|
||||
// or more Write events if data also gets written to a
|
||||
// file.
|
||||
//
|
||||
// fsnotify.Remove A path was removed.
|
||||
//
|
||||
// fsnotify.Rename A path was renamed. A rename is always sent with the
|
||||
// old path as Event.Name, and a Create event will be
|
||||
// sent with the new name. Renames are only sent for
|
||||
// paths that are currently watched; e.g. moving an
|
||||
// unmonitored file into a monitored directory will
|
||||
// show up as just a Create. Similarly, renaming a file
|
||||
// to outside a monitored directory will show up as
|
||||
// only a Rename.
|
||||
//
|
||||
// fsnotify.Write A file or named pipe was written to. A Truncate will
|
||||
// also trigger a Write. A single "write action"
|
||||
// initiated by the user may show up as one or multiple
|
||||
// writes, depending on when the system syncs things to
|
||||
// disk. For example when compiling a large Go program
|
||||
// you may get hundreds of Write events, and you may
|
||||
// want to wait until you've stopped receiving them
|
||||
// (see the dedup example in cmd/fsnotify).
|
||||
//
|
||||
// Some systems may send Write event for directories
|
||||
// when the directory content changes.
|
||||
//
|
||||
// fsnotify.Chmod Attributes were changed. On Linux this is also sent
|
||||
// when a file is removed (or more accurately, when a
|
||||
// link to an inode is removed). On kqueue it's sent
|
||||
// when a file is truncated. On Windows it's never
|
||||
// sent.
|
||||
type fen struct {
|
||||
Events chan Event
|
||||
|
||||
// Errors sends any errors.
|
||||
//
|
||||
// ErrEventOverflow is used to indicate there are too many events:
|
||||
//
|
||||
// - inotify: There are too many queued events (fs.inotify.max_queued_events sysctl)
|
||||
// - windows: The buffer size is too small; WithBufferSize() can be used to increase it.
|
||||
// - kqueue, fen: Not used.
|
||||
Errors chan error
|
||||
|
||||
mu sync.Mutex
|
||||
port *unix.EventPort
|
||||
done chan struct{} // Channel for sending a "quit message" to the reader goroutine
|
||||
dirs map[string]struct{} // Explicitly watched directories
|
||||
watches map[string]struct{} // Explicitly watched non-directories
|
||||
done chan struct{} // Channel for sending a "quit message" to the reader goroutine
|
||||
dirs map[string]Op // Explicitly watched directories
|
||||
watches map[string]Op // Explicitly watched non-directories
|
||||
}
|
||||
|
||||
// NewWatcher creates a new Watcher.
|
||||
func NewWatcher() (*Watcher, error) {
|
||||
return NewBufferedWatcher(0)
|
||||
func newBackend(ev chan Event, errs chan error) (backend, error) {
|
||||
return newBufferedBackend(0, ev, errs)
|
||||
}
|
||||
|
||||
// NewBufferedWatcher creates a new Watcher with a buffered Watcher.Events
|
||||
// channel.
|
||||
//
|
||||
// The main use case for this is situations with a very large number of events
|
||||
// where the kernel buffer size can't be increased (e.g. due to lack of
|
||||
// permissions). An unbuffered Watcher will perform better for almost all use
|
||||
// cases, and whenever possible you will be better off increasing the kernel
|
||||
// buffers instead of adding a large userspace buffer.
|
||||
func NewBufferedWatcher(sz uint) (*Watcher, error) {
|
||||
w := &Watcher{
|
||||
Events: make(chan Event, sz),
|
||||
Errors: make(chan error),
|
||||
dirs: make(map[string]struct{}),
|
||||
watches: make(map[string]struct{}),
|
||||
func newBufferedBackend(sz uint, ev chan Event, errs chan error) (backend, error) {
|
||||
w := &fen{
|
||||
Events: ev,
|
||||
Errors: errs,
|
||||
dirs: make(map[string]Op),
|
||||
watches: make(map[string]Op),
|
||||
done: make(chan struct{}),
|
||||
}
|
||||
|
||||
|
|
@ -171,27 +54,30 @@ func NewBufferedWatcher(sz uint) (*Watcher, error) {
|
|||
|
||||
// sendEvent attempts to send an event to the user, returning true if the event
|
||||
// was put in the channel successfully and false if the watcher has been closed.
|
||||
func (w *Watcher) sendEvent(name string, op Op) (sent bool) {
|
||||
func (w *fen) sendEvent(name string, op Op) (sent bool) {
|
||||
select {
|
||||
case w.Events <- Event{Name: name, Op: op}:
|
||||
return true
|
||||
case <-w.done:
|
||||
return false
|
||||
case w.Events <- Event{Name: name, Op: op}:
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// sendError attempts to send an error to the user, returning true if the error
|
||||
// was put in the channel successfully and false if the watcher has been closed.
|
||||
func (w *Watcher) sendError(err error) (sent bool) {
|
||||
select {
|
||||
case w.Errors <- err:
|
||||
func (w *fen) sendError(err error) (sent bool) {
|
||||
if err == nil {
|
||||
return true
|
||||
}
|
||||
select {
|
||||
case <-w.done:
|
||||
return false
|
||||
case w.Errors <- err:
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
func (w *Watcher) isClosed() bool {
|
||||
func (w *fen) isClosed() bool {
|
||||
select {
|
||||
case <-w.done:
|
||||
return true
|
||||
|
|
@ -200,8 +86,7 @@ func (w *Watcher) isClosed() bool {
|
|||
}
|
||||
}
|
||||
|
||||
// Close removes all watches and closes the Events channel.
|
||||
func (w *Watcher) Close() error {
|
||||
func (w *fen) Close() error {
|
||||
// Take the lock used by associateFile to prevent lingering events from
|
||||
// being processed after the close
|
||||
w.mu.Lock()
|
||||
|
|
@ -213,60 +98,21 @@ func (w *Watcher) Close() error {
|
|||
return w.port.Close()
|
||||
}
|
||||
|
||||
// Add starts monitoring the path for changes.
|
||||
//
|
||||
// A path can only be watched once; watching it more than once is a no-op and will
|
||||
// not return an error. Paths that do not yet exist on the filesystem cannot be
|
||||
// watched.
|
||||
//
|
||||
// A watch will be automatically removed if the watched path is deleted or
|
||||
// renamed. The exception is the Windows backend, which doesn't remove the
|
||||
// watcher on renames.
|
||||
//
|
||||
// Notifications on network filesystems (NFS, SMB, FUSE, etc.) or special
|
||||
// filesystems (/proc, /sys, etc.) generally don't work.
|
||||
//
|
||||
// Returns [ErrClosed] if [Watcher.Close] was called.
|
||||
//
|
||||
// See [Watcher.AddWith] for a version that allows adding options.
|
||||
//
|
||||
// # Watching directories
|
||||
//
|
||||
// All files in a directory are monitored, including new files that are created
|
||||
// after the watcher is started. Subdirectories are not watched (i.e. it's
|
||||
// non-recursive).
|
||||
//
|
||||
// # Watching files
|
||||
//
|
||||
// Watching individual files (rather than directories) is generally not
|
||||
// recommended as many programs (especially editors) update files atomically: it
|
||||
// will write to a temporary file which is then moved to to destination,
|
||||
// overwriting the original (or some variant thereof). The watcher on the
|
||||
// original file is now lost, as that no longer exists.
|
||||
//
|
||||
// The upshot of this is that a power failure or crash won't leave a
|
||||
// half-written file.
|
||||
//
|
||||
// Watch the parent directory and use Event.Name to filter out files you're not
|
||||
// interested in. There is an example of this in cmd/fsnotify/file.go.
|
||||
func (w *Watcher) Add(name string) error { return w.AddWith(name) }
|
||||
func (w *fen) Add(name string) error { return w.AddWith(name) }
|
||||
|
||||
// AddWith is like [Watcher.Add], but allows adding options. When using Add()
|
||||
// the defaults described below are used.
|
||||
//
|
||||
// Possible options are:
|
||||
//
|
||||
// - [WithBufferSize] sets the buffer size for the Windows backend; no-op on
|
||||
// other platforms. The default is 64K (65536 bytes).
|
||||
func (w *Watcher) AddWith(name string, opts ...addOpt) error {
|
||||
func (w *fen) AddWith(name string, opts ...addOpt) error {
|
||||
if w.isClosed() {
|
||||
return ErrClosed
|
||||
}
|
||||
if w.port.PathIsWatched(name) {
|
||||
return nil
|
||||
if debug {
|
||||
fmt.Fprintf(os.Stderr, "FSNOTIFY_DEBUG: %s AddWith(%q)\n",
|
||||
time.Now().Format("15:04:05.000000000"), name)
|
||||
}
|
||||
|
||||
_ = getOptions(opts...)
|
||||
with := getOptions(opts...)
|
||||
if !w.xSupports(with.op) {
|
||||
return fmt.Errorf("%w: %s", xErrUnsupported, with.op)
|
||||
}
|
||||
|
||||
// Currently we resolve symlinks that were explicitly requested to be
|
||||
// watched. Otherwise we would use LStat here.
|
||||
|
|
@ -283,7 +129,7 @@ func (w *Watcher) AddWith(name string, opts ...addOpt) error {
|
|||
}
|
||||
|
||||
w.mu.Lock()
|
||||
w.dirs[name] = struct{}{}
|
||||
w.dirs[name] = with.op
|
||||
w.mu.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
|
@ -294,26 +140,22 @@ func (w *Watcher) AddWith(name string, opts ...addOpt) error {
|
|||
}
|
||||
|
||||
w.mu.Lock()
|
||||
w.watches[name] = struct{}{}
|
||||
w.watches[name] = with.op
|
||||
w.mu.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
// Remove stops monitoring the path for changes.
|
||||
//
|
||||
// Directories are always removed non-recursively. For example, if you added
|
||||
// /tmp/dir and /tmp/dir/subdir then you will need to remove both.
|
||||
//
|
||||
// Removing a path that has not yet been added returns [ErrNonExistentWatch].
|
||||
//
|
||||
// Returns nil if [Watcher.Close] was called.
|
||||
func (w *Watcher) Remove(name string) error {
|
||||
func (w *fen) Remove(name string) error {
|
||||
if w.isClosed() {
|
||||
return nil
|
||||
}
|
||||
if !w.port.PathIsWatched(name) {
|
||||
return fmt.Errorf("%w: %s", ErrNonExistentWatch, name)
|
||||
}
|
||||
if debug {
|
||||
fmt.Fprintf(os.Stderr, "FSNOTIFY_DEBUG: %s Remove(%q)\n",
|
||||
time.Now().Format("15:04:05.000000000"), name)
|
||||
}
|
||||
|
||||
// The user has expressed an intent. Immediately remove this name from
|
||||
// whichever watch list it might be in. If it's not in there the delete
|
||||
|
|
@ -346,7 +188,7 @@ func (w *Watcher) Remove(name string) error {
|
|||
}
|
||||
|
||||
// readEvents contains the main loop that runs in a goroutine watching for events.
|
||||
func (w *Watcher) readEvents() {
|
||||
func (w *fen) readEvents() {
|
||||
// If this function returns, the watcher has been closed and we can close
|
||||
// these channels
|
||||
defer func() {
|
||||
|
|
@ -382,17 +224,19 @@ func (w *Watcher) readEvents() {
|
|||
continue
|
||||
}
|
||||
|
||||
if debug {
|
||||
internal.Debug(pevent.Path, pevent.Events)
|
||||
}
|
||||
|
||||
err = w.handleEvent(&pevent)
|
||||
if err != nil {
|
||||
if !w.sendError(err) {
|
||||
return
|
||||
}
|
||||
if !w.sendError(err) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (w *Watcher) handleDirectory(path string, stat os.FileInfo, follow bool, handler func(string, os.FileInfo, bool) error) error {
|
||||
func (w *fen) handleDirectory(path string, stat os.FileInfo, follow bool, handler func(string, os.FileInfo, bool) error) error {
|
||||
files, err := os.ReadDir(path)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -418,7 +262,7 @@ func (w *Watcher) handleDirectory(path string, stat os.FileInfo, follow bool, ha
|
|||
// bitmap matches more than one event type (e.g. the file was both modified and
|
||||
// had the attributes changed between when the association was created and the
|
||||
// when event was returned)
|
||||
func (w *Watcher) handleEvent(event *unix.PortEvent) error {
|
||||
func (w *fen) handleEvent(event *unix.PortEvent) error {
|
||||
var (
|
||||
events = event.Events
|
||||
path = event.Path
|
||||
|
|
@ -510,15 +354,9 @@ func (w *Watcher) handleEvent(event *unix.PortEvent) error {
|
|||
}
|
||||
|
||||
if events&unix.FILE_MODIFIED != 0 {
|
||||
if fmode.IsDir() {
|
||||
if watchedDir {
|
||||
if err := w.updateDirectory(path); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if !w.sendEvent(path, Write) {
|
||||
return nil
|
||||
}
|
||||
if fmode.IsDir() && watchedDir {
|
||||
if err := w.updateDirectory(path); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if !w.sendEvent(path, Write) {
|
||||
|
|
@ -543,7 +381,7 @@ func (w *Watcher) handleEvent(event *unix.PortEvent) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (w *Watcher) updateDirectory(path string) error {
|
||||
func (w *fen) updateDirectory(path string) error {
|
||||
// The directory was modified, so we must find unwatched entities and watch
|
||||
// them. If something was removed from the directory, nothing will happen,
|
||||
// as everything else should still be watched.
|
||||
|
|
@ -563,10 +401,8 @@ func (w *Watcher) updateDirectory(path string) error {
|
|||
return err
|
||||
}
|
||||
err = w.associateFile(path, finfo, false)
|
||||
if err != nil {
|
||||
if !w.sendError(err) {
|
||||
return nil
|
||||
}
|
||||
if !w.sendError(err) {
|
||||
return nil
|
||||
}
|
||||
if !w.sendEvent(path, Create) {
|
||||
return nil
|
||||
|
|
@ -575,7 +411,7 @@ func (w *Watcher) updateDirectory(path string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (w *Watcher) associateFile(path string, stat os.FileInfo, follow bool) error {
|
||||
func (w *fen) associateFile(path string, stat os.FileInfo, follow bool) error {
|
||||
if w.isClosed() {
|
||||
return ErrClosed
|
||||
}
|
||||
|
|
@ -593,34 +429,34 @@ func (w *Watcher) associateFile(path string, stat os.FileInfo, follow bool) erro
|
|||
// cleared up that discrepancy. The most likely cause is that the event
|
||||
// has fired but we haven't processed it yet.
|
||||
err := w.port.DissociatePath(path)
|
||||
if err != nil && err != unix.ENOENT {
|
||||
if err != nil && !errors.Is(err, unix.ENOENT) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// FILE_NOFOLLOW means we watch symlinks themselves rather than their
|
||||
// targets.
|
||||
events := unix.FILE_MODIFIED | unix.FILE_ATTRIB | unix.FILE_NOFOLLOW
|
||||
if follow {
|
||||
// We *DO* follow symlinks for explicitly watched entries.
|
||||
events = unix.FILE_MODIFIED | unix.FILE_ATTRIB
|
||||
|
||||
var events int
|
||||
if !follow {
|
||||
// Watch symlinks themselves rather than their targets unless this entry
|
||||
// is explicitly watched.
|
||||
events |= unix.FILE_NOFOLLOW
|
||||
}
|
||||
return w.port.AssociatePath(path, stat,
|
||||
events,
|
||||
stat.Mode())
|
||||
if true { // TODO: implement withOps()
|
||||
events |= unix.FILE_MODIFIED
|
||||
}
|
||||
if true {
|
||||
events |= unix.FILE_ATTRIB
|
||||
}
|
||||
return w.port.AssociatePath(path, stat, events, stat.Mode())
|
||||
}
|
||||
|
||||
func (w *Watcher) dissociateFile(path string, stat os.FileInfo, unused bool) error {
|
||||
func (w *fen) dissociateFile(path string, stat os.FileInfo, unused bool) error {
|
||||
if !w.port.PathIsWatched(path) {
|
||||
return nil
|
||||
}
|
||||
return w.port.DissociatePath(path)
|
||||
}
|
||||
|
||||
// WatchList returns all paths explicitly added with [Watcher.Add] (and are not
|
||||
// yet removed).
|
||||
//
|
||||
// Returns nil if [Watcher.Close] was called.
|
||||
func (w *Watcher) WatchList() []string {
|
||||
func (w *fen) WatchList() []string {
|
||||
if w.isClosed() {
|
||||
return nil
|
||||
}
|
||||
|
|
@ -638,3 +474,11 @@ func (w *Watcher) WatchList() []string {
|
|||
|
||||
return entries
|
||||
}
|
||||
|
||||
func (w *fen) xSupports(op Op) bool {
|
||||
if op.Has(xUnportableOpen) || op.Has(xUnportableRead) ||
|
||||
op.Has(xUnportableCloseWrite) || op.Has(xUnportableCloseRead) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
|
|
|||
594
vendor/github.com/fsnotify/fsnotify/backend_inotify.go
generated
vendored
594
vendor/github.com/fsnotify/fsnotify/backend_inotify.go
generated
vendored
|
|
@ -1,8 +1,4 @@
|
|||
//go:build linux && !appengine
|
||||
// +build linux,!appengine
|
||||
|
||||
// Note: the documentation on the Watcher type and methods is generated from
|
||||
// mkdoc.zsh
|
||||
|
||||
package fsnotify
|
||||
|
||||
|
|
@ -10,127 +6,20 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/fsnotify/fsnotify/internal"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// Watcher watches a set of paths, delivering events on a channel.
|
||||
//
|
||||
// A watcher should not be copied (e.g. pass it by pointer, rather than by
|
||||
// value).
|
||||
//
|
||||
// # Linux notes
|
||||
//
|
||||
// When a file is removed a Remove event won't be emitted until all file
|
||||
// descriptors are closed, and deletes will always emit a Chmod. For example:
|
||||
//
|
||||
// fp := os.Open("file")
|
||||
// os.Remove("file") // Triggers Chmod
|
||||
// fp.Close() // Triggers Remove
|
||||
//
|
||||
// This is the event that inotify sends, so not much can be changed about this.
|
||||
//
|
||||
// The fs.inotify.max_user_watches sysctl variable specifies the upper limit
|
||||
// for the number of watches per user, and fs.inotify.max_user_instances
|
||||
// specifies the maximum number of inotify instances per user. Every Watcher you
|
||||
// create is an "instance", and every path you add is a "watch".
|
||||
//
|
||||
// These are also exposed in /proc as /proc/sys/fs/inotify/max_user_watches and
|
||||
// /proc/sys/fs/inotify/max_user_instances
|
||||
//
|
||||
// To increase them you can use sysctl or write the value to the /proc file:
|
||||
//
|
||||
// # Default values on Linux 5.18
|
||||
// sysctl fs.inotify.max_user_watches=124983
|
||||
// sysctl fs.inotify.max_user_instances=128
|
||||
//
|
||||
// To make the changes persist on reboot edit /etc/sysctl.conf or
|
||||
// /usr/lib/sysctl.d/50-default.conf (details differ per Linux distro; check
|
||||
// your distro's documentation):
|
||||
//
|
||||
// fs.inotify.max_user_watches=124983
|
||||
// fs.inotify.max_user_instances=128
|
||||
//
|
||||
// Reaching the limit will result in a "no space left on device" or "too many open
|
||||
// files" error.
|
||||
//
|
||||
// # kqueue notes (macOS, BSD)
|
||||
//
|
||||
// kqueue requires opening a file descriptor for every file that's being watched;
|
||||
// so if you're watching a directory with five files then that's six file
|
||||
// descriptors. You will run in to your system's "max open files" limit faster on
|
||||
// these platforms.
|
||||
//
|
||||
// The sysctl variables kern.maxfiles and kern.maxfilesperproc can be used to
|
||||
// control the maximum number of open files, as well as /etc/login.conf on BSD
|
||||
// systems.
|
||||
//
|
||||
// # Windows notes
|
||||
//
|
||||
// Paths can be added as "C:\path\to\dir", but forward slashes
|
||||
// ("C:/path/to/dir") will also work.
|
||||
//
|
||||
// When a watched directory is removed it will always send an event for the
|
||||
// directory itself, but may not send events for all files in that directory.
|
||||
// Sometimes it will send events for all times, sometimes it will send no
|
||||
// events, and often only for some files.
|
||||
//
|
||||
// The default ReadDirectoryChangesW() buffer size is 64K, which is the largest
|
||||
// value that is guaranteed to work with SMB filesystems. If you have many
|
||||
// events in quick succession this may not be enough, and you will have to use
|
||||
// [WithBufferSize] to increase the value.
|
||||
type Watcher struct {
|
||||
// Events sends the filesystem change events.
|
||||
//
|
||||
// fsnotify can send the following events; a "path" here can refer to a
|
||||
// file, directory, symbolic link, or special file like a FIFO.
|
||||
//
|
||||
// fsnotify.Create A new path was created; this may be followed by one
|
||||
// or more Write events if data also gets written to a
|
||||
// file.
|
||||
//
|
||||
// fsnotify.Remove A path was removed.
|
||||
//
|
||||
// fsnotify.Rename A path was renamed. A rename is always sent with the
|
||||
// old path as Event.Name, and a Create event will be
|
||||
// sent with the new name. Renames are only sent for
|
||||
// paths that are currently watched; e.g. moving an
|
||||
// unmonitored file into a monitored directory will
|
||||
// show up as just a Create. Similarly, renaming a file
|
||||
// to outside a monitored directory will show up as
|
||||
// only a Rename.
|
||||
//
|
||||
// fsnotify.Write A file or named pipe was written to. A Truncate will
|
||||
// also trigger a Write. A single "write action"
|
||||
// initiated by the user may show up as one or multiple
|
||||
// writes, depending on when the system syncs things to
|
||||
// disk. For example when compiling a large Go program
|
||||
// you may get hundreds of Write events, and you may
|
||||
// want to wait until you've stopped receiving them
|
||||
// (see the dedup example in cmd/fsnotify).
|
||||
//
|
||||
// Some systems may send Write event for directories
|
||||
// when the directory content changes.
|
||||
//
|
||||
// fsnotify.Chmod Attributes were changed. On Linux this is also sent
|
||||
// when a file is removed (or more accurately, when a
|
||||
// link to an inode is removed). On kqueue it's sent
|
||||
// when a file is truncated. On Windows it's never
|
||||
// sent.
|
||||
type inotify struct {
|
||||
Events chan Event
|
||||
|
||||
// Errors sends any errors.
|
||||
//
|
||||
// ErrEventOverflow is used to indicate there are too many events:
|
||||
//
|
||||
// - inotify: There are too many queued events (fs.inotify.max_queued_events sysctl)
|
||||
// - windows: The buffer size is too small; WithBufferSize() can be used to increase it.
|
||||
// - kqueue, fen: Not used.
|
||||
Errors chan error
|
||||
|
||||
// Store fd here as os.File.Read() will no longer return on close after
|
||||
|
|
@ -139,8 +28,26 @@ type Watcher struct {
|
|||
inotifyFile *os.File
|
||||
watches *watches
|
||||
done chan struct{} // Channel for sending a "quit message" to the reader goroutine
|
||||
closeMu sync.Mutex
|
||||
doneMu sync.Mutex
|
||||
doneResp chan struct{} // Channel to respond to Close
|
||||
|
||||
// Store rename cookies in an array, with the index wrapping to 0. Almost
|
||||
// all of the time what we get is a MOVED_FROM to set the cookie and the
|
||||
// next event inotify sends will be MOVED_TO to read it. However, this is
|
||||
// not guaranteed – as described in inotify(7) – and we may get other events
|
||||
// between the two MOVED_* events (including other MOVED_* ones).
|
||||
//
|
||||
// A second issue is that moving a file outside the watched directory will
|
||||
// trigger a MOVED_FROM to set the cookie, but we never see the MOVED_TO to
|
||||
// read and delete it. So just storing it in a map would slowly leak memory.
|
||||
//
|
||||
// Doing it like this gives us a simple fast LRU-cache that won't allocate.
|
||||
// Ten items should be more than enough for our purpose, and a loop over
|
||||
// such a short array is faster than a map access anyway (not that it hugely
|
||||
// matters since we're talking about hundreds of ns at the most, but still).
|
||||
cookies [10]koekje
|
||||
cookieIndex uint8
|
||||
cookiesMu sync.Mutex
|
||||
}
|
||||
|
||||
type (
|
||||
|
|
@ -150,9 +57,14 @@ type (
|
|||
path map[string]uint32 // pathname → wd
|
||||
}
|
||||
watch struct {
|
||||
wd uint32 // Watch descriptor (as returned by the inotify_add_watch() syscall)
|
||||
flags uint32 // inotify flags of this watch (see inotify(7) for the list of valid flags)
|
||||
path string // Watch path.
|
||||
wd uint32 // Watch descriptor (as returned by the inotify_add_watch() syscall)
|
||||
flags uint32 // inotify flags of this watch (see inotify(7) for the list of valid flags)
|
||||
path string // Watch path.
|
||||
recurse bool // Recursion with ./...?
|
||||
}
|
||||
koekje struct {
|
||||
cookie uint32
|
||||
path string
|
||||
}
|
||||
)
|
||||
|
||||
|
|
@ -179,23 +91,45 @@ func (w *watches) add(ww *watch) {
|
|||
func (w *watches) remove(wd uint32) {
|
||||
w.mu.Lock()
|
||||
defer w.mu.Unlock()
|
||||
delete(w.path, w.wd[wd].path)
|
||||
watch := w.wd[wd] // Could have had Remove() called. See #616.
|
||||
if watch == nil {
|
||||
return
|
||||
}
|
||||
delete(w.path, watch.path)
|
||||
delete(w.wd, wd)
|
||||
}
|
||||
|
||||
func (w *watches) removePath(path string) (uint32, bool) {
|
||||
func (w *watches) removePath(path string) ([]uint32, error) {
|
||||
w.mu.Lock()
|
||||
defer w.mu.Unlock()
|
||||
|
||||
path, recurse := recursivePath(path)
|
||||
wd, ok := w.path[path]
|
||||
if !ok {
|
||||
return 0, false
|
||||
return nil, fmt.Errorf("%w: %s", ErrNonExistentWatch, path)
|
||||
}
|
||||
|
||||
watch := w.wd[wd]
|
||||
if recurse && !watch.recurse {
|
||||
return nil, fmt.Errorf("can't use /... with non-recursive watch %q", path)
|
||||
}
|
||||
|
||||
delete(w.path, path)
|
||||
delete(w.wd, wd)
|
||||
if !watch.recurse {
|
||||
return []uint32{wd}, nil
|
||||
}
|
||||
|
||||
return wd, true
|
||||
wds := make([]uint32, 0, 8)
|
||||
wds = append(wds, wd)
|
||||
for p, rwd := range w.path {
|
||||
if filepath.HasPrefix(p, path) {
|
||||
delete(w.path, p)
|
||||
delete(w.wd, rwd)
|
||||
wds = append(wds, rwd)
|
||||
}
|
||||
}
|
||||
return wds, nil
|
||||
}
|
||||
|
||||
func (w *watches) byPath(path string) *watch {
|
||||
|
|
@ -236,20 +170,11 @@ func (w *watches) updatePath(path string, f func(*watch) (*watch, error)) error
|
|||
return nil
|
||||
}
|
||||
|
||||
// NewWatcher creates a new Watcher.
|
||||
func NewWatcher() (*Watcher, error) {
|
||||
return NewBufferedWatcher(0)
|
||||
func newBackend(ev chan Event, errs chan error) (backend, error) {
|
||||
return newBufferedBackend(0, ev, errs)
|
||||
}
|
||||
|
||||
// NewBufferedWatcher creates a new Watcher with a buffered Watcher.Events
|
||||
// channel.
|
||||
//
|
||||
// The main use case for this is situations with a very large number of events
|
||||
// where the kernel buffer size can't be increased (e.g. due to lack of
|
||||
// permissions). An unbuffered Watcher will perform better for almost all use
|
||||
// cases, and whenever possible you will be better off increasing the kernel
|
||||
// buffers instead of adding a large userspace buffer.
|
||||
func NewBufferedWatcher(sz uint) (*Watcher, error) {
|
||||
func newBufferedBackend(sz uint, ev chan Event, errs chan error) (backend, error) {
|
||||
// Need to set nonblocking mode for SetDeadline to work, otherwise blocking
|
||||
// I/O operations won't terminate on close.
|
||||
fd, errno := unix.InotifyInit1(unix.IN_CLOEXEC | unix.IN_NONBLOCK)
|
||||
|
|
@ -257,12 +182,12 @@ func NewBufferedWatcher(sz uint) (*Watcher, error) {
|
|||
return nil, errno
|
||||
}
|
||||
|
||||
w := &Watcher{
|
||||
w := &inotify{
|
||||
Events: ev,
|
||||
Errors: errs,
|
||||
fd: fd,
|
||||
inotifyFile: os.NewFile(uintptr(fd), ""),
|
||||
watches: newWatches(),
|
||||
Events: make(chan Event, sz),
|
||||
Errors: make(chan error),
|
||||
done: make(chan struct{}),
|
||||
doneResp: make(chan struct{}),
|
||||
}
|
||||
|
|
@ -272,26 +197,29 @@ func NewBufferedWatcher(sz uint) (*Watcher, error) {
|
|||
}
|
||||
|
||||
// Returns true if the event was sent, or false if watcher is closed.
|
||||
func (w *Watcher) sendEvent(e Event) bool {
|
||||
func (w *inotify) sendEvent(e Event) bool {
|
||||
select {
|
||||
case w.Events <- e:
|
||||
return true
|
||||
case <-w.done:
|
||||
return false
|
||||
case w.Events <- e:
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// Returns true if the error was sent, or false if watcher is closed.
|
||||
func (w *Watcher) sendError(err error) bool {
|
||||
select {
|
||||
case w.Errors <- err:
|
||||
func (w *inotify) sendError(err error) bool {
|
||||
if err == nil {
|
||||
return true
|
||||
}
|
||||
select {
|
||||
case <-w.done:
|
||||
return false
|
||||
case w.Errors <- err:
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
func (w *Watcher) isClosed() bool {
|
||||
func (w *inotify) isClosed() bool {
|
||||
select {
|
||||
case <-w.done:
|
||||
return true
|
||||
|
|
@ -300,15 +228,14 @@ func (w *Watcher) isClosed() bool {
|
|||
}
|
||||
}
|
||||
|
||||
// Close removes all watches and closes the Events channel.
|
||||
func (w *Watcher) Close() error {
|
||||
w.closeMu.Lock()
|
||||
func (w *inotify) Close() error {
|
||||
w.doneMu.Lock()
|
||||
if w.isClosed() {
|
||||
w.closeMu.Unlock()
|
||||
w.doneMu.Unlock()
|
||||
return nil
|
||||
}
|
||||
close(w.done)
|
||||
w.closeMu.Unlock()
|
||||
w.doneMu.Unlock()
|
||||
|
||||
// Causes any blocking reads to return with an error, provided the file
|
||||
// still supports deadline operations.
|
||||
|
|
@ -323,78 +250,104 @@ func (w *Watcher) Close() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Add starts monitoring the path for changes.
|
||||
//
|
||||
// A path can only be watched once; watching it more than once is a no-op and will
|
||||
// not return an error. Paths that do not yet exist on the filesystem cannot be
|
||||
// watched.
|
||||
//
|
||||
// A watch will be automatically removed if the watched path is deleted or
|
||||
// renamed. The exception is the Windows backend, which doesn't remove the
|
||||
// watcher on renames.
|
||||
//
|
||||
// Notifications on network filesystems (NFS, SMB, FUSE, etc.) or special
|
||||
// filesystems (/proc, /sys, etc.) generally don't work.
|
||||
//
|
||||
// Returns [ErrClosed] if [Watcher.Close] was called.
|
||||
//
|
||||
// See [Watcher.AddWith] for a version that allows adding options.
|
||||
//
|
||||
// # Watching directories
|
||||
//
|
||||
// All files in a directory are monitored, including new files that are created
|
||||
// after the watcher is started. Subdirectories are not watched (i.e. it's
|
||||
// non-recursive).
|
||||
//
|
||||
// # Watching files
|
||||
//
|
||||
// Watching individual files (rather than directories) is generally not
|
||||
// recommended as many programs (especially editors) update files atomically: it
|
||||
// will write to a temporary file which is then moved to to destination,
|
||||
// overwriting the original (or some variant thereof). The watcher on the
|
||||
// original file is now lost, as that no longer exists.
|
||||
//
|
||||
// The upshot of this is that a power failure or crash won't leave a
|
||||
// half-written file.
|
||||
//
|
||||
// Watch the parent directory and use Event.Name to filter out files you're not
|
||||
// interested in. There is an example of this in cmd/fsnotify/file.go.
|
||||
func (w *Watcher) Add(name string) error { return w.AddWith(name) }
|
||||
func (w *inotify) Add(name string) error { return w.AddWith(name) }
|
||||
|
||||
// AddWith is like [Watcher.Add], but allows adding options. When using Add()
|
||||
// the defaults described below are used.
|
||||
//
|
||||
// Possible options are:
|
||||
//
|
||||
// - [WithBufferSize] sets the buffer size for the Windows backend; no-op on
|
||||
// other platforms. The default is 64K (65536 bytes).
|
||||
func (w *Watcher) AddWith(name string, opts ...addOpt) error {
|
||||
func (w *inotify) AddWith(path string, opts ...addOpt) error {
|
||||
if w.isClosed() {
|
||||
return ErrClosed
|
||||
}
|
||||
if debug {
|
||||
fmt.Fprintf(os.Stderr, "FSNOTIFY_DEBUG: %s AddWith(%q)\n",
|
||||
time.Now().Format("15:04:05.000000000"), path)
|
||||
}
|
||||
|
||||
name = filepath.Clean(name)
|
||||
_ = getOptions(opts...)
|
||||
with := getOptions(opts...)
|
||||
if !w.xSupports(with.op) {
|
||||
return fmt.Errorf("%w: %s", xErrUnsupported, with.op)
|
||||
}
|
||||
|
||||
var flags uint32 = unix.IN_MOVED_TO | unix.IN_MOVED_FROM |
|
||||
unix.IN_CREATE | unix.IN_ATTRIB | unix.IN_MODIFY |
|
||||
unix.IN_MOVE_SELF | unix.IN_DELETE | unix.IN_DELETE_SELF
|
||||
path, recurse := recursivePath(path)
|
||||
if recurse {
|
||||
return filepath.WalkDir(path, func(root string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !d.IsDir() {
|
||||
if root == path {
|
||||
return fmt.Errorf("fsnotify: not a directory: %q", path)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
return w.watches.updatePath(name, func(existing *watch) (*watch, error) {
|
||||
// Send a Create event when adding new directory from a recursive
|
||||
// watch; this is for "mkdir -p one/two/three". Usually all those
|
||||
// directories will be created before we can set up watchers on the
|
||||
// subdirectories, so only "one" would be sent as a Create event and
|
||||
// not "one/two" and "one/two/three" (inotifywait -r has the same
|
||||
// problem).
|
||||
if with.sendCreate && root != path {
|
||||
w.sendEvent(Event{Name: root, Op: Create})
|
||||
}
|
||||
|
||||
return w.add(root, with, true)
|
||||
})
|
||||
}
|
||||
|
||||
return w.add(path, with, false)
|
||||
}
|
||||
|
||||
func (w *inotify) add(path string, with withOpts, recurse bool) error {
|
||||
var flags uint32
|
||||
if with.noFollow {
|
||||
flags |= unix.IN_DONT_FOLLOW
|
||||
}
|
||||
if with.op.Has(Create) {
|
||||
flags |= unix.IN_CREATE
|
||||
}
|
||||
if with.op.Has(Write) {
|
||||
flags |= unix.IN_MODIFY
|
||||
}
|
||||
if with.op.Has(Remove) {
|
||||
flags |= unix.IN_DELETE | unix.IN_DELETE_SELF
|
||||
}
|
||||
if with.op.Has(Rename) {
|
||||
flags |= unix.IN_MOVED_TO | unix.IN_MOVED_FROM | unix.IN_MOVE_SELF
|
||||
}
|
||||
if with.op.Has(Chmod) {
|
||||
flags |= unix.IN_ATTRIB
|
||||
}
|
||||
if with.op.Has(xUnportableOpen) {
|
||||
flags |= unix.IN_OPEN
|
||||
}
|
||||
if with.op.Has(xUnportableRead) {
|
||||
flags |= unix.IN_ACCESS
|
||||
}
|
||||
if with.op.Has(xUnportableCloseWrite) {
|
||||
flags |= unix.IN_CLOSE_WRITE
|
||||
}
|
||||
if with.op.Has(xUnportableCloseRead) {
|
||||
flags |= unix.IN_CLOSE_NOWRITE
|
||||
}
|
||||
return w.register(path, flags, recurse)
|
||||
}
|
||||
|
||||
func (w *inotify) register(path string, flags uint32, recurse bool) error {
|
||||
return w.watches.updatePath(path, func(existing *watch) (*watch, error) {
|
||||
if existing != nil {
|
||||
flags |= existing.flags | unix.IN_MASK_ADD
|
||||
}
|
||||
|
||||
wd, err := unix.InotifyAddWatch(w.fd, name, flags)
|
||||
wd, err := unix.InotifyAddWatch(w.fd, path, flags)
|
||||
if wd == -1 {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if existing == nil {
|
||||
return &watch{
|
||||
wd: uint32(wd),
|
||||
path: name,
|
||||
flags: flags,
|
||||
wd: uint32(wd),
|
||||
path: path,
|
||||
flags: flags,
|
||||
recurse: recurse,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
|
@ -404,49 +357,44 @@ func (w *Watcher) AddWith(name string, opts ...addOpt) error {
|
|||
})
|
||||
}
|
||||
|
||||
// Remove stops monitoring the path for changes.
|
||||
//
|
||||
// Directories are always removed non-recursively. For example, if you added
|
||||
// /tmp/dir and /tmp/dir/subdir then you will need to remove both.
|
||||
//
|
||||
// Removing a path that has not yet been added returns [ErrNonExistentWatch].
|
||||
//
|
||||
// Returns nil if [Watcher.Close] was called.
|
||||
func (w *Watcher) Remove(name string) error {
|
||||
func (w *inotify) Remove(name string) error {
|
||||
if w.isClosed() {
|
||||
return nil
|
||||
}
|
||||
if debug {
|
||||
fmt.Fprintf(os.Stderr, "FSNOTIFY_DEBUG: %s Remove(%q)\n",
|
||||
time.Now().Format("15:04:05.000000000"), name)
|
||||
}
|
||||
return w.remove(filepath.Clean(name))
|
||||
}
|
||||
|
||||
func (w *Watcher) remove(name string) error {
|
||||
wd, ok := w.watches.removePath(name)
|
||||
if !ok {
|
||||
return fmt.Errorf("%w: %s", ErrNonExistentWatch, name)
|
||||
func (w *inotify) remove(name string) error {
|
||||
wds, err := w.watches.removePath(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
success, errno := unix.InotifyRmWatch(w.fd, wd)
|
||||
if success == -1 {
|
||||
// TODO: Perhaps it's not helpful to return an error here in every case;
|
||||
// The only two possible errors are:
|
||||
//
|
||||
// - EBADF, which happens when w.fd is not a valid file descriptor
|
||||
// of any kind.
|
||||
// - EINVAL, which is when fd is not an inotify descriptor or wd
|
||||
// is not a valid watch descriptor. Watch descriptors are
|
||||
// invalidated when they are removed explicitly or implicitly;
|
||||
// explicitly by inotify_rm_watch, implicitly when the file they
|
||||
// are watching is deleted.
|
||||
return errno
|
||||
for _, wd := range wds {
|
||||
_, err := unix.InotifyRmWatch(w.fd, wd)
|
||||
if err != nil {
|
||||
// TODO: Perhaps it's not helpful to return an error here in every
|
||||
// case; the only two possible errors are:
|
||||
//
|
||||
// EBADF, which happens when w.fd is not a valid file descriptor of
|
||||
// any kind.
|
||||
//
|
||||
// EINVAL, which is when fd is not an inotify descriptor or wd is
|
||||
// not a valid watch descriptor. Watch descriptors are invalidated
|
||||
// when they are removed explicitly or implicitly; explicitly by
|
||||
// inotify_rm_watch, implicitly when the file they are watching is
|
||||
// deleted.
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// WatchList returns all paths explicitly added with [Watcher.Add] (and are not
|
||||
// yet removed).
|
||||
//
|
||||
// Returns nil if [Watcher.Close] was called.
|
||||
func (w *Watcher) WatchList() []string {
|
||||
func (w *inotify) WatchList() []string {
|
||||
if w.isClosed() {
|
||||
return nil
|
||||
}
|
||||
|
|
@ -463,7 +411,7 @@ func (w *Watcher) WatchList() []string {
|
|||
|
||||
// readEvents reads from the inotify file descriptor, converts the
|
||||
// received events into Event objects and sends them via the Events channel
|
||||
func (w *Watcher) readEvents() {
|
||||
func (w *inotify) readEvents() {
|
||||
defer func() {
|
||||
close(w.doneResp)
|
||||
close(w.Errors)
|
||||
|
|
@ -506,15 +454,17 @@ func (w *Watcher) readEvents() {
|
|||
continue
|
||||
}
|
||||
|
||||
var offset uint32
|
||||
// We don't know how many events we just read into the buffer
|
||||
// While the offset points to at least one whole event...
|
||||
var offset uint32
|
||||
for offset <= uint32(n-unix.SizeofInotifyEvent) {
|
||||
var (
|
||||
// Point "raw" to the event in the buffer
|
||||
raw = (*unix.InotifyEvent)(unsafe.Pointer(&buf[offset]))
|
||||
mask = uint32(raw.Mask)
|
||||
nameLen = uint32(raw.Len)
|
||||
// Move to the next event in the buffer
|
||||
next = func() { offset += unix.SizeofInotifyEvent + nameLen }
|
||||
)
|
||||
|
||||
if mask&unix.IN_Q_OVERFLOW != 0 {
|
||||
|
|
@ -523,21 +473,53 @@ func (w *Watcher) readEvents() {
|
|||
}
|
||||
}
|
||||
|
||||
// If the event happened to the watched directory or the watched file, the kernel
|
||||
// doesn't append the filename to the event, but we would like to always fill the
|
||||
// the "Name" field with a valid filename. We retrieve the path of the watch from
|
||||
// the "paths" map.
|
||||
/// If the event happened to the watched directory or the watched
|
||||
/// file, the kernel doesn't append the filename to the event, but
|
||||
/// we would like to always fill the the "Name" field with a valid
|
||||
/// filename. We retrieve the path of the watch from the "paths"
|
||||
/// map.
|
||||
watch := w.watches.byWd(uint32(raw.Wd))
|
||||
/// Can be nil if Remove() was called in another goroutine for this
|
||||
/// path inbetween reading the events from the kernel and reading
|
||||
/// the internal state. Not much we can do about it, so just skip.
|
||||
/// See #616.
|
||||
if watch == nil {
|
||||
next()
|
||||
continue
|
||||
}
|
||||
|
||||
name := watch.path
|
||||
if nameLen > 0 {
|
||||
/// Point "bytes" at the first byte of the filename
|
||||
bytes := (*[unix.PathMax]byte)(unsafe.Pointer(&buf[offset+unix.SizeofInotifyEvent]))[:nameLen:nameLen]
|
||||
/// The filename is padded with NULL bytes. TrimRight() gets rid of those.
|
||||
name += "/" + strings.TrimRight(string(bytes[0:nameLen]), "\000")
|
||||
}
|
||||
|
||||
if debug {
|
||||
internal.Debug(name, raw.Mask, raw.Cookie)
|
||||
}
|
||||
|
||||
if mask&unix.IN_IGNORED != 0 { //&& event.Op != 0
|
||||
next()
|
||||
continue
|
||||
}
|
||||
|
||||
// inotify will automatically remove the watch on deletes; just need
|
||||
// to clean our state here.
|
||||
if watch != nil && mask&unix.IN_DELETE_SELF == unix.IN_DELETE_SELF {
|
||||
if mask&unix.IN_DELETE_SELF == unix.IN_DELETE_SELF {
|
||||
w.watches.remove(watch.wd)
|
||||
}
|
||||
|
||||
// We can't really update the state when a watched path is moved;
|
||||
// only IN_MOVE_SELF is sent and not IN_MOVED_{FROM,TO}. So remove
|
||||
// the watch.
|
||||
if watch != nil && mask&unix.IN_MOVE_SELF == unix.IN_MOVE_SELF {
|
||||
if mask&unix.IN_MOVE_SELF == unix.IN_MOVE_SELF {
|
||||
if watch.recurse {
|
||||
next() // Do nothing
|
||||
continue
|
||||
}
|
||||
|
||||
err := w.remove(watch.path)
|
||||
if err != nil && !errors.Is(err, ErrNonExistentWatch) {
|
||||
if !w.sendError(err) {
|
||||
|
|
@ -546,34 +528,69 @@ func (w *Watcher) readEvents() {
|
|||
}
|
||||
}
|
||||
|
||||
var name string
|
||||
if watch != nil {
|
||||
name = watch.path
|
||||
}
|
||||
if nameLen > 0 {
|
||||
// Point "bytes" at the first byte of the filename
|
||||
bytes := (*[unix.PathMax]byte)(unsafe.Pointer(&buf[offset+unix.SizeofInotifyEvent]))[:nameLen:nameLen]
|
||||
// The filename is padded with NULL bytes. TrimRight() gets rid of those.
|
||||
name += "/" + strings.TrimRight(string(bytes[0:nameLen]), "\000")
|
||||
}
|
||||
|
||||
event := w.newEvent(name, mask)
|
||||
|
||||
// Send the events that are not ignored on the events channel
|
||||
if mask&unix.IN_IGNORED == 0 {
|
||||
if !w.sendEvent(event) {
|
||||
return
|
||||
/// Skip if we're watching both this path and the parent; the parent
|
||||
/// will already send a delete so no need to do it twice.
|
||||
if mask&unix.IN_DELETE_SELF != 0 {
|
||||
if _, ok := w.watches.path[filepath.Dir(watch.path)]; ok {
|
||||
next()
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// Move to the next event in the buffer
|
||||
offset += unix.SizeofInotifyEvent + nameLen
|
||||
ev := w.newEvent(name, mask, raw.Cookie)
|
||||
// Need to update watch path for recurse.
|
||||
if watch.recurse {
|
||||
isDir := mask&unix.IN_ISDIR == unix.IN_ISDIR
|
||||
/// New directory created: set up watch on it.
|
||||
if isDir && ev.Has(Create) {
|
||||
err := w.register(ev.Name, watch.flags, true)
|
||||
if !w.sendError(err) {
|
||||
return
|
||||
}
|
||||
|
||||
// This was a directory rename, so we need to update all
|
||||
// the children.
|
||||
//
|
||||
// TODO: this is of course pretty slow; we should use a
|
||||
// better data structure for storing all of this, e.g. store
|
||||
// children in the watch. I have some code for this in my
|
||||
// kqueue refactor we can use in the future. For now I'm
|
||||
// okay with this as it's not publicly available.
|
||||
// Correctness first, performance second.
|
||||
if ev.renamedFrom != "" {
|
||||
w.watches.mu.Lock()
|
||||
for k, ww := range w.watches.wd {
|
||||
if k == watch.wd || ww.path == ev.Name {
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(ww.path, ev.renamedFrom) {
|
||||
ww.path = strings.Replace(ww.path, ev.renamedFrom, ev.Name, 1)
|
||||
w.watches.wd[k] = ww
|
||||
}
|
||||
}
|
||||
w.watches.mu.Unlock()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Send the events that are not ignored on the events channel
|
||||
if !w.sendEvent(ev) {
|
||||
return
|
||||
}
|
||||
next()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// newEvent returns an platform-independent Event based on an inotify mask.
|
||||
func (w *Watcher) newEvent(name string, mask uint32) Event {
|
||||
func (w *inotify) isRecursive(path string) bool {
|
||||
ww := w.watches.byPath(path)
|
||||
if ww == nil { // path could be a file, so also check the Dir.
|
||||
ww = w.watches.byPath(filepath.Dir(path))
|
||||
}
|
||||
return ww != nil && ww.recurse
|
||||
}
|
||||
|
||||
func (w *inotify) newEvent(name string, mask, cookie uint32) Event {
|
||||
e := Event{Name: name}
|
||||
if mask&unix.IN_CREATE == unix.IN_CREATE || mask&unix.IN_MOVED_TO == unix.IN_MOVED_TO {
|
||||
e.Op |= Create
|
||||
|
|
@ -584,11 +601,58 @@ func (w *Watcher) newEvent(name string, mask uint32) Event {
|
|||
if mask&unix.IN_MODIFY == unix.IN_MODIFY {
|
||||
e.Op |= Write
|
||||
}
|
||||
if mask&unix.IN_OPEN == unix.IN_OPEN {
|
||||
e.Op |= xUnportableOpen
|
||||
}
|
||||
if mask&unix.IN_ACCESS == unix.IN_ACCESS {
|
||||
e.Op |= xUnportableRead
|
||||
}
|
||||
if mask&unix.IN_CLOSE_WRITE == unix.IN_CLOSE_WRITE {
|
||||
e.Op |= xUnportableCloseWrite
|
||||
}
|
||||
if mask&unix.IN_CLOSE_NOWRITE == unix.IN_CLOSE_NOWRITE {
|
||||
e.Op |= xUnportableCloseRead
|
||||
}
|
||||
if mask&unix.IN_MOVE_SELF == unix.IN_MOVE_SELF || mask&unix.IN_MOVED_FROM == unix.IN_MOVED_FROM {
|
||||
e.Op |= Rename
|
||||
}
|
||||
if mask&unix.IN_ATTRIB == unix.IN_ATTRIB {
|
||||
e.Op |= Chmod
|
||||
}
|
||||
|
||||
if cookie != 0 {
|
||||
if mask&unix.IN_MOVED_FROM == unix.IN_MOVED_FROM {
|
||||
w.cookiesMu.Lock()
|
||||
w.cookies[w.cookieIndex] = koekje{cookie: cookie, path: e.Name}
|
||||
w.cookieIndex++
|
||||
if w.cookieIndex > 9 {
|
||||
w.cookieIndex = 0
|
||||
}
|
||||
w.cookiesMu.Unlock()
|
||||
} else if mask&unix.IN_MOVED_TO == unix.IN_MOVED_TO {
|
||||
w.cookiesMu.Lock()
|
||||
var prev string
|
||||
for _, c := range w.cookies {
|
||||
if c.cookie == cookie {
|
||||
prev = c.path
|
||||
break
|
||||
}
|
||||
}
|
||||
w.cookiesMu.Unlock()
|
||||
e.renamedFrom = prev
|
||||
}
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
func (w *inotify) xSupports(op Op) bool {
|
||||
return true // Supports everything.
|
||||
}
|
||||
|
||||
func (w *inotify) state() {
|
||||
w.watches.mu.Lock()
|
||||
defer w.watches.mu.Unlock()
|
||||
for wd, ww := range w.watches.wd {
|
||||
fmt.Fprintf(os.Stderr, "%4d: recurse=%t %q\n", wd, ww.recurse, ww.path)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
747
vendor/github.com/fsnotify/fsnotify/backend_kqueue.go
generated
vendored
747
vendor/github.com/fsnotify/fsnotify/backend_kqueue.go
generated
vendored
File diff suppressed because it is too large
Load diff
204
vendor/github.com/fsnotify/fsnotify/backend_other.go
generated
vendored
204
vendor/github.com/fsnotify/fsnotify/backend_other.go
generated
vendored
|
|
@ -1,205 +1,23 @@
|
|||
//go:build appengine || (!darwin && !dragonfly && !freebsd && !openbsd && !linux && !netbsd && !solaris && !windows)
|
||||
// +build appengine !darwin,!dragonfly,!freebsd,!openbsd,!linux,!netbsd,!solaris,!windows
|
||||
|
||||
// Note: the documentation on the Watcher type and methods is generated from
|
||||
// mkdoc.zsh
|
||||
|
||||
package fsnotify
|
||||
|
||||
import "errors"
|
||||
|
||||
// Watcher watches a set of paths, delivering events on a channel.
|
||||
//
|
||||
// A watcher should not be copied (e.g. pass it by pointer, rather than by
|
||||
// value).
|
||||
//
|
||||
// # Linux notes
|
||||
//
|
||||
// When a file is removed a Remove event won't be emitted until all file
|
||||
// descriptors are closed, and deletes will always emit a Chmod. For example:
|
||||
//
|
||||
// fp := os.Open("file")
|
||||
// os.Remove("file") // Triggers Chmod
|
||||
// fp.Close() // Triggers Remove
|
||||
//
|
||||
// This is the event that inotify sends, so not much can be changed about this.
|
||||
//
|
||||
// The fs.inotify.max_user_watches sysctl variable specifies the upper limit
|
||||
// for the number of watches per user, and fs.inotify.max_user_instances
|
||||
// specifies the maximum number of inotify instances per user. Every Watcher you
|
||||
// create is an "instance", and every path you add is a "watch".
|
||||
//
|
||||
// These are also exposed in /proc as /proc/sys/fs/inotify/max_user_watches and
|
||||
// /proc/sys/fs/inotify/max_user_instances
|
||||
//
|
||||
// To increase them you can use sysctl or write the value to the /proc file:
|
||||
//
|
||||
// # Default values on Linux 5.18
|
||||
// sysctl fs.inotify.max_user_watches=124983
|
||||
// sysctl fs.inotify.max_user_instances=128
|
||||
//
|
||||
// To make the changes persist on reboot edit /etc/sysctl.conf or
|
||||
// /usr/lib/sysctl.d/50-default.conf (details differ per Linux distro; check
|
||||
// your distro's documentation):
|
||||
//
|
||||
// fs.inotify.max_user_watches=124983
|
||||
// fs.inotify.max_user_instances=128
|
||||
//
|
||||
// Reaching the limit will result in a "no space left on device" or "too many open
|
||||
// files" error.
|
||||
//
|
||||
// # kqueue notes (macOS, BSD)
|
||||
//
|
||||
// kqueue requires opening a file descriptor for every file that's being watched;
|
||||
// so if you're watching a directory with five files then that's six file
|
||||
// descriptors. You will run in to your system's "max open files" limit faster on
|
||||
// these platforms.
|
||||
//
|
||||
// The sysctl variables kern.maxfiles and kern.maxfilesperproc can be used to
|
||||
// control the maximum number of open files, as well as /etc/login.conf on BSD
|
||||
// systems.
|
||||
//
|
||||
// # Windows notes
|
||||
//
|
||||
// Paths can be added as "C:\path\to\dir", but forward slashes
|
||||
// ("C:/path/to/dir") will also work.
|
||||
//
|
||||
// When a watched directory is removed it will always send an event for the
|
||||
// directory itself, but may not send events for all files in that directory.
|
||||
// Sometimes it will send events for all times, sometimes it will send no
|
||||
// events, and often only for some files.
|
||||
//
|
||||
// The default ReadDirectoryChangesW() buffer size is 64K, which is the largest
|
||||
// value that is guaranteed to work with SMB filesystems. If you have many
|
||||
// events in quick succession this may not be enough, and you will have to use
|
||||
// [WithBufferSize] to increase the value.
|
||||
type Watcher struct {
|
||||
// Events sends the filesystem change events.
|
||||
//
|
||||
// fsnotify can send the following events; a "path" here can refer to a
|
||||
// file, directory, symbolic link, or special file like a FIFO.
|
||||
//
|
||||
// fsnotify.Create A new path was created; this may be followed by one
|
||||
// or more Write events if data also gets written to a
|
||||
// file.
|
||||
//
|
||||
// fsnotify.Remove A path was removed.
|
||||
//
|
||||
// fsnotify.Rename A path was renamed. A rename is always sent with the
|
||||
// old path as Event.Name, and a Create event will be
|
||||
// sent with the new name. Renames are only sent for
|
||||
// paths that are currently watched; e.g. moving an
|
||||
// unmonitored file into a monitored directory will
|
||||
// show up as just a Create. Similarly, renaming a file
|
||||
// to outside a monitored directory will show up as
|
||||
// only a Rename.
|
||||
//
|
||||
// fsnotify.Write A file or named pipe was written to. A Truncate will
|
||||
// also trigger a Write. A single "write action"
|
||||
// initiated by the user may show up as one or multiple
|
||||
// writes, depending on when the system syncs things to
|
||||
// disk. For example when compiling a large Go program
|
||||
// you may get hundreds of Write events, and you may
|
||||
// want to wait until you've stopped receiving them
|
||||
// (see the dedup example in cmd/fsnotify).
|
||||
//
|
||||
// Some systems may send Write event for directories
|
||||
// when the directory content changes.
|
||||
//
|
||||
// fsnotify.Chmod Attributes were changed. On Linux this is also sent
|
||||
// when a file is removed (or more accurately, when a
|
||||
// link to an inode is removed). On kqueue it's sent
|
||||
// when a file is truncated. On Windows it's never
|
||||
// sent.
|
||||
type other struct {
|
||||
Events chan Event
|
||||
|
||||
// Errors sends any errors.
|
||||
//
|
||||
// ErrEventOverflow is used to indicate there are too many events:
|
||||
//
|
||||
// - inotify: There are too many queued events (fs.inotify.max_queued_events sysctl)
|
||||
// - windows: The buffer size is too small; WithBufferSize() can be used to increase it.
|
||||
// - kqueue, fen: Not used.
|
||||
Errors chan error
|
||||
}
|
||||
|
||||
// NewWatcher creates a new Watcher.
|
||||
func NewWatcher() (*Watcher, error) {
|
||||
func newBackend(ev chan Event, errs chan error) (backend, error) {
|
||||
return nil, errors.New("fsnotify not supported on the current platform")
|
||||
}
|
||||
|
||||
// NewBufferedWatcher creates a new Watcher with a buffered Watcher.Events
|
||||
// channel.
|
||||
//
|
||||
// The main use case for this is situations with a very large number of events
|
||||
// where the kernel buffer size can't be increased (e.g. due to lack of
|
||||
// permissions). An unbuffered Watcher will perform better for almost all use
|
||||
// cases, and whenever possible you will be better off increasing the kernel
|
||||
// buffers instead of adding a large userspace buffer.
|
||||
func NewBufferedWatcher(sz uint) (*Watcher, error) { return NewWatcher() }
|
||||
|
||||
// Close removes all watches and closes the Events channel.
|
||||
func (w *Watcher) Close() error { return nil }
|
||||
|
||||
// WatchList returns all paths explicitly added with [Watcher.Add] (and are not
|
||||
// yet removed).
|
||||
//
|
||||
// Returns nil if [Watcher.Close] was called.
|
||||
func (w *Watcher) WatchList() []string { return nil }
|
||||
|
||||
// Add starts monitoring the path for changes.
|
||||
//
|
||||
// A path can only be watched once; watching it more than once is a no-op and will
|
||||
// not return an error. Paths that do not yet exist on the filesystem cannot be
|
||||
// watched.
|
||||
//
|
||||
// A watch will be automatically removed if the watched path is deleted or
|
||||
// renamed. The exception is the Windows backend, which doesn't remove the
|
||||
// watcher on renames.
|
||||
//
|
||||
// Notifications on network filesystems (NFS, SMB, FUSE, etc.) or special
|
||||
// filesystems (/proc, /sys, etc.) generally don't work.
|
||||
//
|
||||
// Returns [ErrClosed] if [Watcher.Close] was called.
|
||||
//
|
||||
// See [Watcher.AddWith] for a version that allows adding options.
|
||||
//
|
||||
// # Watching directories
|
||||
//
|
||||
// All files in a directory are monitored, including new files that are created
|
||||
// after the watcher is started. Subdirectories are not watched (i.e. it's
|
||||
// non-recursive).
|
||||
//
|
||||
// # Watching files
|
||||
//
|
||||
// Watching individual files (rather than directories) is generally not
|
||||
// recommended as many programs (especially editors) update files atomically: it
|
||||
// will write to a temporary file which is then moved to to destination,
|
||||
// overwriting the original (or some variant thereof). The watcher on the
|
||||
// original file is now lost, as that no longer exists.
|
||||
//
|
||||
// The upshot of this is that a power failure or crash won't leave a
|
||||
// half-written file.
|
||||
//
|
||||
// Watch the parent directory and use Event.Name to filter out files you're not
|
||||
// interested in. There is an example of this in cmd/fsnotify/file.go.
|
||||
func (w *Watcher) Add(name string) error { return nil }
|
||||
|
||||
// AddWith is like [Watcher.Add], but allows adding options. When using Add()
|
||||
// the defaults described below are used.
|
||||
//
|
||||
// Possible options are:
|
||||
//
|
||||
// - [WithBufferSize] sets the buffer size for the Windows backend; no-op on
|
||||
// other platforms. The default is 64K (65536 bytes).
|
||||
func (w *Watcher) AddWith(name string, opts ...addOpt) error { return nil }
|
||||
|
||||
// Remove stops monitoring the path for changes.
|
||||
//
|
||||
// Directories are always removed non-recursively. For example, if you added
|
||||
// /tmp/dir and /tmp/dir/subdir then you will need to remove both.
|
||||
//
|
||||
// Removing a path that has not yet been added returns [ErrNonExistentWatch].
|
||||
//
|
||||
// Returns nil if [Watcher.Close] was called.
|
||||
func (w *Watcher) Remove(name string) error { return nil }
|
||||
func newBufferedBackend(sz uint, ev chan Event, errs chan error) (backend, error) {
|
||||
return newBackend(ev, errs)
|
||||
}
|
||||
func (w *other) Close() error { return nil }
|
||||
func (w *other) WatchList() []string { return nil }
|
||||
func (w *other) Add(name string) error { return nil }
|
||||
func (w *other) AddWith(name string, opts ...addOpt) error { return nil }
|
||||
func (w *other) Remove(name string) error { return nil }
|
||||
func (w *other) xSupports(op Op) bool { return false }
|
||||
|
|
|
|||
305
vendor/github.com/fsnotify/fsnotify/backend_windows.go
generated
vendored
305
vendor/github.com/fsnotify/fsnotify/backend_windows.go
generated
vendored
|
|
@ -1,12 +1,8 @@
|
|||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
// Windows backend based on ReadDirectoryChangesW()
|
||||
//
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-readdirectorychangesw
|
||||
//
|
||||
// Note: the documentation on the Watcher type and methods is generated from
|
||||
// mkdoc.zsh
|
||||
|
||||
package fsnotify
|
||||
|
||||
|
|
@ -19,123 +15,15 @@ import (
|
|||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/fsnotify/fsnotify/internal"
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
// Watcher watches a set of paths, delivering events on a channel.
|
||||
//
|
||||
// A watcher should not be copied (e.g. pass it by pointer, rather than by
|
||||
// value).
|
||||
//
|
||||
// # Linux notes
|
||||
//
|
||||
// When a file is removed a Remove event won't be emitted until all file
|
||||
// descriptors are closed, and deletes will always emit a Chmod. For example:
|
||||
//
|
||||
// fp := os.Open("file")
|
||||
// os.Remove("file") // Triggers Chmod
|
||||
// fp.Close() // Triggers Remove
|
||||
//
|
||||
// This is the event that inotify sends, so not much can be changed about this.
|
||||
//
|
||||
// The fs.inotify.max_user_watches sysctl variable specifies the upper limit
|
||||
// for the number of watches per user, and fs.inotify.max_user_instances
|
||||
// specifies the maximum number of inotify instances per user. Every Watcher you
|
||||
// create is an "instance", and every path you add is a "watch".
|
||||
//
|
||||
// These are also exposed in /proc as /proc/sys/fs/inotify/max_user_watches and
|
||||
// /proc/sys/fs/inotify/max_user_instances
|
||||
//
|
||||
// To increase them you can use sysctl or write the value to the /proc file:
|
||||
//
|
||||
// # Default values on Linux 5.18
|
||||
// sysctl fs.inotify.max_user_watches=124983
|
||||
// sysctl fs.inotify.max_user_instances=128
|
||||
//
|
||||
// To make the changes persist on reboot edit /etc/sysctl.conf or
|
||||
// /usr/lib/sysctl.d/50-default.conf (details differ per Linux distro; check
|
||||
// your distro's documentation):
|
||||
//
|
||||
// fs.inotify.max_user_watches=124983
|
||||
// fs.inotify.max_user_instances=128
|
||||
//
|
||||
// Reaching the limit will result in a "no space left on device" or "too many open
|
||||
// files" error.
|
||||
//
|
||||
// # kqueue notes (macOS, BSD)
|
||||
//
|
||||
// kqueue requires opening a file descriptor for every file that's being watched;
|
||||
// so if you're watching a directory with five files then that's six file
|
||||
// descriptors. You will run in to your system's "max open files" limit faster on
|
||||
// these platforms.
|
||||
//
|
||||
// The sysctl variables kern.maxfiles and kern.maxfilesperproc can be used to
|
||||
// control the maximum number of open files, as well as /etc/login.conf on BSD
|
||||
// systems.
|
||||
//
|
||||
// # Windows notes
|
||||
//
|
||||
// Paths can be added as "C:\path\to\dir", but forward slashes
|
||||
// ("C:/path/to/dir") will also work.
|
||||
//
|
||||
// When a watched directory is removed it will always send an event for the
|
||||
// directory itself, but may not send events for all files in that directory.
|
||||
// Sometimes it will send events for all times, sometimes it will send no
|
||||
// events, and often only for some files.
|
||||
//
|
||||
// The default ReadDirectoryChangesW() buffer size is 64K, which is the largest
|
||||
// value that is guaranteed to work with SMB filesystems. If you have many
|
||||
// events in quick succession this may not be enough, and you will have to use
|
||||
// [WithBufferSize] to increase the value.
|
||||
type Watcher struct {
|
||||
// Events sends the filesystem change events.
|
||||
//
|
||||
// fsnotify can send the following events; a "path" here can refer to a
|
||||
// file, directory, symbolic link, or special file like a FIFO.
|
||||
//
|
||||
// fsnotify.Create A new path was created; this may be followed by one
|
||||
// or more Write events if data also gets written to a
|
||||
// file.
|
||||
//
|
||||
// fsnotify.Remove A path was removed.
|
||||
//
|
||||
// fsnotify.Rename A path was renamed. A rename is always sent with the
|
||||
// old path as Event.Name, and a Create event will be
|
||||
// sent with the new name. Renames are only sent for
|
||||
// paths that are currently watched; e.g. moving an
|
||||
// unmonitored file into a monitored directory will
|
||||
// show up as just a Create. Similarly, renaming a file
|
||||
// to outside a monitored directory will show up as
|
||||
// only a Rename.
|
||||
//
|
||||
// fsnotify.Write A file or named pipe was written to. A Truncate will
|
||||
// also trigger a Write. A single "write action"
|
||||
// initiated by the user may show up as one or multiple
|
||||
// writes, depending on when the system syncs things to
|
||||
// disk. For example when compiling a large Go program
|
||||
// you may get hundreds of Write events, and you may
|
||||
// want to wait until you've stopped receiving them
|
||||
// (see the dedup example in cmd/fsnotify).
|
||||
//
|
||||
// Some systems may send Write event for directories
|
||||
// when the directory content changes.
|
||||
//
|
||||
// fsnotify.Chmod Attributes were changed. On Linux this is also sent
|
||||
// when a file is removed (or more accurately, when a
|
||||
// link to an inode is removed). On kqueue it's sent
|
||||
// when a file is truncated. On Windows it's never
|
||||
// sent.
|
||||
type readDirChangesW struct {
|
||||
Events chan Event
|
||||
|
||||
// Errors sends any errors.
|
||||
//
|
||||
// ErrEventOverflow is used to indicate there are too many events:
|
||||
//
|
||||
// - inotify: There are too many queued events (fs.inotify.max_queued_events sysctl)
|
||||
// - windows: The buffer size is too small; WithBufferSize() can be used to increase it.
|
||||
// - kqueue, fen: Not used.
|
||||
Errors chan error
|
||||
|
||||
port windows.Handle // Handle to completion port
|
||||
|
|
@ -147,48 +35,40 @@ type Watcher struct {
|
|||
closed bool // Set to true when Close() is first called
|
||||
}
|
||||
|
||||
// NewWatcher creates a new Watcher.
|
||||
func NewWatcher() (*Watcher, error) {
|
||||
return NewBufferedWatcher(50)
|
||||
func newBackend(ev chan Event, errs chan error) (backend, error) {
|
||||
return newBufferedBackend(50, ev, errs)
|
||||
}
|
||||
|
||||
// NewBufferedWatcher creates a new Watcher with a buffered Watcher.Events
|
||||
// channel.
|
||||
//
|
||||
// The main use case for this is situations with a very large number of events
|
||||
// where the kernel buffer size can't be increased (e.g. due to lack of
|
||||
// permissions). An unbuffered Watcher will perform better for almost all use
|
||||
// cases, and whenever possible you will be better off increasing the kernel
|
||||
// buffers instead of adding a large userspace buffer.
|
||||
func NewBufferedWatcher(sz uint) (*Watcher, error) {
|
||||
func newBufferedBackend(sz uint, ev chan Event, errs chan error) (backend, error) {
|
||||
port, err := windows.CreateIoCompletionPort(windows.InvalidHandle, 0, 0, 0)
|
||||
if err != nil {
|
||||
return nil, os.NewSyscallError("CreateIoCompletionPort", err)
|
||||
}
|
||||
w := &Watcher{
|
||||
w := &readDirChangesW{
|
||||
Events: ev,
|
||||
Errors: errs,
|
||||
port: port,
|
||||
watches: make(watchMap),
|
||||
input: make(chan *input, 1),
|
||||
Events: make(chan Event, sz),
|
||||
Errors: make(chan error),
|
||||
quit: make(chan chan<- error, 1),
|
||||
}
|
||||
go w.readEvents()
|
||||
return w, nil
|
||||
}
|
||||
|
||||
func (w *Watcher) isClosed() bool {
|
||||
func (w *readDirChangesW) isClosed() bool {
|
||||
w.mu.Lock()
|
||||
defer w.mu.Unlock()
|
||||
return w.closed
|
||||
}
|
||||
|
||||
func (w *Watcher) sendEvent(name string, mask uint64) bool {
|
||||
func (w *readDirChangesW) sendEvent(name, renamedFrom string, mask uint64) bool {
|
||||
if mask == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
event := w.newEvent(name, uint32(mask))
|
||||
event.renamedFrom = renamedFrom
|
||||
select {
|
||||
case ch := <-w.quit:
|
||||
w.quit <- ch
|
||||
|
|
@ -198,17 +78,19 @@ func (w *Watcher) sendEvent(name string, mask uint64) bool {
|
|||
}
|
||||
|
||||
// Returns true if the error was sent, or false if watcher is closed.
|
||||
func (w *Watcher) sendError(err error) bool {
|
||||
func (w *readDirChangesW) sendError(err error) bool {
|
||||
if err == nil {
|
||||
return true
|
||||
}
|
||||
select {
|
||||
case w.Errors <- err:
|
||||
return true
|
||||
case <-w.quit:
|
||||
return false
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Close removes all watches and closes the Events channel.
|
||||
func (w *Watcher) Close() error {
|
||||
func (w *readDirChangesW) Close() error {
|
||||
if w.isClosed() {
|
||||
return nil
|
||||
}
|
||||
|
|
@ -226,57 +108,21 @@ func (w *Watcher) Close() error {
|
|||
return <-ch
|
||||
}
|
||||
|
||||
// Add starts monitoring the path for changes.
|
||||
//
|
||||
// A path can only be watched once; watching it more than once is a no-op and will
|
||||
// not return an error. Paths that do not yet exist on the filesystem cannot be
|
||||
// watched.
|
||||
//
|
||||
// A watch will be automatically removed if the watched path is deleted or
|
||||
// renamed. The exception is the Windows backend, which doesn't remove the
|
||||
// watcher on renames.
|
||||
//
|
||||
// Notifications on network filesystems (NFS, SMB, FUSE, etc.) or special
|
||||
// filesystems (/proc, /sys, etc.) generally don't work.
|
||||
//
|
||||
// Returns [ErrClosed] if [Watcher.Close] was called.
|
||||
//
|
||||
// See [Watcher.AddWith] for a version that allows adding options.
|
||||
//
|
||||
// # Watching directories
|
||||
//
|
||||
// All files in a directory are monitored, including new files that are created
|
||||
// after the watcher is started. Subdirectories are not watched (i.e. it's
|
||||
// non-recursive).
|
||||
//
|
||||
// # Watching files
|
||||
//
|
||||
// Watching individual files (rather than directories) is generally not
|
||||
// recommended as many programs (especially editors) update files atomically: it
|
||||
// will write to a temporary file which is then moved to to destination,
|
||||
// overwriting the original (or some variant thereof). The watcher on the
|
||||
// original file is now lost, as that no longer exists.
|
||||
//
|
||||
// The upshot of this is that a power failure or crash won't leave a
|
||||
// half-written file.
|
||||
//
|
||||
// Watch the parent directory and use Event.Name to filter out files you're not
|
||||
// interested in. There is an example of this in cmd/fsnotify/file.go.
|
||||
func (w *Watcher) Add(name string) error { return w.AddWith(name) }
|
||||
func (w *readDirChangesW) Add(name string) error { return w.AddWith(name) }
|
||||
|
||||
// AddWith is like [Watcher.Add], but allows adding options. When using Add()
|
||||
// the defaults described below are used.
|
||||
//
|
||||
// Possible options are:
|
||||
//
|
||||
// - [WithBufferSize] sets the buffer size for the Windows backend; no-op on
|
||||
// other platforms. The default is 64K (65536 bytes).
|
||||
func (w *Watcher) AddWith(name string, opts ...addOpt) error {
|
||||
func (w *readDirChangesW) AddWith(name string, opts ...addOpt) error {
|
||||
if w.isClosed() {
|
||||
return ErrClosed
|
||||
}
|
||||
if debug {
|
||||
fmt.Fprintf(os.Stderr, "FSNOTIFY_DEBUG: %s AddWith(%q)\n",
|
||||
time.Now().Format("15:04:05.000000000"), filepath.ToSlash(name))
|
||||
}
|
||||
|
||||
with := getOptions(opts...)
|
||||
if !w.xSupports(with.op) {
|
||||
return fmt.Errorf("%w: %s", xErrUnsupported, with.op)
|
||||
}
|
||||
if with.bufsize < 4096 {
|
||||
return fmt.Errorf("fsnotify.WithBufferSize: buffer size cannot be smaller than 4096 bytes")
|
||||
}
|
||||
|
|
@ -295,18 +141,14 @@ func (w *Watcher) AddWith(name string, opts ...addOpt) error {
|
|||
return <-in.reply
|
||||
}
|
||||
|
||||
// Remove stops monitoring the path for changes.
|
||||
//
|
||||
// Directories are always removed non-recursively. For example, if you added
|
||||
// /tmp/dir and /tmp/dir/subdir then you will need to remove both.
|
||||
//
|
||||
// Removing a path that has not yet been added returns [ErrNonExistentWatch].
|
||||
//
|
||||
// Returns nil if [Watcher.Close] was called.
|
||||
func (w *Watcher) Remove(name string) error {
|
||||
func (w *readDirChangesW) Remove(name string) error {
|
||||
if w.isClosed() {
|
||||
return nil
|
||||
}
|
||||
if debug {
|
||||
fmt.Fprintf(os.Stderr, "FSNOTIFY_DEBUG: %s Remove(%q)\n",
|
||||
time.Now().Format("15:04:05.000000000"), filepath.ToSlash(name))
|
||||
}
|
||||
|
||||
in := &input{
|
||||
op: opRemoveWatch,
|
||||
|
|
@ -320,11 +162,7 @@ func (w *Watcher) Remove(name string) error {
|
|||
return <-in.reply
|
||||
}
|
||||
|
||||
// WatchList returns all paths explicitly added with [Watcher.Add] (and are not
|
||||
// yet removed).
|
||||
//
|
||||
// Returns nil if [Watcher.Close] was called.
|
||||
func (w *Watcher) WatchList() []string {
|
||||
func (w *readDirChangesW) WatchList() []string {
|
||||
if w.isClosed() {
|
||||
return nil
|
||||
}
|
||||
|
|
@ -335,7 +173,13 @@ func (w *Watcher) WatchList() []string {
|
|||
entries := make([]string, 0, len(w.watches))
|
||||
for _, entry := range w.watches {
|
||||
for _, watchEntry := range entry {
|
||||
entries = append(entries, watchEntry.path)
|
||||
for name := range watchEntry.names {
|
||||
entries = append(entries, filepath.Join(watchEntry.path, name))
|
||||
}
|
||||
// the directory itself is being watched
|
||||
if watchEntry.mask != 0 {
|
||||
entries = append(entries, watchEntry.path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -361,7 +205,7 @@ const (
|
|||
sysFSIGNORED = 0x8000
|
||||
)
|
||||
|
||||
func (w *Watcher) newEvent(name string, mask uint32) Event {
|
||||
func (w *readDirChangesW) newEvent(name string, mask uint32) Event {
|
||||
e := Event{Name: name}
|
||||
if mask&sysFSCREATE == sysFSCREATE || mask&sysFSMOVEDTO == sysFSMOVEDTO {
|
||||
e.Op |= Create
|
||||
|
|
@ -417,7 +261,7 @@ type (
|
|||
watchMap map[uint32]indexMap
|
||||
)
|
||||
|
||||
func (w *Watcher) wakeupReader() error {
|
||||
func (w *readDirChangesW) wakeupReader() error {
|
||||
err := windows.PostQueuedCompletionStatus(w.port, 0, 0, nil)
|
||||
if err != nil {
|
||||
return os.NewSyscallError("PostQueuedCompletionStatus", err)
|
||||
|
|
@ -425,7 +269,7 @@ func (w *Watcher) wakeupReader() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (w *Watcher) getDir(pathname string) (dir string, err error) {
|
||||
func (w *readDirChangesW) getDir(pathname string) (dir string, err error) {
|
||||
attr, err := windows.GetFileAttributes(windows.StringToUTF16Ptr(pathname))
|
||||
if err != nil {
|
||||
return "", os.NewSyscallError("GetFileAttributes", err)
|
||||
|
|
@ -439,7 +283,7 @@ func (w *Watcher) getDir(pathname string) (dir string, err error) {
|
|||
return
|
||||
}
|
||||
|
||||
func (w *Watcher) getIno(path string) (ino *inode, err error) {
|
||||
func (w *readDirChangesW) getIno(path string) (ino *inode, err error) {
|
||||
h, err := windows.CreateFile(windows.StringToUTF16Ptr(path),
|
||||
windows.FILE_LIST_DIRECTORY,
|
||||
windows.FILE_SHARE_READ|windows.FILE_SHARE_WRITE|windows.FILE_SHARE_DELETE,
|
||||
|
|
@ -482,9 +326,8 @@ func (m watchMap) set(ino *inode, watch *watch) {
|
|||
}
|
||||
|
||||
// Must run within the I/O thread.
|
||||
func (w *Watcher) addWatch(pathname string, flags uint64, bufsize int) error {
|
||||
//pathname, recurse := recursivePath(pathname)
|
||||
recurse := false
|
||||
func (w *readDirChangesW) addWatch(pathname string, flags uint64, bufsize int) error {
|
||||
pathname, recurse := recursivePath(pathname)
|
||||
|
||||
dir, err := w.getDir(pathname)
|
||||
if err != nil {
|
||||
|
|
@ -538,7 +381,7 @@ func (w *Watcher) addWatch(pathname string, flags uint64, bufsize int) error {
|
|||
}
|
||||
|
||||
// Must run within the I/O thread.
|
||||
func (w *Watcher) remWatch(pathname string) error {
|
||||
func (w *readDirChangesW) remWatch(pathname string) error {
|
||||
pathname, recurse := recursivePath(pathname)
|
||||
|
||||
dir, err := w.getDir(pathname)
|
||||
|
|
@ -566,11 +409,11 @@ func (w *Watcher) remWatch(pathname string) error {
|
|||
return fmt.Errorf("%w: %s", ErrNonExistentWatch, pathname)
|
||||
}
|
||||
if pathname == dir {
|
||||
w.sendEvent(watch.path, watch.mask&sysFSIGNORED)
|
||||
w.sendEvent(watch.path, "", watch.mask&sysFSIGNORED)
|
||||
watch.mask = 0
|
||||
} else {
|
||||
name := filepath.Base(pathname)
|
||||
w.sendEvent(filepath.Join(watch.path, name), watch.names[name]&sysFSIGNORED)
|
||||
w.sendEvent(filepath.Join(watch.path, name), "", watch.names[name]&sysFSIGNORED)
|
||||
delete(watch.names, name)
|
||||
}
|
||||
|
||||
|
|
@ -578,23 +421,23 @@ func (w *Watcher) remWatch(pathname string) error {
|
|||
}
|
||||
|
||||
// Must run within the I/O thread.
|
||||
func (w *Watcher) deleteWatch(watch *watch) {
|
||||
func (w *readDirChangesW) deleteWatch(watch *watch) {
|
||||
for name, mask := range watch.names {
|
||||
if mask&provisional == 0 {
|
||||
w.sendEvent(filepath.Join(watch.path, name), mask&sysFSIGNORED)
|
||||
w.sendEvent(filepath.Join(watch.path, name), "", mask&sysFSIGNORED)
|
||||
}
|
||||
delete(watch.names, name)
|
||||
}
|
||||
if watch.mask != 0 {
|
||||
if watch.mask&provisional == 0 {
|
||||
w.sendEvent(watch.path, watch.mask&sysFSIGNORED)
|
||||
w.sendEvent(watch.path, "", watch.mask&sysFSIGNORED)
|
||||
}
|
||||
watch.mask = 0
|
||||
}
|
||||
}
|
||||
|
||||
// Must run within the I/O thread.
|
||||
func (w *Watcher) startRead(watch *watch) error {
|
||||
func (w *readDirChangesW) startRead(watch *watch) error {
|
||||
err := windows.CancelIo(watch.ino.handle)
|
||||
if err != nil {
|
||||
w.sendError(os.NewSyscallError("CancelIo", err))
|
||||
|
|
@ -624,7 +467,7 @@ func (w *Watcher) startRead(watch *watch) error {
|
|||
err := os.NewSyscallError("ReadDirectoryChanges", rdErr)
|
||||
if rdErr == windows.ERROR_ACCESS_DENIED && watch.mask&provisional == 0 {
|
||||
// Watched directory was probably removed
|
||||
w.sendEvent(watch.path, watch.mask&sysFSDELETESELF)
|
||||
w.sendEvent(watch.path, "", watch.mask&sysFSDELETESELF)
|
||||
err = nil
|
||||
}
|
||||
w.deleteWatch(watch)
|
||||
|
|
@ -637,7 +480,7 @@ func (w *Watcher) startRead(watch *watch) error {
|
|||
// readEvents reads from the I/O completion port, converts the
|
||||
// received events into Event objects and sends them via the Events channel.
|
||||
// Entry point to the I/O thread.
|
||||
func (w *Watcher) readEvents() {
|
||||
func (w *readDirChangesW) readEvents() {
|
||||
var (
|
||||
n uint32
|
||||
key uintptr
|
||||
|
|
@ -700,7 +543,7 @@ func (w *Watcher) readEvents() {
|
|||
}
|
||||
case windows.ERROR_ACCESS_DENIED:
|
||||
// Watched directory was probably removed
|
||||
w.sendEvent(watch.path, watch.mask&sysFSDELETESELF)
|
||||
w.sendEvent(watch.path, "", watch.mask&sysFSDELETESELF)
|
||||
w.deleteWatch(watch)
|
||||
w.startRead(watch)
|
||||
continue
|
||||
|
|
@ -733,6 +576,10 @@ func (w *Watcher) readEvents() {
|
|||
name := windows.UTF16ToString(buf)
|
||||
fullname := filepath.Join(watch.path, name)
|
||||
|
||||
if debug {
|
||||
internal.Debug(fullname, raw.Action)
|
||||
}
|
||||
|
||||
var mask uint64
|
||||
switch raw.Action {
|
||||
case windows.FILE_ACTION_REMOVED:
|
||||
|
|
@ -761,21 +608,22 @@ func (w *Watcher) readEvents() {
|
|||
}
|
||||
}
|
||||
|
||||
sendNameEvent := func() {
|
||||
w.sendEvent(fullname, watch.names[name]&mask)
|
||||
}
|
||||
if raw.Action != windows.FILE_ACTION_RENAMED_NEW_NAME {
|
||||
sendNameEvent()
|
||||
w.sendEvent(fullname, "", watch.names[name]&mask)
|
||||
}
|
||||
if raw.Action == windows.FILE_ACTION_REMOVED {
|
||||
w.sendEvent(fullname, watch.names[name]&sysFSIGNORED)
|
||||
w.sendEvent(fullname, "", watch.names[name]&sysFSIGNORED)
|
||||
delete(watch.names, name)
|
||||
}
|
||||
|
||||
w.sendEvent(fullname, watch.mask&w.toFSnotifyFlags(raw.Action))
|
||||
if watch.rename != "" && raw.Action == windows.FILE_ACTION_RENAMED_NEW_NAME {
|
||||
w.sendEvent(fullname, filepath.Join(watch.path, watch.rename), watch.mask&w.toFSnotifyFlags(raw.Action))
|
||||
} else {
|
||||
w.sendEvent(fullname, "", watch.mask&w.toFSnotifyFlags(raw.Action))
|
||||
}
|
||||
|
||||
if raw.Action == windows.FILE_ACTION_RENAMED_NEW_NAME {
|
||||
fullname = filepath.Join(watch.path, watch.rename)
|
||||
sendNameEvent()
|
||||
w.sendEvent(filepath.Join(watch.path, watch.rename), "", watch.names[name]&mask)
|
||||
}
|
||||
|
||||
// Move to the next event in the buffer
|
||||
|
|
@ -787,8 +635,7 @@ func (w *Watcher) readEvents() {
|
|||
// Error!
|
||||
if offset >= n {
|
||||
//lint:ignore ST1005 Windows should be capitalized
|
||||
w.sendError(errors.New(
|
||||
"Windows system assumed buffer larger than it is, events have likely been missed"))
|
||||
w.sendError(errors.New("Windows system assumed buffer larger than it is, events have likely been missed"))
|
||||
break
|
||||
}
|
||||
}
|
||||
|
|
@ -799,7 +646,7 @@ func (w *Watcher) readEvents() {
|
|||
}
|
||||
}
|
||||
|
||||
func (w *Watcher) toWindowsFlags(mask uint64) uint32 {
|
||||
func (w *readDirChangesW) toWindowsFlags(mask uint64) uint32 {
|
||||
var m uint32
|
||||
if mask&sysFSMODIFY != 0 {
|
||||
m |= windows.FILE_NOTIFY_CHANGE_LAST_WRITE
|
||||
|
|
@ -810,7 +657,7 @@ func (w *Watcher) toWindowsFlags(mask uint64) uint32 {
|
|||
return m
|
||||
}
|
||||
|
||||
func (w *Watcher) toFSnotifyFlags(action uint32) uint64 {
|
||||
func (w *readDirChangesW) toFSnotifyFlags(action uint32) uint64 {
|
||||
switch action {
|
||||
case windows.FILE_ACTION_ADDED:
|
||||
return sysFSCREATE
|
||||
|
|
@ -825,3 +672,11 @@ func (w *Watcher) toFSnotifyFlags(action uint32) uint64 {
|
|||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (w *readDirChangesW) xSupports(op Op) bool {
|
||||
if op.Has(xUnportableOpen) || op.Has(xUnportableRead) ||
|
||||
op.Has(xUnportableCloseWrite) || op.Has(xUnportableCloseRead) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
|
|
|||
368
vendor/github.com/fsnotify/fsnotify/fsnotify.go
generated
vendored
368
vendor/github.com/fsnotify/fsnotify/fsnotify.go
generated
vendored
|
|
@ -3,19 +3,146 @@
|
|||
//
|
||||
// Currently supported systems:
|
||||
//
|
||||
// Linux 2.6.32+ via inotify
|
||||
// BSD, macOS via kqueue
|
||||
// Windows via ReadDirectoryChangesW
|
||||
// illumos via FEN
|
||||
// - Linux via inotify
|
||||
// - BSD, macOS via kqueue
|
||||
// - Windows via ReadDirectoryChangesW
|
||||
// - illumos via FEN
|
||||
//
|
||||
// # FSNOTIFY_DEBUG
|
||||
//
|
||||
// Set the FSNOTIFY_DEBUG environment variable to "1" to print debug messages to
|
||||
// stderr. This can be useful to track down some problems, especially in cases
|
||||
// where fsnotify is used as an indirect dependency.
|
||||
//
|
||||
// Every event will be printed as soon as there's something useful to print,
|
||||
// with as little processing from fsnotify.
|
||||
//
|
||||
// Example output:
|
||||
//
|
||||
// FSNOTIFY_DEBUG: 11:34:23.633087586 256:IN_CREATE → "/tmp/file-1"
|
||||
// FSNOTIFY_DEBUG: 11:34:23.633202319 4:IN_ATTRIB → "/tmp/file-1"
|
||||
// FSNOTIFY_DEBUG: 11:34:28.989728764 512:IN_DELETE → "/tmp/file-1"
|
||||
package fsnotify
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Watcher watches a set of paths, delivering events on a channel.
|
||||
//
|
||||
// A watcher should not be copied (e.g. pass it by pointer, rather than by
|
||||
// value).
|
||||
//
|
||||
// # Linux notes
|
||||
//
|
||||
// When a file is removed a Remove event won't be emitted until all file
|
||||
// descriptors are closed, and deletes will always emit a Chmod. For example:
|
||||
//
|
||||
// fp := os.Open("file")
|
||||
// os.Remove("file") // Triggers Chmod
|
||||
// fp.Close() // Triggers Remove
|
||||
//
|
||||
// This is the event that inotify sends, so not much can be changed about this.
|
||||
//
|
||||
// The fs.inotify.max_user_watches sysctl variable specifies the upper limit
|
||||
// for the number of watches per user, and fs.inotify.max_user_instances
|
||||
// specifies the maximum number of inotify instances per user. Every Watcher you
|
||||
// create is an "instance", and every path you add is a "watch".
|
||||
//
|
||||
// These are also exposed in /proc as /proc/sys/fs/inotify/max_user_watches and
|
||||
// /proc/sys/fs/inotify/max_user_instances
|
||||
//
|
||||
// To increase them you can use sysctl or write the value to the /proc file:
|
||||
//
|
||||
// # Default values on Linux 5.18
|
||||
// sysctl fs.inotify.max_user_watches=124983
|
||||
// sysctl fs.inotify.max_user_instances=128
|
||||
//
|
||||
// To make the changes persist on reboot edit /etc/sysctl.conf or
|
||||
// /usr/lib/sysctl.d/50-default.conf (details differ per Linux distro; check
|
||||
// your distro's documentation):
|
||||
//
|
||||
// fs.inotify.max_user_watches=124983
|
||||
// fs.inotify.max_user_instances=128
|
||||
//
|
||||
// Reaching the limit will result in a "no space left on device" or "too many open
|
||||
// files" error.
|
||||
//
|
||||
// # kqueue notes (macOS, BSD)
|
||||
//
|
||||
// kqueue requires opening a file descriptor for every file that's being watched;
|
||||
// so if you're watching a directory with five files then that's six file
|
||||
// descriptors. You will run in to your system's "max open files" limit faster on
|
||||
// these platforms.
|
||||
//
|
||||
// The sysctl variables kern.maxfiles and kern.maxfilesperproc can be used to
|
||||
// control the maximum number of open files, as well as /etc/login.conf on BSD
|
||||
// systems.
|
||||
//
|
||||
// # Windows notes
|
||||
//
|
||||
// Paths can be added as "C:\\path\\to\\dir", but forward slashes
|
||||
// ("C:/path/to/dir") will also work.
|
||||
//
|
||||
// When a watched directory is removed it will always send an event for the
|
||||
// directory itself, but may not send events for all files in that directory.
|
||||
// Sometimes it will send events for all files, sometimes it will send no
|
||||
// events, and often only for some files.
|
||||
//
|
||||
// The default ReadDirectoryChangesW() buffer size is 64K, which is the largest
|
||||
// value that is guaranteed to work with SMB filesystems. If you have many
|
||||
// events in quick succession this may not be enough, and you will have to use
|
||||
// [WithBufferSize] to increase the value.
|
||||
type Watcher struct {
|
||||
b backend
|
||||
|
||||
// Events sends the filesystem change events.
|
||||
//
|
||||
// fsnotify can send the following events; a "path" here can refer to a
|
||||
// file, directory, symbolic link, or special file like a FIFO.
|
||||
//
|
||||
// fsnotify.Create A new path was created; this may be followed by one
|
||||
// or more Write events if data also gets written to a
|
||||
// file.
|
||||
//
|
||||
// fsnotify.Remove A path was removed.
|
||||
//
|
||||
// fsnotify.Rename A path was renamed. A rename is always sent with the
|
||||
// old path as Event.Name, and a Create event will be
|
||||
// sent with the new name. Renames are only sent for
|
||||
// paths that are currently watched; e.g. moving an
|
||||
// unmonitored file into a monitored directory will
|
||||
// show up as just a Create. Similarly, renaming a file
|
||||
// to outside a monitored directory will show up as
|
||||
// only a Rename.
|
||||
//
|
||||
// fsnotify.Write A file or named pipe was written to. A Truncate will
|
||||
// also trigger a Write. A single "write action"
|
||||
// initiated by the user may show up as one or multiple
|
||||
// writes, depending on when the system syncs things to
|
||||
// disk. For example when compiling a large Go program
|
||||
// you may get hundreds of Write events, and you may
|
||||
// want to wait until you've stopped receiving them
|
||||
// (see the dedup example in cmd/fsnotify).
|
||||
//
|
||||
// Some systems may send Write event for directories
|
||||
// when the directory content changes.
|
||||
//
|
||||
// fsnotify.Chmod Attributes were changed. On Linux this is also sent
|
||||
// when a file is removed (or more accurately, when a
|
||||
// link to an inode is removed). On kqueue it's sent
|
||||
// when a file is truncated. On Windows it's never
|
||||
// sent.
|
||||
Events chan Event
|
||||
|
||||
// Errors sends any errors.
|
||||
Errors chan error
|
||||
}
|
||||
|
||||
// Event represents a file system notification.
|
||||
type Event struct {
|
||||
// Path to the file or directory.
|
||||
|
|
@ -30,6 +157,16 @@ type Event struct {
|
|||
// This is a bitmask and some systems may send multiple operations at once.
|
||||
// Use the Event.Has() method instead of comparing with ==.
|
||||
Op Op
|
||||
|
||||
// Create events will have this set to the old path if it's a rename. This
|
||||
// only works when both the source and destination are watched. It's not
|
||||
// reliable when watching individual files, only directories.
|
||||
//
|
||||
// For example "mv /tmp/file /tmp/rename" will emit:
|
||||
//
|
||||
// Event{Op: Rename, Name: "/tmp/file"}
|
||||
// Event{Op: Create, Name: "/tmp/rename", RenamedFrom: "/tmp/file"}
|
||||
renamedFrom string
|
||||
}
|
||||
|
||||
// Op describes a set of file operations.
|
||||
|
|
@ -50,7 +187,7 @@ const (
|
|||
// example "remove to trash" is often a rename).
|
||||
Remove
|
||||
|
||||
// The path was renamed to something else; any watched on it will be
|
||||
// The path was renamed to something else; any watches on it will be
|
||||
// removed.
|
||||
Rename
|
||||
|
||||
|
|
@ -60,15 +197,155 @@ const (
|
|||
// get triggered very frequently by some software. For example, Spotlight
|
||||
// indexing on macOS, anti-virus software, backup software, etc.
|
||||
Chmod
|
||||
|
||||
// File descriptor was opened.
|
||||
//
|
||||
// Only works on Linux and FreeBSD.
|
||||
xUnportableOpen
|
||||
|
||||
// File was read from.
|
||||
//
|
||||
// Only works on Linux and FreeBSD.
|
||||
xUnportableRead
|
||||
|
||||
// File opened for writing was closed.
|
||||
//
|
||||
// Only works on Linux and FreeBSD.
|
||||
//
|
||||
// The advantage of using this over Write is that it's more reliable than
|
||||
// waiting for Write events to stop. It's also faster (if you're not
|
||||
// listening to Write events): copying a file of a few GB can easily
|
||||
// generate tens of thousands of Write events in a short span of time.
|
||||
xUnportableCloseWrite
|
||||
|
||||
// File opened for reading was closed.
|
||||
//
|
||||
// Only works on Linux and FreeBSD.
|
||||
xUnportableCloseRead
|
||||
)
|
||||
|
||||
// Common errors that can be reported.
|
||||
var (
|
||||
// ErrNonExistentWatch is used when Remove() is called on a path that's not
|
||||
// added.
|
||||
ErrNonExistentWatch = errors.New("fsnotify: can't remove non-existent watch")
|
||||
ErrEventOverflow = errors.New("fsnotify: queue or buffer overflow")
|
||||
ErrClosed = errors.New("fsnotify: watcher already closed")
|
||||
|
||||
// ErrClosed is used when trying to operate on a closed Watcher.
|
||||
ErrClosed = errors.New("fsnotify: watcher already closed")
|
||||
|
||||
// ErrEventOverflow is reported from the Errors channel when there are too
|
||||
// many events:
|
||||
//
|
||||
// - inotify: inotify returns IN_Q_OVERFLOW – because there are too
|
||||
// many queued events (the fs.inotify.max_queued_events
|
||||
// sysctl can be used to increase this).
|
||||
// - windows: The buffer size is too small; WithBufferSize() can be used to increase it.
|
||||
// - kqueue, fen: Not used.
|
||||
ErrEventOverflow = errors.New("fsnotify: queue or buffer overflow")
|
||||
|
||||
// ErrUnsupported is returned by AddWith() when WithOps() specified an
|
||||
// Unportable event that's not supported on this platform.
|
||||
xErrUnsupported = errors.New("fsnotify: not supported with this backend")
|
||||
)
|
||||
|
||||
// NewWatcher creates a new Watcher.
|
||||
func NewWatcher() (*Watcher, error) {
|
||||
ev, errs := make(chan Event), make(chan error)
|
||||
b, err := newBackend(ev, errs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Watcher{b: b, Events: ev, Errors: errs}, nil
|
||||
}
|
||||
|
||||
// NewBufferedWatcher creates a new Watcher with a buffered Watcher.Events
|
||||
// channel.
|
||||
//
|
||||
// The main use case for this is situations with a very large number of events
|
||||
// where the kernel buffer size can't be increased (e.g. due to lack of
|
||||
// permissions). An unbuffered Watcher will perform better for almost all use
|
||||
// cases, and whenever possible you will be better off increasing the kernel
|
||||
// buffers instead of adding a large userspace buffer.
|
||||
func NewBufferedWatcher(sz uint) (*Watcher, error) {
|
||||
ev, errs := make(chan Event), make(chan error)
|
||||
b, err := newBufferedBackend(sz, ev, errs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Watcher{b: b, Events: ev, Errors: errs}, nil
|
||||
}
|
||||
|
||||
// Add starts monitoring the path for changes.
|
||||
//
|
||||
// A path can only be watched once; watching it more than once is a no-op and will
|
||||
// not return an error. Paths that do not yet exist on the filesystem cannot be
|
||||
// watched.
|
||||
//
|
||||
// A watch will be automatically removed if the watched path is deleted or
|
||||
// renamed. The exception is the Windows backend, which doesn't remove the
|
||||
// watcher on renames.
|
||||
//
|
||||
// Notifications on network filesystems (NFS, SMB, FUSE, etc.) or special
|
||||
// filesystems (/proc, /sys, etc.) generally don't work.
|
||||
//
|
||||
// Returns [ErrClosed] if [Watcher.Close] was called.
|
||||
//
|
||||
// See [Watcher.AddWith] for a version that allows adding options.
|
||||
//
|
||||
// # Watching directories
|
||||
//
|
||||
// All files in a directory are monitored, including new files that are created
|
||||
// after the watcher is started. Subdirectories are not watched (i.e. it's
|
||||
// non-recursive).
|
||||
//
|
||||
// # Watching files
|
||||
//
|
||||
// Watching individual files (rather than directories) is generally not
|
||||
// recommended as many programs (especially editors) update files atomically: it
|
||||
// will write to a temporary file which is then moved to destination,
|
||||
// overwriting the original (or some variant thereof). The watcher on the
|
||||
// original file is now lost, as that no longer exists.
|
||||
//
|
||||
// The upshot of this is that a power failure or crash won't leave a
|
||||
// half-written file.
|
||||
//
|
||||
// Watch the parent directory and use Event.Name to filter out files you're not
|
||||
// interested in. There is an example of this in cmd/fsnotify/file.go.
|
||||
func (w *Watcher) Add(path string) error { return w.b.Add(path) }
|
||||
|
||||
// AddWith is like [Watcher.Add], but allows adding options. When using Add()
|
||||
// the defaults described below are used.
|
||||
//
|
||||
// Possible options are:
|
||||
//
|
||||
// - [WithBufferSize] sets the buffer size for the Windows backend; no-op on
|
||||
// other platforms. The default is 64K (65536 bytes).
|
||||
func (w *Watcher) AddWith(path string, opts ...addOpt) error { return w.b.AddWith(path, opts...) }
|
||||
|
||||
// Remove stops monitoring the path for changes.
|
||||
//
|
||||
// Directories are always removed non-recursively. For example, if you added
|
||||
// /tmp/dir and /tmp/dir/subdir then you will need to remove both.
|
||||
//
|
||||
// Removing a path that has not yet been added returns [ErrNonExistentWatch].
|
||||
//
|
||||
// Returns nil if [Watcher.Close] was called.
|
||||
func (w *Watcher) Remove(path string) error { return w.b.Remove(path) }
|
||||
|
||||
// Close removes all watches and closes the Events channel.
|
||||
func (w *Watcher) Close() error { return w.b.Close() }
|
||||
|
||||
// WatchList returns all paths explicitly added with [Watcher.Add] (and are not
|
||||
// yet removed).
|
||||
//
|
||||
// Returns nil if [Watcher.Close] was called.
|
||||
func (w *Watcher) WatchList() []string { return w.b.WatchList() }
|
||||
|
||||
// Supports reports if all the listed operations are supported by this platform.
|
||||
//
|
||||
// Create, Write, Remove, Rename, and Chmod are always supported. It can only
|
||||
// return false for an Op starting with Unportable.
|
||||
func (w *Watcher) xSupports(op Op) bool { return w.b.xSupports(op) }
|
||||
|
||||
func (o Op) String() string {
|
||||
var b strings.Builder
|
||||
if o.Has(Create) {
|
||||
|
|
@ -80,6 +357,18 @@ func (o Op) String() string {
|
|||
if o.Has(Write) {
|
||||
b.WriteString("|WRITE")
|
||||
}
|
||||
if o.Has(xUnportableOpen) {
|
||||
b.WriteString("|OPEN")
|
||||
}
|
||||
if o.Has(xUnportableRead) {
|
||||
b.WriteString("|READ")
|
||||
}
|
||||
if o.Has(xUnportableCloseWrite) {
|
||||
b.WriteString("|CLOSE_WRITE")
|
||||
}
|
||||
if o.Has(xUnportableCloseRead) {
|
||||
b.WriteString("|CLOSE_READ")
|
||||
}
|
||||
if o.Has(Rename) {
|
||||
b.WriteString("|RENAME")
|
||||
}
|
||||
|
|
@ -100,24 +389,48 @@ func (e Event) Has(op Op) bool { return e.Op.Has(op) }
|
|||
|
||||
// String returns a string representation of the event with their path.
|
||||
func (e Event) String() string {
|
||||
if e.renamedFrom != "" {
|
||||
return fmt.Sprintf("%-13s %q ← %q", e.Op.String(), e.Name, e.renamedFrom)
|
||||
}
|
||||
return fmt.Sprintf("%-13s %q", e.Op.String(), e.Name)
|
||||
}
|
||||
|
||||
type (
|
||||
backend interface {
|
||||
Add(string) error
|
||||
AddWith(string, ...addOpt) error
|
||||
Remove(string) error
|
||||
WatchList() []string
|
||||
Close() error
|
||||
xSupports(Op) bool
|
||||
}
|
||||
addOpt func(opt *withOpts)
|
||||
withOpts struct {
|
||||
bufsize int
|
||||
bufsize int
|
||||
op Op
|
||||
noFollow bool
|
||||
sendCreate bool
|
||||
}
|
||||
)
|
||||
|
||||
var debug = func() bool {
|
||||
// Check for exactly "1" (rather than mere existence) so we can add
|
||||
// options/flags in the future. I don't know if we ever want that, but it's
|
||||
// nice to leave the option open.
|
||||
return os.Getenv("FSNOTIFY_DEBUG") == "1"
|
||||
}()
|
||||
|
||||
var defaultOpts = withOpts{
|
||||
bufsize: 65536, // 64K
|
||||
op: Create | Write | Remove | Rename | Chmod,
|
||||
}
|
||||
|
||||
func getOptions(opts ...addOpt) withOpts {
|
||||
with := defaultOpts
|
||||
for _, o := range opts {
|
||||
o(&with)
|
||||
if o != nil {
|
||||
o(&with)
|
||||
}
|
||||
}
|
||||
return with
|
||||
}
|
||||
|
|
@ -136,9 +449,44 @@ func WithBufferSize(bytes int) addOpt {
|
|||
return func(opt *withOpts) { opt.bufsize = bytes }
|
||||
}
|
||||
|
||||
// WithOps sets which operations to listen for. The default is [Create],
|
||||
// [Write], [Remove], [Rename], and [Chmod].
|
||||
//
|
||||
// Excluding operations you're not interested in can save quite a bit of CPU
|
||||
// time; in some use cases there may be hundreds of thousands of useless Write
|
||||
// or Chmod operations per second.
|
||||
//
|
||||
// This can also be used to add unportable operations not supported by all
|
||||
// platforms; unportable operations all start with "Unportable":
|
||||
// [UnportableOpen], [UnportableRead], [UnportableCloseWrite], and
|
||||
// [UnportableCloseRead].
|
||||
//
|
||||
// AddWith returns an error when using an unportable operation that's not
|
||||
// supported. Use [Watcher.Support] to check for support.
|
||||
func withOps(op Op) addOpt {
|
||||
return func(opt *withOpts) { opt.op = op }
|
||||
}
|
||||
|
||||
// WithNoFollow disables following symlinks, so the symlinks themselves are
|
||||
// watched.
|
||||
func withNoFollow() addOpt {
|
||||
return func(opt *withOpts) { opt.noFollow = true }
|
||||
}
|
||||
|
||||
// "Internal" option for recursive watches on inotify.
|
||||
func withCreate() addOpt {
|
||||
return func(opt *withOpts) { opt.sendCreate = true }
|
||||
}
|
||||
|
||||
var enableRecurse = false
|
||||
|
||||
// Check if this path is recursive (ends with "/..." or "\..."), and return the
|
||||
// path with the /... stripped.
|
||||
func recursivePath(path string) (string, bool) {
|
||||
path = filepath.Clean(path)
|
||||
if !enableRecurse { // Only enabled in tests for now.
|
||||
return path, false
|
||||
}
|
||||
if filepath.Base(path) == "..." {
|
||||
return filepath.Dir(path), true
|
||||
}
|
||||
|
|
|
|||
39
vendor/github.com/fsnotify/fsnotify/internal/darwin.go
generated
vendored
Normal file
39
vendor/github.com/fsnotify/fsnotify/internal/darwin.go
generated
vendored
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
//go:build darwin
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
var (
|
||||
SyscallEACCES = syscall.EACCES
|
||||
UnixEACCES = unix.EACCES
|
||||
)
|
||||
|
||||
var maxfiles uint64
|
||||
|
||||
// Go 1.19 will do this automatically: https://go-review.googlesource.com/c/go/+/393354/
|
||||
func SetRlimit() {
|
||||
var l syscall.Rlimit
|
||||
err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &l)
|
||||
if err == nil && l.Cur != l.Max {
|
||||
l.Cur = l.Max
|
||||
syscall.Setrlimit(syscall.RLIMIT_NOFILE, &l)
|
||||
}
|
||||
maxfiles = l.Cur
|
||||
|
||||
if n, err := syscall.SysctlUint32("kern.maxfiles"); err == nil && uint64(n) < maxfiles {
|
||||
maxfiles = uint64(n)
|
||||
}
|
||||
|
||||
if n, err := syscall.SysctlUint32("kern.maxfilesperproc"); err == nil && uint64(n) < maxfiles {
|
||||
maxfiles = uint64(n)
|
||||
}
|
||||
}
|
||||
|
||||
func Maxfiles() uint64 { return maxfiles }
|
||||
func Mkfifo(path string, mode uint32) error { return unix.Mkfifo(path, mode) }
|
||||
func Mknod(path string, mode uint32, dev int) error { return unix.Mknod(path, mode, dev) }
|
||||
57
vendor/github.com/fsnotify/fsnotify/internal/debug_darwin.go
generated
vendored
Normal file
57
vendor/github.com/fsnotify/fsnotify/internal/debug_darwin.go
generated
vendored
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
package internal
|
||||
|
||||
import "golang.org/x/sys/unix"
|
||||
|
||||
var names = []struct {
|
||||
n string
|
||||
m uint32
|
||||
}{
|
||||
{"NOTE_ABSOLUTE", unix.NOTE_ABSOLUTE},
|
||||
{"NOTE_ATTRIB", unix.NOTE_ATTRIB},
|
||||
{"NOTE_BACKGROUND", unix.NOTE_BACKGROUND},
|
||||
{"NOTE_CHILD", unix.NOTE_CHILD},
|
||||
{"NOTE_CRITICAL", unix.NOTE_CRITICAL},
|
||||
{"NOTE_DELETE", unix.NOTE_DELETE},
|
||||
{"NOTE_EXEC", unix.NOTE_EXEC},
|
||||
{"NOTE_EXIT", unix.NOTE_EXIT},
|
||||
{"NOTE_EXITSTATUS", unix.NOTE_EXITSTATUS},
|
||||
{"NOTE_EXIT_CSERROR", unix.NOTE_EXIT_CSERROR},
|
||||
{"NOTE_EXIT_DECRYPTFAIL", unix.NOTE_EXIT_DECRYPTFAIL},
|
||||
{"NOTE_EXIT_DETAIL", unix.NOTE_EXIT_DETAIL},
|
||||
{"NOTE_EXIT_DETAIL_MASK", unix.NOTE_EXIT_DETAIL_MASK},
|
||||
{"NOTE_EXIT_MEMORY", unix.NOTE_EXIT_MEMORY},
|
||||
{"NOTE_EXIT_REPARENTED", unix.NOTE_EXIT_REPARENTED},
|
||||
{"NOTE_EXTEND", unix.NOTE_EXTEND},
|
||||
{"NOTE_FFAND", unix.NOTE_FFAND},
|
||||
{"NOTE_FFCOPY", unix.NOTE_FFCOPY},
|
||||
{"NOTE_FFCTRLMASK", unix.NOTE_FFCTRLMASK},
|
||||
{"NOTE_FFLAGSMASK", unix.NOTE_FFLAGSMASK},
|
||||
{"NOTE_FFNOP", unix.NOTE_FFNOP},
|
||||
{"NOTE_FFOR", unix.NOTE_FFOR},
|
||||
{"NOTE_FORK", unix.NOTE_FORK},
|
||||
{"NOTE_FUNLOCK", unix.NOTE_FUNLOCK},
|
||||
{"NOTE_LEEWAY", unix.NOTE_LEEWAY},
|
||||
{"NOTE_LINK", unix.NOTE_LINK},
|
||||
{"NOTE_LOWAT", unix.NOTE_LOWAT},
|
||||
{"NOTE_MACHTIME", unix.NOTE_MACHTIME},
|
||||
{"NOTE_MACH_CONTINUOUS_TIME", unix.NOTE_MACH_CONTINUOUS_TIME},
|
||||
{"NOTE_NONE", unix.NOTE_NONE},
|
||||
{"NOTE_NSECONDS", unix.NOTE_NSECONDS},
|
||||
{"NOTE_OOB", unix.NOTE_OOB},
|
||||
//{"NOTE_PCTRLMASK", unix.NOTE_PCTRLMASK}, -0x100000 (?!)
|
||||
{"NOTE_PDATAMASK", unix.NOTE_PDATAMASK},
|
||||
{"NOTE_REAP", unix.NOTE_REAP},
|
||||
{"NOTE_RENAME", unix.NOTE_RENAME},
|
||||
{"NOTE_REVOKE", unix.NOTE_REVOKE},
|
||||
{"NOTE_SECONDS", unix.NOTE_SECONDS},
|
||||
{"NOTE_SIGNAL", unix.NOTE_SIGNAL},
|
||||
{"NOTE_TRACK", unix.NOTE_TRACK},
|
||||
{"NOTE_TRACKERR", unix.NOTE_TRACKERR},
|
||||
{"NOTE_TRIGGER", unix.NOTE_TRIGGER},
|
||||
{"NOTE_USECONDS", unix.NOTE_USECONDS},
|
||||
{"NOTE_VM_ERROR", unix.NOTE_VM_ERROR},
|
||||
{"NOTE_VM_PRESSURE", unix.NOTE_VM_PRESSURE},
|
||||
{"NOTE_VM_PRESSURE_SUDDEN_TERMINATE", unix.NOTE_VM_PRESSURE_SUDDEN_TERMINATE},
|
||||
{"NOTE_VM_PRESSURE_TERMINATE", unix.NOTE_VM_PRESSURE_TERMINATE},
|
||||
{"NOTE_WRITE", unix.NOTE_WRITE},
|
||||
}
|
||||
33
vendor/github.com/fsnotify/fsnotify/internal/debug_dragonfly.go
generated
vendored
Normal file
33
vendor/github.com/fsnotify/fsnotify/internal/debug_dragonfly.go
generated
vendored
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
package internal
|
||||
|
||||
import "golang.org/x/sys/unix"
|
||||
|
||||
var names = []struct {
|
||||
n string
|
||||
m uint32
|
||||
}{
|
||||
{"NOTE_ATTRIB", unix.NOTE_ATTRIB},
|
||||
{"NOTE_CHILD", unix.NOTE_CHILD},
|
||||
{"NOTE_DELETE", unix.NOTE_DELETE},
|
||||
{"NOTE_EXEC", unix.NOTE_EXEC},
|
||||
{"NOTE_EXIT", unix.NOTE_EXIT},
|
||||
{"NOTE_EXTEND", unix.NOTE_EXTEND},
|
||||
{"NOTE_FFAND", unix.NOTE_FFAND},
|
||||
{"NOTE_FFCOPY", unix.NOTE_FFCOPY},
|
||||
{"NOTE_FFCTRLMASK", unix.NOTE_FFCTRLMASK},
|
||||
{"NOTE_FFLAGSMASK", unix.NOTE_FFLAGSMASK},
|
||||
{"NOTE_FFNOP", unix.NOTE_FFNOP},
|
||||
{"NOTE_FFOR", unix.NOTE_FFOR},
|
||||
{"NOTE_FORK", unix.NOTE_FORK},
|
||||
{"NOTE_LINK", unix.NOTE_LINK},
|
||||
{"NOTE_LOWAT", unix.NOTE_LOWAT},
|
||||
{"NOTE_OOB", unix.NOTE_OOB},
|
||||
{"NOTE_PCTRLMASK", unix.NOTE_PCTRLMASK},
|
||||
{"NOTE_PDATAMASK", unix.NOTE_PDATAMASK},
|
||||
{"NOTE_RENAME", unix.NOTE_RENAME},
|
||||
{"NOTE_REVOKE", unix.NOTE_REVOKE},
|
||||
{"NOTE_TRACK", unix.NOTE_TRACK},
|
||||
{"NOTE_TRACKERR", unix.NOTE_TRACKERR},
|
||||
{"NOTE_TRIGGER", unix.NOTE_TRIGGER},
|
||||
{"NOTE_WRITE", unix.NOTE_WRITE},
|
||||
}
|
||||
42
vendor/github.com/fsnotify/fsnotify/internal/debug_freebsd.go
generated
vendored
Normal file
42
vendor/github.com/fsnotify/fsnotify/internal/debug_freebsd.go
generated
vendored
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
package internal
|
||||
|
||||
import "golang.org/x/sys/unix"
|
||||
|
||||
var names = []struct {
|
||||
n string
|
||||
m uint32
|
||||
}{
|
||||
{"NOTE_ABSTIME", unix.NOTE_ABSTIME},
|
||||
{"NOTE_ATTRIB", unix.NOTE_ATTRIB},
|
||||
{"NOTE_CHILD", unix.NOTE_CHILD},
|
||||
{"NOTE_CLOSE", unix.NOTE_CLOSE},
|
||||
{"NOTE_CLOSE_WRITE", unix.NOTE_CLOSE_WRITE},
|
||||
{"NOTE_DELETE", unix.NOTE_DELETE},
|
||||
{"NOTE_EXEC", unix.NOTE_EXEC},
|
||||
{"NOTE_EXIT", unix.NOTE_EXIT},
|
||||
{"NOTE_EXTEND", unix.NOTE_EXTEND},
|
||||
{"NOTE_FFAND", unix.NOTE_FFAND},
|
||||
{"NOTE_FFCOPY", unix.NOTE_FFCOPY},
|
||||
{"NOTE_FFCTRLMASK", unix.NOTE_FFCTRLMASK},
|
||||
{"NOTE_FFLAGSMASK", unix.NOTE_FFLAGSMASK},
|
||||
{"NOTE_FFNOP", unix.NOTE_FFNOP},
|
||||
{"NOTE_FFOR", unix.NOTE_FFOR},
|
||||
{"NOTE_FILE_POLL", unix.NOTE_FILE_POLL},
|
||||
{"NOTE_FORK", unix.NOTE_FORK},
|
||||
{"NOTE_LINK", unix.NOTE_LINK},
|
||||
{"NOTE_LOWAT", unix.NOTE_LOWAT},
|
||||
{"NOTE_MSECONDS", unix.NOTE_MSECONDS},
|
||||
{"NOTE_NSECONDS", unix.NOTE_NSECONDS},
|
||||
{"NOTE_OPEN", unix.NOTE_OPEN},
|
||||
{"NOTE_PCTRLMASK", unix.NOTE_PCTRLMASK},
|
||||
{"NOTE_PDATAMASK", unix.NOTE_PDATAMASK},
|
||||
{"NOTE_READ", unix.NOTE_READ},
|
||||
{"NOTE_RENAME", unix.NOTE_RENAME},
|
||||
{"NOTE_REVOKE", unix.NOTE_REVOKE},
|
||||
{"NOTE_SECONDS", unix.NOTE_SECONDS},
|
||||
{"NOTE_TRACK", unix.NOTE_TRACK},
|
||||
{"NOTE_TRACKERR", unix.NOTE_TRACKERR},
|
||||
{"NOTE_TRIGGER", unix.NOTE_TRIGGER},
|
||||
{"NOTE_USECONDS", unix.NOTE_USECONDS},
|
||||
{"NOTE_WRITE", unix.NOTE_WRITE},
|
||||
}
|
||||
32
vendor/github.com/fsnotify/fsnotify/internal/debug_kqueue.go
generated
vendored
Normal file
32
vendor/github.com/fsnotify/fsnotify/internal/debug_kqueue.go
generated
vendored
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
//go:build freebsd || openbsd || netbsd || dragonfly || darwin
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func Debug(name string, kevent *unix.Kevent_t) {
|
||||
mask := uint32(kevent.Fflags)
|
||||
|
||||
var (
|
||||
l []string
|
||||
unknown = mask
|
||||
)
|
||||
for _, n := range names {
|
||||
if mask&n.m == n.m {
|
||||
l = append(l, n.n)
|
||||
unknown ^= n.m
|
||||
}
|
||||
}
|
||||
if unknown > 0 {
|
||||
l = append(l, fmt.Sprintf("0x%x", unknown))
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "FSNOTIFY_DEBUG: %s %10d:%-60s → %q\n",
|
||||
time.Now().Format("15:04:05.000000000"), mask, strings.Join(l, " | "), name)
|
||||
}
|
||||
56
vendor/github.com/fsnotify/fsnotify/internal/debug_linux.go
generated
vendored
Normal file
56
vendor/github.com/fsnotify/fsnotify/internal/debug_linux.go
generated
vendored
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
package internal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func Debug(name string, mask, cookie uint32) {
|
||||
names := []struct {
|
||||
n string
|
||||
m uint32
|
||||
}{
|
||||
{"IN_ACCESS", unix.IN_ACCESS},
|
||||
{"IN_ATTRIB", unix.IN_ATTRIB},
|
||||
{"IN_CLOSE", unix.IN_CLOSE},
|
||||
{"IN_CLOSE_NOWRITE", unix.IN_CLOSE_NOWRITE},
|
||||
{"IN_CLOSE_WRITE", unix.IN_CLOSE_WRITE},
|
||||
{"IN_CREATE", unix.IN_CREATE},
|
||||
{"IN_DELETE", unix.IN_DELETE},
|
||||
{"IN_DELETE_SELF", unix.IN_DELETE_SELF},
|
||||
{"IN_IGNORED", unix.IN_IGNORED},
|
||||
{"IN_ISDIR", unix.IN_ISDIR},
|
||||
{"IN_MODIFY", unix.IN_MODIFY},
|
||||
{"IN_MOVE", unix.IN_MOVE},
|
||||
{"IN_MOVED_FROM", unix.IN_MOVED_FROM},
|
||||
{"IN_MOVED_TO", unix.IN_MOVED_TO},
|
||||
{"IN_MOVE_SELF", unix.IN_MOVE_SELF},
|
||||
{"IN_OPEN", unix.IN_OPEN},
|
||||
{"IN_Q_OVERFLOW", unix.IN_Q_OVERFLOW},
|
||||
{"IN_UNMOUNT", unix.IN_UNMOUNT},
|
||||
}
|
||||
|
||||
var (
|
||||
l []string
|
||||
unknown = mask
|
||||
)
|
||||
for _, n := range names {
|
||||
if mask&n.m == n.m {
|
||||
l = append(l, n.n)
|
||||
unknown ^= n.m
|
||||
}
|
||||
}
|
||||
if unknown > 0 {
|
||||
l = append(l, fmt.Sprintf("0x%x", unknown))
|
||||
}
|
||||
var c string
|
||||
if cookie > 0 {
|
||||
c = fmt.Sprintf("(cookie: %d) ", cookie)
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "FSNOTIFY_DEBUG: %s %-30s → %s%q\n",
|
||||
time.Now().Format("15:04:05.000000000"), strings.Join(l, "|"), c, name)
|
||||
}
|
||||
25
vendor/github.com/fsnotify/fsnotify/internal/debug_netbsd.go
generated
vendored
Normal file
25
vendor/github.com/fsnotify/fsnotify/internal/debug_netbsd.go
generated
vendored
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
package internal
|
||||
|
||||
import "golang.org/x/sys/unix"
|
||||
|
||||
var names = []struct {
|
||||
n string
|
||||
m uint32
|
||||
}{
|
||||
{"NOTE_ATTRIB", unix.NOTE_ATTRIB},
|
||||
{"NOTE_CHILD", unix.NOTE_CHILD},
|
||||
{"NOTE_DELETE", unix.NOTE_DELETE},
|
||||
{"NOTE_EXEC", unix.NOTE_EXEC},
|
||||
{"NOTE_EXIT", unix.NOTE_EXIT},
|
||||
{"NOTE_EXTEND", unix.NOTE_EXTEND},
|
||||
{"NOTE_FORK", unix.NOTE_FORK},
|
||||
{"NOTE_LINK", unix.NOTE_LINK},
|
||||
{"NOTE_LOWAT", unix.NOTE_LOWAT},
|
||||
{"NOTE_PCTRLMASK", unix.NOTE_PCTRLMASK},
|
||||
{"NOTE_PDATAMASK", unix.NOTE_PDATAMASK},
|
||||
{"NOTE_RENAME", unix.NOTE_RENAME},
|
||||
{"NOTE_REVOKE", unix.NOTE_REVOKE},
|
||||
{"NOTE_TRACK", unix.NOTE_TRACK},
|
||||
{"NOTE_TRACKERR", unix.NOTE_TRACKERR},
|
||||
{"NOTE_WRITE", unix.NOTE_WRITE},
|
||||
}
|
||||
28
vendor/github.com/fsnotify/fsnotify/internal/debug_openbsd.go
generated
vendored
Normal file
28
vendor/github.com/fsnotify/fsnotify/internal/debug_openbsd.go
generated
vendored
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
package internal
|
||||
|
||||
import "golang.org/x/sys/unix"
|
||||
|
||||
var names = []struct {
|
||||
n string
|
||||
m uint32
|
||||
}{
|
||||
{"NOTE_ATTRIB", unix.NOTE_ATTRIB},
|
||||
// {"NOTE_CHANGE", unix.NOTE_CHANGE}, // Not on 386?
|
||||
{"NOTE_CHILD", unix.NOTE_CHILD},
|
||||
{"NOTE_DELETE", unix.NOTE_DELETE},
|
||||
{"NOTE_EOF", unix.NOTE_EOF},
|
||||
{"NOTE_EXEC", unix.NOTE_EXEC},
|
||||
{"NOTE_EXIT", unix.NOTE_EXIT},
|
||||
{"NOTE_EXTEND", unix.NOTE_EXTEND},
|
||||
{"NOTE_FORK", unix.NOTE_FORK},
|
||||
{"NOTE_LINK", unix.NOTE_LINK},
|
||||
{"NOTE_LOWAT", unix.NOTE_LOWAT},
|
||||
{"NOTE_PCTRLMASK", unix.NOTE_PCTRLMASK},
|
||||
{"NOTE_PDATAMASK", unix.NOTE_PDATAMASK},
|
||||
{"NOTE_RENAME", unix.NOTE_RENAME},
|
||||
{"NOTE_REVOKE", unix.NOTE_REVOKE},
|
||||
{"NOTE_TRACK", unix.NOTE_TRACK},
|
||||
{"NOTE_TRACKERR", unix.NOTE_TRACKERR},
|
||||
{"NOTE_TRUNCATE", unix.NOTE_TRUNCATE},
|
||||
{"NOTE_WRITE", unix.NOTE_WRITE},
|
||||
}
|
||||
45
vendor/github.com/fsnotify/fsnotify/internal/debug_solaris.go
generated
vendored
Normal file
45
vendor/github.com/fsnotify/fsnotify/internal/debug_solaris.go
generated
vendored
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
package internal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func Debug(name string, mask int32) {
|
||||
names := []struct {
|
||||
n string
|
||||
m int32
|
||||
}{
|
||||
{"FILE_ACCESS", unix.FILE_ACCESS},
|
||||
{"FILE_MODIFIED", unix.FILE_MODIFIED},
|
||||
{"FILE_ATTRIB", unix.FILE_ATTRIB},
|
||||
{"FILE_TRUNC", unix.FILE_TRUNC},
|
||||
{"FILE_NOFOLLOW", unix.FILE_NOFOLLOW},
|
||||
{"FILE_DELETE", unix.FILE_DELETE},
|
||||
{"FILE_RENAME_TO", unix.FILE_RENAME_TO},
|
||||
{"FILE_RENAME_FROM", unix.FILE_RENAME_FROM},
|
||||
{"UNMOUNTED", unix.UNMOUNTED},
|
||||
{"MOUNTEDOVER", unix.MOUNTEDOVER},
|
||||
{"FILE_EXCEPTION", unix.FILE_EXCEPTION},
|
||||
}
|
||||
|
||||
var (
|
||||
l []string
|
||||
unknown = mask
|
||||
)
|
||||
for _, n := range names {
|
||||
if mask&n.m == n.m {
|
||||
l = append(l, n.n)
|
||||
unknown ^= n.m
|
||||
}
|
||||
}
|
||||
if unknown > 0 {
|
||||
l = append(l, fmt.Sprintf("0x%x", unknown))
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "FSNOTIFY_DEBUG: %s %10d:%-30s → %q\n",
|
||||
time.Now().Format("15:04:05.000000000"), mask, strings.Join(l, " | "), name)
|
||||
}
|
||||
40
vendor/github.com/fsnotify/fsnotify/internal/debug_windows.go
generated
vendored
Normal file
40
vendor/github.com/fsnotify/fsnotify/internal/debug_windows.go
generated
vendored
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
package internal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
func Debug(name string, mask uint32) {
|
||||
names := []struct {
|
||||
n string
|
||||
m uint32
|
||||
}{
|
||||
{"FILE_ACTION_ADDED", windows.FILE_ACTION_ADDED},
|
||||
{"FILE_ACTION_REMOVED", windows.FILE_ACTION_REMOVED},
|
||||
{"FILE_ACTION_MODIFIED", windows.FILE_ACTION_MODIFIED},
|
||||
{"FILE_ACTION_RENAMED_OLD_NAME", windows.FILE_ACTION_RENAMED_OLD_NAME},
|
||||
{"FILE_ACTION_RENAMED_NEW_NAME", windows.FILE_ACTION_RENAMED_NEW_NAME},
|
||||
}
|
||||
|
||||
var (
|
||||
l []string
|
||||
unknown = mask
|
||||
)
|
||||
for _, n := range names {
|
||||
if mask&n.m == n.m {
|
||||
l = append(l, n.n)
|
||||
unknown ^= n.m
|
||||
}
|
||||
}
|
||||
if unknown > 0 {
|
||||
l = append(l, fmt.Sprintf("0x%x", unknown))
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "FSNOTIFY_DEBUG: %s %-65s → %q\n",
|
||||
time.Now().Format("15:04:05.000000000"), strings.Join(l, " | "), filepath.ToSlash(name))
|
||||
}
|
||||
31
vendor/github.com/fsnotify/fsnotify/internal/freebsd.go
generated
vendored
Normal file
31
vendor/github.com/fsnotify/fsnotify/internal/freebsd.go
generated
vendored
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
//go:build freebsd
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
var (
|
||||
SyscallEACCES = syscall.EACCES
|
||||
UnixEACCES = unix.EACCES
|
||||
)
|
||||
|
||||
var maxfiles uint64
|
||||
|
||||
func SetRlimit() {
|
||||
// Go 1.19 will do this automatically: https://go-review.googlesource.com/c/go/+/393354/
|
||||
var l syscall.Rlimit
|
||||
err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &l)
|
||||
if err == nil && l.Cur != l.Max {
|
||||
l.Cur = l.Max
|
||||
syscall.Setrlimit(syscall.RLIMIT_NOFILE, &l)
|
||||
}
|
||||
maxfiles = uint64(l.Cur)
|
||||
}
|
||||
|
||||
func Maxfiles() uint64 { return maxfiles }
|
||||
func Mkfifo(path string, mode uint32) error { return unix.Mkfifo(path, mode) }
|
||||
func Mknod(path string, mode uint32, dev int) error { return unix.Mknod(path, mode, uint64(dev)) }
|
||||
2
vendor/github.com/fsnotify/fsnotify/internal/internal.go
generated
vendored
Normal file
2
vendor/github.com/fsnotify/fsnotify/internal/internal.go
generated
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
// Package internal contains some helpers.
|
||||
package internal
|
||||
31
vendor/github.com/fsnotify/fsnotify/internal/unix.go
generated
vendored
Normal file
31
vendor/github.com/fsnotify/fsnotify/internal/unix.go
generated
vendored
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
//go:build !windows && !darwin && !freebsd
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
var (
|
||||
SyscallEACCES = syscall.EACCES
|
||||
UnixEACCES = unix.EACCES
|
||||
)
|
||||
|
||||
var maxfiles uint64
|
||||
|
||||
func SetRlimit() {
|
||||
// Go 1.19 will do this automatically: https://go-review.googlesource.com/c/go/+/393354/
|
||||
var l syscall.Rlimit
|
||||
err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &l)
|
||||
if err == nil && l.Cur != l.Max {
|
||||
l.Cur = l.Max
|
||||
syscall.Setrlimit(syscall.RLIMIT_NOFILE, &l)
|
||||
}
|
||||
maxfiles = uint64(l.Cur)
|
||||
}
|
||||
|
||||
func Maxfiles() uint64 { return maxfiles }
|
||||
func Mkfifo(path string, mode uint32) error { return unix.Mkfifo(path, mode) }
|
||||
func Mknod(path string, mode uint32, dev int) error { return unix.Mknod(path, mode, dev) }
|
||||
7
vendor/github.com/fsnotify/fsnotify/internal/unix2.go
generated
vendored
Normal file
7
vendor/github.com/fsnotify/fsnotify/internal/unix2.go
generated
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
//go:build !windows
|
||||
|
||||
package internal
|
||||
|
||||
func HasPrivilegesForSymlink() bool {
|
||||
return true
|
||||
}
|
||||
41
vendor/github.com/fsnotify/fsnotify/internal/windows.go
generated
vendored
Normal file
41
vendor/github.com/fsnotify/fsnotify/internal/windows.go
generated
vendored
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
//go:build windows
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
// Just a dummy.
|
||||
var (
|
||||
SyscallEACCES = errors.New("dummy")
|
||||
UnixEACCES = errors.New("dummy")
|
||||
)
|
||||
|
||||
func SetRlimit() {}
|
||||
func Maxfiles() uint64 { return 1<<64 - 1 }
|
||||
func Mkfifo(path string, mode uint32) error { return errors.New("no FIFOs on Windows") }
|
||||
func Mknod(path string, mode uint32, dev int) error { return errors.New("no device nodes on Windows") }
|
||||
|
||||
func HasPrivilegesForSymlink() bool {
|
||||
var sid *windows.SID
|
||||
err := windows.AllocateAndInitializeSid(
|
||||
&windows.SECURITY_NT_AUTHORITY,
|
||||
2,
|
||||
windows.SECURITY_BUILTIN_DOMAIN_RID,
|
||||
windows.DOMAIN_ALIAS_RID_ADMINS,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
&sid)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
defer windows.FreeSid(sid)
|
||||
token := windows.Token(0)
|
||||
member, err := token.IsMember(sid)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return member || token.IsElevated()
|
||||
}
|
||||
259
vendor/github.com/fsnotify/fsnotify/mkdoc.zsh
generated
vendored
259
vendor/github.com/fsnotify/fsnotify/mkdoc.zsh
generated
vendored
|
|
@ -1,259 +0,0 @@
|
|||
#!/usr/bin/env zsh
|
||||
[ "${ZSH_VERSION:-}" = "" ] && echo >&2 "Only works with zsh" && exit 1
|
||||
setopt err_exit no_unset pipefail extended_glob
|
||||
|
||||
# Simple script to update the godoc comments on all watchers so you don't need
|
||||
# to update the same comment 5 times.
|
||||
|
||||
watcher=$(<<EOF
|
||||
// Watcher watches a set of paths, delivering events on a channel.
|
||||
//
|
||||
// A watcher should not be copied (e.g. pass it by pointer, rather than by
|
||||
// value).
|
||||
//
|
||||
// # Linux notes
|
||||
//
|
||||
// When a file is removed a Remove event won't be emitted until all file
|
||||
// descriptors are closed, and deletes will always emit a Chmod. For example:
|
||||
//
|
||||
// fp := os.Open("file")
|
||||
// os.Remove("file") // Triggers Chmod
|
||||
// fp.Close() // Triggers Remove
|
||||
//
|
||||
// This is the event that inotify sends, so not much can be changed about this.
|
||||
//
|
||||
// The fs.inotify.max_user_watches sysctl variable specifies the upper limit
|
||||
// for the number of watches per user, and fs.inotify.max_user_instances
|
||||
// specifies the maximum number of inotify instances per user. Every Watcher you
|
||||
// create is an "instance", and every path you add is a "watch".
|
||||
//
|
||||
// These are also exposed in /proc as /proc/sys/fs/inotify/max_user_watches and
|
||||
// /proc/sys/fs/inotify/max_user_instances
|
||||
//
|
||||
// To increase them you can use sysctl or write the value to the /proc file:
|
||||
//
|
||||
// # Default values on Linux 5.18
|
||||
// sysctl fs.inotify.max_user_watches=124983
|
||||
// sysctl fs.inotify.max_user_instances=128
|
||||
//
|
||||
// To make the changes persist on reboot edit /etc/sysctl.conf or
|
||||
// /usr/lib/sysctl.d/50-default.conf (details differ per Linux distro; check
|
||||
// your distro's documentation):
|
||||
//
|
||||
// fs.inotify.max_user_watches=124983
|
||||
// fs.inotify.max_user_instances=128
|
||||
//
|
||||
// Reaching the limit will result in a "no space left on device" or "too many open
|
||||
// files" error.
|
||||
//
|
||||
// # kqueue notes (macOS, BSD)
|
||||
//
|
||||
// kqueue requires opening a file descriptor for every file that's being watched;
|
||||
// so if you're watching a directory with five files then that's six file
|
||||
// descriptors. You will run in to your system's "max open files" limit faster on
|
||||
// these platforms.
|
||||
//
|
||||
// The sysctl variables kern.maxfiles and kern.maxfilesperproc can be used to
|
||||
// control the maximum number of open files, as well as /etc/login.conf on BSD
|
||||
// systems.
|
||||
//
|
||||
// # Windows notes
|
||||
//
|
||||
// Paths can be added as "C:\\path\\to\\dir", but forward slashes
|
||||
// ("C:/path/to/dir") will also work.
|
||||
//
|
||||
// When a watched directory is removed it will always send an event for the
|
||||
// directory itself, but may not send events for all files in that directory.
|
||||
// Sometimes it will send events for all times, sometimes it will send no
|
||||
// events, and often only for some files.
|
||||
//
|
||||
// The default ReadDirectoryChangesW() buffer size is 64K, which is the largest
|
||||
// value that is guaranteed to work with SMB filesystems. If you have many
|
||||
// events in quick succession this may not be enough, and you will have to use
|
||||
// [WithBufferSize] to increase the value.
|
||||
EOF
|
||||
)
|
||||
|
||||
new=$(<<EOF
|
||||
// NewWatcher creates a new Watcher.
|
||||
EOF
|
||||
)
|
||||
|
||||
newbuffered=$(<<EOF
|
||||
// NewBufferedWatcher creates a new Watcher with a buffered Watcher.Events
|
||||
// channel.
|
||||
//
|
||||
// The main use case for this is situations with a very large number of events
|
||||
// where the kernel buffer size can't be increased (e.g. due to lack of
|
||||
// permissions). An unbuffered Watcher will perform better for almost all use
|
||||
// cases, and whenever possible you will be better off increasing the kernel
|
||||
// buffers instead of adding a large userspace buffer.
|
||||
EOF
|
||||
)
|
||||
|
||||
add=$(<<EOF
|
||||
// Add starts monitoring the path for changes.
|
||||
//
|
||||
// A path can only be watched once; watching it more than once is a no-op and will
|
||||
// not return an error. Paths that do not yet exist on the filesystem cannot be
|
||||
// watched.
|
||||
//
|
||||
// A watch will be automatically removed if the watched path is deleted or
|
||||
// renamed. The exception is the Windows backend, which doesn't remove the
|
||||
// watcher on renames.
|
||||
//
|
||||
// Notifications on network filesystems (NFS, SMB, FUSE, etc.) or special
|
||||
// filesystems (/proc, /sys, etc.) generally don't work.
|
||||
//
|
||||
// Returns [ErrClosed] if [Watcher.Close] was called.
|
||||
//
|
||||
// See [Watcher.AddWith] for a version that allows adding options.
|
||||
//
|
||||
// # Watching directories
|
||||
//
|
||||
// All files in a directory are monitored, including new files that are created
|
||||
// after the watcher is started. Subdirectories are not watched (i.e. it's
|
||||
// non-recursive).
|
||||
//
|
||||
// # Watching files
|
||||
//
|
||||
// Watching individual files (rather than directories) is generally not
|
||||
// recommended as many programs (especially editors) update files atomically: it
|
||||
// will write to a temporary file which is then moved to to destination,
|
||||
// overwriting the original (or some variant thereof). The watcher on the
|
||||
// original file is now lost, as that no longer exists.
|
||||
//
|
||||
// The upshot of this is that a power failure or crash won't leave a
|
||||
// half-written file.
|
||||
//
|
||||
// Watch the parent directory and use Event.Name to filter out files you're not
|
||||
// interested in. There is an example of this in cmd/fsnotify/file.go.
|
||||
EOF
|
||||
)
|
||||
|
||||
addwith=$(<<EOF
|
||||
// AddWith is like [Watcher.Add], but allows adding options. When using Add()
|
||||
// the defaults described below are used.
|
||||
//
|
||||
// Possible options are:
|
||||
//
|
||||
// - [WithBufferSize] sets the buffer size for the Windows backend; no-op on
|
||||
// other platforms. The default is 64K (65536 bytes).
|
||||
EOF
|
||||
)
|
||||
|
||||
remove=$(<<EOF
|
||||
// Remove stops monitoring the path for changes.
|
||||
//
|
||||
// Directories are always removed non-recursively. For example, if you added
|
||||
// /tmp/dir and /tmp/dir/subdir then you will need to remove both.
|
||||
//
|
||||
// Removing a path that has not yet been added returns [ErrNonExistentWatch].
|
||||
//
|
||||
// Returns nil if [Watcher.Close] was called.
|
||||
EOF
|
||||
)
|
||||
|
||||
close=$(<<EOF
|
||||
// Close removes all watches and closes the Events channel.
|
||||
EOF
|
||||
)
|
||||
|
||||
watchlist=$(<<EOF
|
||||
// WatchList returns all paths explicitly added with [Watcher.Add] (and are not
|
||||
// yet removed).
|
||||
//
|
||||
// Returns nil if [Watcher.Close] was called.
|
||||
EOF
|
||||
)
|
||||
|
||||
events=$(<<EOF
|
||||
// Events sends the filesystem change events.
|
||||
//
|
||||
// fsnotify can send the following events; a "path" here can refer to a
|
||||
// file, directory, symbolic link, or special file like a FIFO.
|
||||
//
|
||||
// fsnotify.Create A new path was created; this may be followed by one
|
||||
// or more Write events if data also gets written to a
|
||||
// file.
|
||||
//
|
||||
// fsnotify.Remove A path was removed.
|
||||
//
|
||||
// fsnotify.Rename A path was renamed. A rename is always sent with the
|
||||
// old path as Event.Name, and a Create event will be
|
||||
// sent with the new name. Renames are only sent for
|
||||
// paths that are currently watched; e.g. moving an
|
||||
// unmonitored file into a monitored directory will
|
||||
// show up as just a Create. Similarly, renaming a file
|
||||
// to outside a monitored directory will show up as
|
||||
// only a Rename.
|
||||
//
|
||||
// fsnotify.Write A file or named pipe was written to. A Truncate will
|
||||
// also trigger a Write. A single "write action"
|
||||
// initiated by the user may show up as one or multiple
|
||||
// writes, depending on when the system syncs things to
|
||||
// disk. For example when compiling a large Go program
|
||||
// you may get hundreds of Write events, and you may
|
||||
// want to wait until you've stopped receiving them
|
||||
// (see the dedup example in cmd/fsnotify).
|
||||
//
|
||||
// Some systems may send Write event for directories
|
||||
// when the directory content changes.
|
||||
//
|
||||
// fsnotify.Chmod Attributes were changed. On Linux this is also sent
|
||||
// when a file is removed (or more accurately, when a
|
||||
// link to an inode is removed). On kqueue it's sent
|
||||
// when a file is truncated. On Windows it's never
|
||||
// sent.
|
||||
EOF
|
||||
)
|
||||
|
||||
errors=$(<<EOF
|
||||
// Errors sends any errors.
|
||||
//
|
||||
// ErrEventOverflow is used to indicate there are too many events:
|
||||
//
|
||||
// - inotify: There are too many queued events (fs.inotify.max_queued_events sysctl)
|
||||
// - windows: The buffer size is too small; WithBufferSize() can be used to increase it.
|
||||
// - kqueue, fen: Not used.
|
||||
EOF
|
||||
)
|
||||
|
||||
set-cmt() {
|
||||
local pat=$1
|
||||
local cmt=$2
|
||||
|
||||
IFS=$'\n' local files=($(grep -n $pat backend_*~*_test.go))
|
||||
for f in $files; do
|
||||
IFS=':' local fields=($=f)
|
||||
local file=$fields[1]
|
||||
local end=$(( $fields[2] - 1 ))
|
||||
|
||||
# Find start of comment.
|
||||
local start=0
|
||||
IFS=$'\n' local lines=($(head -n$end $file))
|
||||
for (( i = 1; i <= $#lines; i++ )); do
|
||||
local line=$lines[-$i]
|
||||
if ! grep -q '^[[:space:]]*//' <<<$line; then
|
||||
start=$(( end - (i - 2) ))
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
head -n $(( start - 1 )) $file >/tmp/x
|
||||
print -r -- $cmt >>/tmp/x
|
||||
tail -n+$(( end + 1 )) $file >>/tmp/x
|
||||
mv /tmp/x $file
|
||||
done
|
||||
}
|
||||
|
||||
set-cmt '^type Watcher struct ' $watcher
|
||||
set-cmt '^func NewWatcher(' $new
|
||||
set-cmt '^func NewBufferedWatcher(' $newbuffered
|
||||
set-cmt '^func (w \*Watcher) Add(' $add
|
||||
set-cmt '^func (w \*Watcher) AddWith(' $addwith
|
||||
set-cmt '^func (w \*Watcher) Remove(' $remove
|
||||
set-cmt '^func (w \*Watcher) Close(' $close
|
||||
set-cmt '^func (w \*Watcher) WatchList(' $watchlist
|
||||
set-cmt '^[[:space:]]*Events *chan Event$' $events
|
||||
set-cmt '^[[:space:]]*Errors *chan error$' $errors
|
||||
1
vendor/github.com/fsnotify/fsnotify/system_bsd.go
generated
vendored
1
vendor/github.com/fsnotify/fsnotify/system_bsd.go
generated
vendored
|
|
@ -1,5 +1,4 @@
|
|||
//go:build freebsd || openbsd || netbsd || dragonfly
|
||||
// +build freebsd openbsd netbsd dragonfly
|
||||
|
||||
package fsnotify
|
||||
|
||||
|
|
|
|||
1
vendor/github.com/fsnotify/fsnotify/system_darwin.go
generated
vendored
1
vendor/github.com/fsnotify/fsnotify/system_darwin.go
generated
vendored
|
|
@ -1,5 +1,4 @@
|
|||
//go:build darwin
|
||||
// +build darwin
|
||||
|
||||
package fsnotify
|
||||
|
||||
|
|
|
|||
205
vendor/github.com/magiconair/properties/CHANGELOG.md
generated
vendored
205
vendor/github.com/magiconair/properties/CHANGELOG.md
generated
vendored
|
|
@ -1,205 +0,0 @@
|
|||
## Changelog
|
||||
|
||||
### [1.8.7](https://github.com/magiconair/properties/tree/v1.8.7) - 08 Dec 2022
|
||||
|
||||
* [PR #65](https://github.com/magiconair/properties/pull/65): Speedup Merge
|
||||
|
||||
Thanks to [@AdityaVallabh](https://github.com/AdityaVallabh) for the patch.
|
||||
|
||||
* [PR #66](https://github.com/magiconair/properties/pull/66): use github actions
|
||||
|
||||
### [1.8.6](https://github.com/magiconair/properties/tree/v1.8.6) - 23 Feb 2022
|
||||
|
||||
* [PR #57](https://github.com/magiconair/properties/pull/57):Fix "unreachable code" lint error
|
||||
|
||||
Thanks to [@ellie](https://github.com/ellie) for the patch.
|
||||
|
||||
* [PR #63](https://github.com/magiconair/properties/pull/63): Make TestMustGetParsedDuration backwards compatible
|
||||
|
||||
This patch ensures that the `TestMustGetParsedDuration` still works with `go1.3` to make the
|
||||
author happy until it affects real users.
|
||||
|
||||
Thanks to [@maage](https://github.com/maage) for the patch.
|
||||
|
||||
### [1.8.5](https://github.com/magiconair/properties/tree/v1.8.5) - 24 Mar 2021
|
||||
|
||||
* [PR #55](https://github.com/magiconair/properties/pull/55): Fix: Encoding Bug in Comments
|
||||
|
||||
When reading comments \ are loaded correctly, but when writing they are then
|
||||
replaced by \\. This leads to wrong comments when writing and reading multiple times.
|
||||
|
||||
Thanks to [@doxsch](https://github.com/doxsch) for the patch.
|
||||
|
||||
### [1.8.4](https://github.com/magiconair/properties/tree/v1.8.4) - 23 Sep 2020
|
||||
|
||||
* [PR #50](https://github.com/magiconair/properties/pull/50): enhance error message for circular references
|
||||
|
||||
Thanks to [@sriv](https://github.com/sriv) for the patch.
|
||||
|
||||
### [1.8.3](https://github.com/magiconair/properties/tree/v1.8.3) - 14 Sep 2020
|
||||
|
||||
* [PR #49](https://github.com/magiconair/properties/pull/49): Include the key in error message causing the circular reference
|
||||
|
||||
The change is include the key in the error message which is causing the circular
|
||||
reference when parsing/loading the properties files.
|
||||
|
||||
Thanks to [@haroon-sheikh](https://github.com/haroon-sheikh) for the patch.
|
||||
|
||||
### [1.8.2](https://github.com/magiconair/properties/tree/v1.8.2) - 25 Aug 2020
|
||||
|
||||
* [PR #36](https://github.com/magiconair/properties/pull/36): Escape backslash on write
|
||||
|
||||
This patch ensures that backslashes are escaped on write. Existing applications which
|
||||
rely on the old behavior may need to be updated.
|
||||
|
||||
Thanks to [@apesternikov](https://github.com/apesternikov) for the patch.
|
||||
|
||||
* [PR #42](https://github.com/magiconair/properties/pull/42): Made Content-Type check whitespace agnostic in LoadURL()
|
||||
|
||||
Thanks to [@aliras1](https://github.com/aliras1) for the patch.
|
||||
|
||||
* [PR #41](https://github.com/magiconair/properties/pull/41): Make key/value separator configurable on Write()
|
||||
|
||||
Thanks to [@mkjor](https://github.com/mkjor) for the patch.
|
||||
|
||||
* [PR #40](https://github.com/magiconair/properties/pull/40): Add method to return a sorted list of keys
|
||||
|
||||
Thanks to [@mkjor](https://github.com/mkjor) for the patch.
|
||||
|
||||
### [1.8.1](https://github.com/magiconair/properties/tree/v1.8.1) - 10 May 2019
|
||||
|
||||
* [PR #35](https://github.com/magiconair/properties/pull/35): Close body always after request
|
||||
|
||||
This patch ensures that in `LoadURL` the response body is always closed.
|
||||
|
||||
Thanks to [@liubog2008](https://github.com/liubog2008) for the patch.
|
||||
|
||||
### [1.8](https://github.com/magiconair/properties/tree/v1.8) - 15 May 2018
|
||||
|
||||
* [PR #26](https://github.com/magiconair/properties/pull/26): Disable expansion during loading
|
||||
|
||||
This adds the option to disable property expansion during loading.
|
||||
|
||||
Thanks to [@kmala](https://github.com/kmala) for the patch.
|
||||
|
||||
### [1.7.6](https://github.com/magiconair/properties/tree/v1.7.6) - 14 Feb 2018
|
||||
|
||||
* [PR #29](https://github.com/magiconair/properties/pull/29): Reworked expansion logic to handle more complex cases.
|
||||
|
||||
See PR for an example.
|
||||
|
||||
Thanks to [@yobert](https://github.com/yobert) for the fix.
|
||||
|
||||
### [1.7.5](https://github.com/magiconair/properties/tree/v1.7.5) - 13 Feb 2018
|
||||
|
||||
* [PR #28](https://github.com/magiconair/properties/pull/28): Support duplicate expansions in the same value
|
||||
|
||||
Values which expand the same key multiple times (e.g. `key=${a} ${a}`) will no longer fail
|
||||
with a `circular reference error`.
|
||||
|
||||
Thanks to [@yobert](https://github.com/yobert) for the fix.
|
||||
|
||||
### [1.7.4](https://github.com/magiconair/properties/tree/v1.7.4) - 31 Oct 2017
|
||||
|
||||
* [Issue #23](https://github.com/magiconair/properties/issues/23): Ignore blank lines with whitespaces
|
||||
|
||||
* [PR #24](https://github.com/magiconair/properties/pull/24): Update keys when DisableExpansion is enabled
|
||||
|
||||
Thanks to [@mgurov](https://github.com/mgurov) for the fix.
|
||||
|
||||
### [1.7.3](https://github.com/magiconair/properties/tree/v1.7.3) - 10 Jul 2017
|
||||
|
||||
* [Issue #17](https://github.com/magiconair/properties/issues/17): Add [SetValue()](http://godoc.org/github.com/magiconair/properties#Properties.SetValue) method to set values generically
|
||||
* [Issue #22](https://github.com/magiconair/properties/issues/22): Add [LoadMap()](http://godoc.org/github.com/magiconair/properties#LoadMap) function to load properties from a string map
|
||||
|
||||
### [1.7.2](https://github.com/magiconair/properties/tree/v1.7.2) - 20 Mar 2017
|
||||
|
||||
* [Issue #15](https://github.com/magiconair/properties/issues/15): Drop gocheck dependency
|
||||
* [PR #21](https://github.com/magiconair/properties/pull/21): Add [Map()](http://godoc.org/github.com/magiconair/properties#Properties.Map) and [FilterFunc()](http://godoc.org/github.com/magiconair/properties#Properties.FilterFunc)
|
||||
|
||||
### [1.7.1](https://github.com/magiconair/properties/tree/v1.7.1) - 13 Jan 2017
|
||||
|
||||
* [Issue #14](https://github.com/magiconair/properties/issues/14): Decouple TestLoadExpandedFile from `$USER`
|
||||
* [PR #12](https://github.com/magiconair/properties/pull/12): Load from files and URLs
|
||||
* [PR #16](https://github.com/magiconair/properties/pull/16): Keep gofmt happy
|
||||
* [PR #18](https://github.com/magiconair/properties/pull/18): Fix Delete() function
|
||||
|
||||
### [1.7.0](https://github.com/magiconair/properties/tree/v1.7.0) - 20 Mar 2016
|
||||
|
||||
* [Issue #10](https://github.com/magiconair/properties/issues/10): Add [LoadURL,LoadURLs,MustLoadURL,MustLoadURLs](http://godoc.org/github.com/magiconair/properties#LoadURL) method to load properties from a URL.
|
||||
* [Issue #11](https://github.com/magiconair/properties/issues/11): Add [LoadString,MustLoadString](http://godoc.org/github.com/magiconair/properties#LoadString) method to load properties from an UTF8 string.
|
||||
* [PR #8](https://github.com/magiconair/properties/pull/8): Add [MustFlag](http://godoc.org/github.com/magiconair/properties#Properties.MustFlag) method to provide overrides via command line flags. (@pascaldekloe)
|
||||
|
||||
### [1.6.0](https://github.com/magiconair/properties/tree/v1.6.0) - 11 Dec 2015
|
||||
|
||||
* Add [Decode](http://godoc.org/github.com/magiconair/properties#Properties.Decode) method to populate struct from properties via tags.
|
||||
|
||||
### [1.5.6](https://github.com/magiconair/properties/tree/v1.5.6) - 18 Oct 2015
|
||||
|
||||
* Vendored in gopkg.in/check.v1
|
||||
|
||||
### [1.5.5](https://github.com/magiconair/properties/tree/v1.5.5) - 31 Jul 2015
|
||||
|
||||
* [PR #6](https://github.com/magiconair/properties/pull/6): Add [Delete](http://godoc.org/github.com/magiconair/properties#Properties.Delete) method to remove keys including comments. (@gerbenjacobs)
|
||||
|
||||
### [1.5.4](https://github.com/magiconair/properties/tree/v1.5.4) - 23 Jun 2015
|
||||
|
||||
* [Issue #5](https://github.com/magiconair/properties/issues/5): Allow disabling of property expansion [DisableExpansion](http://godoc.org/github.com/magiconair/properties#Properties.DisableExpansion). When property expansion is disabled Properties become a simple key/value store and don't check for circular references.
|
||||
|
||||
### [1.5.3](https://github.com/magiconair/properties/tree/v1.5.3) - 02 Jun 2015
|
||||
|
||||
* [Issue #4](https://github.com/magiconair/properties/issues/4): Maintain key order in [Filter()](http://godoc.org/github.com/magiconair/properties#Properties.Filter), [FilterPrefix()](http://godoc.org/github.com/magiconair/properties#Properties.FilterPrefix) and [FilterRegexp()](http://godoc.org/github.com/magiconair/properties#Properties.FilterRegexp)
|
||||
|
||||
### [1.5.2](https://github.com/magiconair/properties/tree/v1.5.2) - 10 Apr 2015
|
||||
|
||||
* [Issue #3](https://github.com/magiconair/properties/issues/3): Don't print comments in [WriteComment()](http://godoc.org/github.com/magiconair/properties#Properties.WriteComment) if they are all empty
|
||||
* Add clickable links to README
|
||||
|
||||
### [1.5.1](https://github.com/magiconair/properties/tree/v1.5.1) - 08 Dec 2014
|
||||
|
||||
* Added [GetParsedDuration()](http://godoc.org/github.com/magiconair/properties#Properties.GetParsedDuration) and [MustGetParsedDuration()](http://godoc.org/github.com/magiconair/properties#Properties.MustGetParsedDuration) for values specified compatible with
|
||||
[time.ParseDuration()](http://golang.org/pkg/time/#ParseDuration).
|
||||
|
||||
### [1.5.0](https://github.com/magiconair/properties/tree/v1.5.0) - 18 Nov 2014
|
||||
|
||||
* Added support for single and multi-line comments (reading, writing and updating)
|
||||
* The order of keys is now preserved
|
||||
* Calling [Set()](http://godoc.org/github.com/magiconair/properties#Properties.Set) with an empty key now silently ignores the call and does not create a new entry
|
||||
* Added a [MustSet()](http://godoc.org/github.com/magiconair/properties#Properties.MustSet) method
|
||||
* Migrated test library from launchpad.net/gocheck to [gopkg.in/check.v1](http://gopkg.in/check.v1)
|
||||
|
||||
### [1.4.2](https://github.com/magiconair/properties/tree/v1.4.2) - 15 Nov 2014
|
||||
|
||||
* [Issue #2](https://github.com/magiconair/properties/issues/2): Fixed goroutine leak in parser which created two lexers but cleaned up only one
|
||||
|
||||
### [1.4.1](https://github.com/magiconair/properties/tree/v1.4.1) - 13 Nov 2014
|
||||
|
||||
* [Issue #1](https://github.com/magiconair/properties/issues/1): Fixed bug in Keys() method which returned an empty string
|
||||
|
||||
### [1.4.0](https://github.com/magiconair/properties/tree/v1.4.0) - 23 Sep 2014
|
||||
|
||||
* Added [Keys()](http://godoc.org/github.com/magiconair/properties#Properties.Keys) to get the keys
|
||||
* Added [Filter()](http://godoc.org/github.com/magiconair/properties#Properties.Filter), [FilterRegexp()](http://godoc.org/github.com/magiconair/properties#Properties.FilterRegexp) and [FilterPrefix()](http://godoc.org/github.com/magiconair/properties#Properties.FilterPrefix) to get a subset of the properties
|
||||
|
||||
### [1.3.0](https://github.com/magiconair/properties/tree/v1.3.0) - 18 Mar 2014
|
||||
|
||||
* Added support for time.Duration
|
||||
* Made MustXXX() failure beha[ior configurable (log.Fatal, panic](https://github.com/magiconair/properties/tree/vior configurable (log.Fatal, panic) - custom)
|
||||
* Changed default of MustXXX() failure from panic to log.Fatal
|
||||
|
||||
### [1.2.0](https://github.com/magiconair/properties/tree/v1.2.0) - 05 Mar 2014
|
||||
|
||||
* Added MustGet... functions
|
||||
* Added support for int and uint with range checks on 32 bit platforms
|
||||
|
||||
### [1.1.0](https://github.com/magiconair/properties/tree/v1.1.0) - 20 Jan 2014
|
||||
|
||||
* Renamed from goproperties to properties
|
||||
* Added support for expansion of environment vars in
|
||||
filenames and value expressions
|
||||
* Fixed bug where value expressions were not at the
|
||||
start of the string
|
||||
|
||||
### [1.0.0](https://github.com/magiconair/properties/tree/v1.0.0) - 7 Jan 2014
|
||||
|
||||
* Initial release
|
||||
30
vendor/github.com/magiconair/properties/README.md
generated
vendored
30
vendor/github.com/magiconair/properties/README.md
generated
vendored
|
|
@ -1,12 +1,9 @@
|
|||
[](https://github.com/magiconair/properties/releases)
|
||||
[](https://travis-ci.org/magiconair/properties)
|
||||
[](https://raw.githubusercontent.com/magiconair/properties/master/LICENSE)
|
||||
[](http://godoc.org/github.com/magiconair/properties)
|
||||
|
||||
# Overview
|
||||
|
||||
#### Please run `git pull --tags` to update the tags. See [below](#updated-git-tags) why.
|
||||
|
||||
properties is a Go library for reading and writing properties files.
|
||||
|
||||
It supports reading from multiple files or URLs and Spring style recursive
|
||||
|
|
@ -99,30 +96,3 @@ $ go get -u github.com/magiconair/properties
|
|||
## ToDo
|
||||
|
||||
* Dump contents with passwords and secrets obscured
|
||||
|
||||
## Updated Git tags
|
||||
|
||||
#### 13 Feb 2018
|
||||
|
||||
I realized that all of the git tags I had pushed before v1.7.5 were lightweight tags
|
||||
and I've only recently learned that this doesn't play well with `git describe` 😞
|
||||
|
||||
I have replaced all lightweight tags with signed tags using this script which should
|
||||
retain the commit date, name and email address. Please run `git pull --tags` to update them.
|
||||
|
||||
Worst case you have to reclone the repo.
|
||||
|
||||
```shell
|
||||
#!/bin/bash
|
||||
tag=$1
|
||||
echo "Updating $tag"
|
||||
date=$(git show ${tag}^0 --format=%aD | head -1)
|
||||
email=$(git show ${tag}^0 --format=%aE | head -1)
|
||||
name=$(git show ${tag}^0 --format=%aN | head -1)
|
||||
GIT_COMMITTER_DATE="$date" GIT_COMMITTER_NAME="$name" GIT_COMMITTER_EMAIL="$email" git tag -s -f ${tag} ${tag}^0 -m ${tag}
|
||||
```
|
||||
|
||||
I apologize for the inconvenience.
|
||||
|
||||
Frank
|
||||
|
||||
|
|
|
|||
6
vendor/github.com/magiconair/properties/decode.go
generated
vendored
6
vendor/github.com/magiconair/properties/decode.go
generated
vendored
|
|
@ -189,12 +189,12 @@ func dec(p *Properties, key string, def *string, opts map[string]string, v refle
|
|||
for i := 0; i < v.NumField(); i++ {
|
||||
fv := v.Field(i)
|
||||
fk, def, opts := keydef(t.Field(i))
|
||||
if !fv.CanSet() {
|
||||
return fmt.Errorf("cannot set %s", t.Field(i).Name)
|
||||
}
|
||||
if fk == "-" {
|
||||
continue
|
||||
}
|
||||
if !fv.CanSet() {
|
||||
return fmt.Errorf("cannot set %s", t.Field(i).Name)
|
||||
}
|
||||
if key != "" {
|
||||
fk = key + "." + fk
|
||||
}
|
||||
|
|
|
|||
27
vendor/github.com/magiconair/properties/load.go
generated
vendored
27
vendor/github.com/magiconair/properties/load.go
generated
vendored
|
|
@ -6,7 +6,7 @@ package properties
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
|
|
@ -52,6 +52,15 @@ func (l *Loader) LoadBytes(buf []byte) (*Properties, error) {
|
|||
return l.loadBytes(buf, l.Encoding)
|
||||
}
|
||||
|
||||
// LoadReader reads an io.Reader into a Properties struct.
|
||||
func (l *Loader) LoadReader(r io.Reader) (*Properties, error) {
|
||||
if buf, err := io.ReadAll(r); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return l.loadBytes(buf, l.Encoding)
|
||||
}
|
||||
}
|
||||
|
||||
// LoadAll reads the content of multiple URLs or files in the given order into
|
||||
// a Properties struct. If IgnoreMissing is true then a 404 status code or
|
||||
// missing file will not be reported as error. Encoding sets the encoding for
|
||||
|
|
@ -91,7 +100,7 @@ func (l *Loader) LoadAll(names []string) (*Properties, error) {
|
|||
// If IgnoreMissing is true then a missing file will not be
|
||||
// reported as error.
|
||||
func (l *Loader) LoadFile(filename string) (*Properties, error) {
|
||||
data, err := ioutil.ReadFile(filename)
|
||||
data, err := os.ReadFile(filename)
|
||||
if err != nil {
|
||||
if l.IgnoreMissing && os.IsNotExist(err) {
|
||||
LogPrintf("properties: %s not found. skipping", filename)
|
||||
|
|
@ -126,7 +135,7 @@ func (l *Loader) LoadURL(url string) (*Properties, error) {
|
|||
return nil, fmt.Errorf("properties: %s returned %d", url, resp.StatusCode)
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("properties: %s error reading response. %s", url, err)
|
||||
}
|
||||
|
|
@ -185,6 +194,12 @@ func LoadFile(filename string, enc Encoding) (*Properties, error) {
|
|||
return l.LoadAll([]string{filename})
|
||||
}
|
||||
|
||||
// LoadReader reads an io.Reader into a Properties struct.
|
||||
func LoadReader(r io.Reader, enc Encoding) (*Properties, error) {
|
||||
l := &Loader{Encoding: enc}
|
||||
return l.LoadReader(r)
|
||||
}
|
||||
|
||||
// LoadFiles reads multiple files in the given order into
|
||||
// a Properties struct. If 'ignoreMissing' is true then
|
||||
// non-existent files will not be reported as error.
|
||||
|
|
@ -224,6 +239,12 @@ func MustLoadString(s string) *Properties {
|
|||
return must(LoadString(s))
|
||||
}
|
||||
|
||||
// MustLoadSReader reads an io.Reader into a Properties struct and
|
||||
// panics on error.
|
||||
func MustLoadReader(r io.Reader, enc Encoding) *Properties {
|
||||
return must(LoadReader(r, enc))
|
||||
}
|
||||
|
||||
// MustLoadFile reads a file into a Properties struct and
|
||||
// panics on error.
|
||||
func MustLoadFile(filename string, enc Encoding) *Properties {
|
||||
|
|
|
|||
1
vendor/github.com/pelletier/go-toml/v2/.goreleaser.yaml
generated
vendored
1
vendor/github.com/pelletier/go-toml/v2/.goreleaser.yaml
generated
vendored
|
|
@ -1,3 +1,4 @@
|
|||
version: 2
|
||||
before:
|
||||
hooks:
|
||||
- go mod tidy
|
||||
|
|
|
|||
2
vendor/github.com/pelletier/go-toml/v2/README.md
generated
vendored
2
vendor/github.com/pelletier/go-toml/v2/README.md
generated
vendored
|
|
@ -565,7 +565,7 @@ complete solutions exist out there.
|
|||
|
||||
## Versioning
|
||||
|
||||
Expect for parts explicitely marked otherwise, go-toml follows [Semantic
|
||||
Expect for parts explicitly marked otherwise, go-toml follows [Semantic
|
||||
Versioning](https://semver.org). The supported version of
|
||||
[TOML](https://github.com/toml-lang/toml) is indicated at the beginning of this
|
||||
document. The last two major versions of Go are supported (see [Go Release
|
||||
|
|
|
|||
24
vendor/github.com/pelletier/go-toml/v2/marshaler.go
generated
vendored
24
vendor/github.com/pelletier/go-toml/v2/marshaler.go
generated
vendored
|
|
@ -8,7 +8,7 @@ import (
|
|||
"io"
|
||||
"math"
|
||||
"reflect"
|
||||
"sort"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
|
@ -280,7 +280,7 @@ func (enc *Encoder) encode(b []byte, ctx encoderCtx, v reflect.Value) ([]byte, e
|
|||
}
|
||||
|
||||
hasTextMarshaler := v.Type().Implements(textMarshalerType)
|
||||
if hasTextMarshaler || (v.CanAddr() && reflect.PtrTo(v.Type()).Implements(textMarshalerType)) {
|
||||
if hasTextMarshaler || (v.CanAddr() && reflect.PointerTo(v.Type()).Implements(textMarshalerType)) {
|
||||
if !hasTextMarshaler {
|
||||
v = v.Addr()
|
||||
}
|
||||
|
|
@ -631,6 +631,18 @@ func (enc *Encoder) keyToString(k reflect.Value) (string, error) {
|
|||
return "", fmt.Errorf("toml: error marshalling key %v from text: %w", k, err)
|
||||
}
|
||||
return string(keyB), nil
|
||||
|
||||
case keyType.Kind() == reflect.Int || keyType.Kind() == reflect.Int8 || keyType.Kind() == reflect.Int16 || keyType.Kind() == reflect.Int32 || keyType.Kind() == reflect.Int64:
|
||||
return strconv.FormatInt(k.Int(), 10), nil
|
||||
|
||||
case keyType.Kind() == reflect.Uint || keyType.Kind() == reflect.Uint8 || keyType.Kind() == reflect.Uint16 || keyType.Kind() == reflect.Uint32 || keyType.Kind() == reflect.Uint64:
|
||||
return strconv.FormatUint(k.Uint(), 10), nil
|
||||
|
||||
case keyType.Kind() == reflect.Float32:
|
||||
return strconv.FormatFloat(k.Float(), 'f', -1, 32), nil
|
||||
|
||||
case keyType.Kind() == reflect.Float64:
|
||||
return strconv.FormatFloat(k.Float(), 'f', -1, 64), nil
|
||||
}
|
||||
return "", fmt.Errorf("toml: type %s is not supported as a map key", keyType.Kind())
|
||||
}
|
||||
|
|
@ -668,8 +680,8 @@ func (enc *Encoder) encodeMap(b []byte, ctx encoderCtx, v reflect.Value) ([]byte
|
|||
}
|
||||
|
||||
func sortEntriesByKey(e []entry) {
|
||||
sort.Slice(e, func(i, j int) bool {
|
||||
return e[i].Key < e[j].Key
|
||||
slices.SortFunc(e, func(a, b entry) int {
|
||||
return strings.Compare(a.Key, b.Key)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -732,7 +744,7 @@ func walkStruct(ctx encoderCtx, t *table, v reflect.Value) {
|
|||
if fieldType.Anonymous {
|
||||
if fieldType.Type.Kind() == reflect.Struct {
|
||||
walkStruct(ctx, t, f)
|
||||
} else if fieldType.Type.Kind() == reflect.Pointer && !f.IsNil() && f.Elem().Kind() == reflect.Struct {
|
||||
} else if fieldType.Type.Kind() == reflect.Ptr && !f.IsNil() && f.Elem().Kind() == reflect.Struct {
|
||||
walkStruct(ctx, t, f.Elem())
|
||||
}
|
||||
continue
|
||||
|
|
@ -951,7 +963,7 @@ func willConvertToTable(ctx encoderCtx, v reflect.Value) bool {
|
|||
if !v.IsValid() {
|
||||
return false
|
||||
}
|
||||
if v.Type() == timeType || v.Type().Implements(textMarshalerType) || (v.Kind() != reflect.Ptr && v.CanAddr() && reflect.PtrTo(v.Type()).Implements(textMarshalerType)) {
|
||||
if v.Type() == timeType || v.Type().Implements(textMarshalerType) || (v.Kind() != reflect.Ptr && v.CanAddr() && reflect.PointerTo(v.Type()).Implements(textMarshalerType)) {
|
||||
return false
|
||||
}
|
||||
|
||||
|
|
|
|||
45
vendor/github.com/pelletier/go-toml/v2/unmarshaler.go
generated
vendored
45
vendor/github.com/pelletier/go-toml/v2/unmarshaler.go
generated
vendored
|
|
@ -5,9 +5,9 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
|
@ -21,10 +21,8 @@ import (
|
|||
//
|
||||
// It is a shortcut for Decoder.Decode() with the default options.
|
||||
func Unmarshal(data []byte, v interface{}) error {
|
||||
p := unstable.Parser{}
|
||||
p.Reset(data)
|
||||
d := decoder{p: &p}
|
||||
|
||||
d := decoder{}
|
||||
d.p.Reset(data)
|
||||
return d.FromParser(v)
|
||||
}
|
||||
|
||||
|
|
@ -117,27 +115,25 @@ func (d *Decoder) EnableUnmarshalerInterface() *Decoder {
|
|||
// Inline Table -> same as Table
|
||||
// Array of Tables -> same as Array and Table
|
||||
func (d *Decoder) Decode(v interface{}) error {
|
||||
b, err := ioutil.ReadAll(d.r)
|
||||
b, err := io.ReadAll(d.r)
|
||||
if err != nil {
|
||||
return fmt.Errorf("toml: %w", err)
|
||||
}
|
||||
|
||||
p := unstable.Parser{}
|
||||
p.Reset(b)
|
||||
dec := decoder{
|
||||
p: &p,
|
||||
strict: strict{
|
||||
Enabled: d.strict,
|
||||
},
|
||||
unmarshalerInterface: d.unmarshalerInterface,
|
||||
}
|
||||
dec.p.Reset(b)
|
||||
|
||||
return dec.FromParser(v)
|
||||
}
|
||||
|
||||
type decoder struct {
|
||||
// Which parser instance in use for this decoding session.
|
||||
p *unstable.Parser
|
||||
p unstable.Parser
|
||||
|
||||
// Flag indicating that the current expression is stashed.
|
||||
// If set to true, calling nextExpr will not actually pull a new expression
|
||||
|
|
@ -1078,12 +1074,39 @@ func (d *decoder) keyFromData(keyType reflect.Type, data []byte) (reflect.Value,
|
|||
}
|
||||
return mk, nil
|
||||
|
||||
case reflect.PtrTo(keyType).Implements(textUnmarshalerType):
|
||||
case reflect.PointerTo(keyType).Implements(textUnmarshalerType):
|
||||
mk := reflect.New(keyType)
|
||||
if err := mk.Interface().(encoding.TextUnmarshaler).UnmarshalText(data); err != nil {
|
||||
return reflect.Value{}, fmt.Errorf("toml: error unmarshalling key type %s from text: %w", stringType, err)
|
||||
}
|
||||
return mk.Elem(), nil
|
||||
|
||||
case keyType.Kind() == reflect.Int || keyType.Kind() == reflect.Int8 || keyType.Kind() == reflect.Int16 || keyType.Kind() == reflect.Int32 || keyType.Kind() == reflect.Int64:
|
||||
key, err := strconv.ParseInt(string(data), 10, 64)
|
||||
if err != nil {
|
||||
return reflect.Value{}, fmt.Errorf("toml: error parsing key of type %s from integer: %w", stringType, err)
|
||||
}
|
||||
return reflect.ValueOf(key).Convert(keyType), nil
|
||||
case keyType.Kind() == reflect.Uint || keyType.Kind() == reflect.Uint8 || keyType.Kind() == reflect.Uint16 || keyType.Kind() == reflect.Uint32 || keyType.Kind() == reflect.Uint64:
|
||||
key, err := strconv.ParseUint(string(data), 10, 64)
|
||||
if err != nil {
|
||||
return reflect.Value{}, fmt.Errorf("toml: error parsing key of type %s from unsigned integer: %w", stringType, err)
|
||||
}
|
||||
return reflect.ValueOf(key).Convert(keyType), nil
|
||||
|
||||
case keyType.Kind() == reflect.Float32:
|
||||
key, err := strconv.ParseFloat(string(data), 32)
|
||||
if err != nil {
|
||||
return reflect.Value{}, fmt.Errorf("toml: error parsing key of type %s from float: %w", stringType, err)
|
||||
}
|
||||
return reflect.ValueOf(float32(key)), nil
|
||||
|
||||
case keyType.Kind() == reflect.Float64:
|
||||
key, err := strconv.ParseFloat(string(data), 64)
|
||||
if err != nil {
|
||||
return reflect.Value{}, fmt.Errorf("toml: error parsing key of type %s from float: %w", stringType, err)
|
||||
}
|
||||
return reflect.ValueOf(float64(key)), nil
|
||||
}
|
||||
return reflect.Value{}, fmt.Errorf("toml: cannot convert map key of type %s to expected type %s", stringType, keyType)
|
||||
}
|
||||
|
|
|
|||
4
vendor/github.com/sagikazarmark/locafero/.envrc
generated
vendored
4
vendor/github.com/sagikazarmark/locafero/.envrc
generated
vendored
|
|
@ -1,4 +1,4 @@
|
|||
if ! has nix_direnv_version || ! nix_direnv_version 2.3.0; then
|
||||
source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/2.3.0/direnvrc" "sha256-Dmd+j63L84wuzgyjITIfSxSD57Tx7v51DMxVZOsiUD8="
|
||||
if ! has nix_direnv_version || ! nix_direnv_version 3.0.4; then
|
||||
source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/3.0.4/direnvrc" "sha256-DzlYZ33mWF/Gs8DDeyjr8mnVmQGx7ASYqA5WlxwvBG4="
|
||||
fi
|
||||
use flake . --impure
|
||||
|
|
|
|||
6
vendor/github.com/sagikazarmark/locafero/finder.go
generated
vendored
6
vendor/github.com/sagikazarmark/locafero/finder.go
generated
vendored
|
|
@ -27,7 +27,7 @@ type Finder struct {
|
|||
// It provides the capability to search for entries with depth,
|
||||
// meaning it can target deeper locations within the directory structure.
|
||||
//
|
||||
// It also supports glob syntax (as defined by [filepat.Match]), offering greater flexibility in search patterns.
|
||||
// It also supports glob syntax (as defined by [filepath.Match]), offering greater flexibility in search patterns.
|
||||
//
|
||||
// Examples:
|
||||
// - config.yaml
|
||||
|
|
@ -63,7 +63,7 @@ func (f Finder) Find(fsys afero.Fs) ([]string, error) {
|
|||
|
||||
// pool.Go(func() ([]string, error) {
|
||||
// // If the name contains any glob character, perform a glob match
|
||||
// if strings.ContainsAny(searchName, "*?[]\\^") {
|
||||
// if strings.ContainsAny(searchName, globMatch) {
|
||||
// return globWalkSearch(fsys, searchPath, searchName, f.Type)
|
||||
// }
|
||||
//
|
||||
|
|
@ -79,7 +79,7 @@ func (f Finder) Find(fsys afero.Fs) ([]string, error) {
|
|||
|
||||
allResults, err := iter.MapErr(searchItems, func(item *searchItem) ([]string, error) {
|
||||
// If the name contains any glob character, perform a glob match
|
||||
if strings.ContainsAny(item.name, "*?[]\\^") {
|
||||
if strings.ContainsAny(item.name, globMatch) {
|
||||
return globWalkSearch(fsys, item.path, item.name, f.Type)
|
||||
}
|
||||
|
||||
|
|
|
|||
333
vendor/github.com/sagikazarmark/locafero/flake.lock
generated
vendored
333
vendor/github.com/sagikazarmark/locafero/flake.lock
generated
vendored
|
|
@ -1,22 +1,84 @@
|
|||
{
|
||||
"nodes": {
|
||||
"devenv": {
|
||||
"cachix": {
|
||||
"inputs": {
|
||||
"flake-compat": "flake-compat",
|
||||
"nix": "nix",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"pre-commit-hooks": "pre-commit-hooks"
|
||||
"devenv": "devenv_2",
|
||||
"flake-compat": [
|
||||
"devenv",
|
||||
"flake-compat"
|
||||
],
|
||||
"nixpkgs": [
|
||||
"devenv",
|
||||
"nixpkgs"
|
||||
],
|
||||
"pre-commit-hooks": [
|
||||
"devenv",
|
||||
"pre-commit-hooks"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1694097209,
|
||||
"narHash": "sha256-gQmBjjxeSyySjbh0yQVBKApo2KWIFqqbRUvG+Fa+QpM=",
|
||||
"lastModified": 1712055811,
|
||||
"narHash": "sha256-7FcfMm5A/f02yyzuavJe06zLa9hcMHsagE28ADcmQvk=",
|
||||
"owner": "cachix",
|
||||
"repo": "devenv",
|
||||
"rev": "7a8e6a91510efe89d8dcb8e43233f93e86f6b189",
|
||||
"repo": "cachix",
|
||||
"rev": "02e38da89851ec7fec3356a5c04bc8349cae0e30",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "cachix",
|
||||
"repo": "cachix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"devenv": {
|
||||
"inputs": {
|
||||
"cachix": "cachix",
|
||||
"flake-compat": "flake-compat_2",
|
||||
"nix": "nix_2",
|
||||
"nixpkgs": "nixpkgs_2",
|
||||
"pre-commit-hooks": "pre-commit-hooks"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1725907707,
|
||||
"narHash": "sha256-s3pbtzZmVPHzc86WQjK7MGZMNvvw6hWnFMljEkllAfM=",
|
||||
"owner": "cachix",
|
||||
"repo": "devenv",
|
||||
"rev": "2bbbbc468fc02257265a79652a8350651cca495a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "cachix",
|
||||
"repo": "devenv",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"devenv_2": {
|
||||
"inputs": {
|
||||
"flake-compat": [
|
||||
"devenv",
|
||||
"cachix",
|
||||
"flake-compat"
|
||||
],
|
||||
"nix": "nix",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"poetry2nix": "poetry2nix",
|
||||
"pre-commit-hooks": [
|
||||
"devenv",
|
||||
"cachix",
|
||||
"pre-commit-hooks"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1708704632,
|
||||
"narHash": "sha256-w+dOIW60FKMaHI1q5714CSibk99JfYxm0CzTinYWr+Q=",
|
||||
"owner": "cachix",
|
||||
"repo": "devenv",
|
||||
"rev": "2ee4450b0f4b95a1b90f2eb5ffea98b90e48c196",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "cachix",
|
||||
"ref": "python-rewrite",
|
||||
"repo": "devenv",
|
||||
"type": "github"
|
||||
}
|
||||
|
|
@ -37,16 +99,32 @@
|
|||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-compat_2": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1696426674,
|
||||
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-parts": {
|
||||
"inputs": {
|
||||
"nixpkgs-lib": "nixpkgs-lib"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1693611461,
|
||||
"narHash": "sha256-aPODl8vAgGQ0ZYFIRisxYG5MOGSkIczvu2Cd8Gb9+1Y=",
|
||||
"lastModified": 1725234343,
|
||||
"narHash": "sha256-+ebgonl3NbiKD2UD0x4BszCZQ6sTfL4xioaM49o5B3Y=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"rev": "7f53fdb7bdc5bb237da7fefef12d099e4fd611ca",
|
||||
"rev": "567b938d64d4b4112ee253b9274472dc3a346eb6",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
@ -60,11 +138,29 @@
|
|||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1685518550,
|
||||
"narHash": "sha256-o2d0KcvaXzTrPRIo0kOLV0/QXHhDQ5DTi+OxcjO8xqY=",
|
||||
"lastModified": 1689068808,
|
||||
"narHash": "sha256-6ixXo3wt24N/melDWjq70UuHQLxGV8jZvooRanIHXw0=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "a1720a10a6cfe8234c0e93907ffe81be440f4cef",
|
||||
"rev": "919d646de7be200f3bf08cb76ae1f09402b6f9b4",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils_2": {
|
||||
"inputs": {
|
||||
"systems": "systems_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1710146030,
|
||||
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
@ -82,11 +178,11 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1660459072,
|
||||
"narHash": "sha256-8DFJjXG8zqoONA1vXtgeKXy68KdJL5UaXR8NtVMUbx8=",
|
||||
"lastModified": 1709087332,
|
||||
"narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "gitignore.nix",
|
||||
"rev": "a20de23b925fd8264fd7fad6454652e142fd7f73",
|
||||
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
@ -95,53 +191,90 @@
|
|||
"type": "github"
|
||||
}
|
||||
},
|
||||
"lowdown-src": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1633514407,
|
||||
"narHash": "sha256-Dw32tiMjdK9t3ETl5fzGrutQTzh2rufgZV4A/BbxuD4=",
|
||||
"owner": "kristapsdz",
|
||||
"repo": "lowdown",
|
||||
"rev": "d2c2b44ff6c27b936ec27358a2653caaef8f73b8",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "kristapsdz",
|
||||
"repo": "lowdown",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nix": {
|
||||
"inputs": {
|
||||
"lowdown-src": "lowdown-src",
|
||||
"flake-compat": "flake-compat",
|
||||
"nixpkgs": [
|
||||
"devenv",
|
||||
"cachix",
|
||||
"devenv",
|
||||
"nixpkgs"
|
||||
],
|
||||
"nixpkgs-regression": "nixpkgs-regression"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1676545802,
|
||||
"narHash": "sha256-EK4rZ+Hd5hsvXnzSzk2ikhStJnD63odF7SzsQ8CuSPU=",
|
||||
"lastModified": 1712911606,
|
||||
"narHash": "sha256-BGvBhepCufsjcUkXnEEXhEVjwdJAwPglCC2+bInc794=",
|
||||
"owner": "domenkozar",
|
||||
"repo": "nix",
|
||||
"rev": "7c91803598ffbcfe4a55c44ac6d49b2cf07a527f",
|
||||
"rev": "b24a9318ea3f3600c1e24b4a00691ee912d4de12",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "domenkozar",
|
||||
"ref": "relaxed-flakes",
|
||||
"ref": "devenv-2.21",
|
||||
"repo": "nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nix-github-actions": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"devenv",
|
||||
"cachix",
|
||||
"devenv",
|
||||
"poetry2nix",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1688870561,
|
||||
"narHash": "sha256-4UYkifnPEw1nAzqqPOTL2MvWtm3sNGw1UTYTalkTcGY=",
|
||||
"owner": "nix-community",
|
||||
"repo": "nix-github-actions",
|
||||
"rev": "165b1650b753316aa7f1787f3005a8d2da0f5301",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "nix-github-actions",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nix_2": {
|
||||
"inputs": {
|
||||
"flake-compat": [
|
||||
"devenv",
|
||||
"flake-compat"
|
||||
],
|
||||
"nixpkgs": [
|
||||
"devenv",
|
||||
"nixpkgs"
|
||||
],
|
||||
"nixpkgs-regression": "nixpkgs-regression_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1712911606,
|
||||
"narHash": "sha256-BGvBhepCufsjcUkXnEEXhEVjwdJAwPglCC2+bInc794=",
|
||||
"owner": "domenkozar",
|
||||
"repo": "nix",
|
||||
"rev": "b24a9318ea3f3600c1e24b4a00691ee912d4de12",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "domenkozar",
|
||||
"ref": "devenv-2.21",
|
||||
"repo": "nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1678875422,
|
||||
"narHash": "sha256-T3o6NcQPwXjxJMn2shz86Chch4ljXgZn746c2caGxd8=",
|
||||
"lastModified": 1692808169,
|
||||
"narHash": "sha256-x9Opq06rIiwdwGeK2Ykj69dNc2IvUH1fY55Wm7atwrE=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "126f49a01de5b7e35a43fd43f891ecf6d3a51459",
|
||||
"rev": "9201b5ff357e781bf014d0330d18555695df7ba8",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
@ -153,20 +286,14 @@
|
|||
},
|
||||
"nixpkgs-lib": {
|
||||
"locked": {
|
||||
"dir": "lib",
|
||||
"lastModified": 1693471703,
|
||||
"narHash": "sha256-0l03ZBL8P1P6z8MaSDS/MvuU8E75rVxe5eE1N6gxeTo=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "3e52e76b70d5508f3cec70b882a29199f4d1ee85",
|
||||
"type": "github"
|
||||
"lastModified": 1725233747,
|
||||
"narHash": "sha256-Ss8QWLXdr2JCBPcYChJhz4xJm+h/xjl4G0c0XlP6a74=",
|
||||
"type": "tarball",
|
||||
"url": "https://github.com/NixOS/nixpkgs/archive/356624c12086a18f2ea2825fed34523d60ccc4e3.tar.gz"
|
||||
},
|
||||
"original": {
|
||||
"dir": "lib",
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
"type": "tarball",
|
||||
"url": "https://github.com/NixOS/nixpkgs/archive/356624c12086a18f2ea2825fed34523d60ccc4e3.tar.gz"
|
||||
}
|
||||
},
|
||||
"nixpkgs-regression": {
|
||||
|
|
@ -185,29 +312,61 @@
|
|||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-stable": {
|
||||
"nixpkgs-regression_2": {
|
||||
"locked": {
|
||||
"lastModified": 1685801374,
|
||||
"narHash": "sha256-otaSUoFEMM+LjBI1XL/xGB5ao6IwnZOXc47qhIgJe8U=",
|
||||
"lastModified": 1643052045,
|
||||
"narHash": "sha256-uGJ0VXIhWKGXxkeNnq4TvV3CIOkUJ3PAoLZ3HMzNVMw=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "c37ca420157f4abc31e26f436c1145f8951ff373",
|
||||
"rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-23.05",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-stable": {
|
||||
"locked": {
|
||||
"lastModified": 1710695816,
|
||||
"narHash": "sha256-3Eh7fhEID17pv9ZxrPwCLfqXnYP006RKzSs0JptsN84=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "614b4613980a522ba49f0d194531beddbb7220d3",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-23.11",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1694343207,
|
||||
"narHash": "sha256-jWi7OwFxU5Owi4k2JmiL1sa/OuBCQtpaAesuj5LXC8w=",
|
||||
"lastModified": 1713361204,
|
||||
"narHash": "sha256-TA6EDunWTkc5FvDCqU3W2T3SFn0gRZqh6D/hJnM02MM=",
|
||||
"owner": "cachix",
|
||||
"repo": "devenv-nixpkgs",
|
||||
"rev": "285676e87ad9f0ca23d8714a6ab61e7e027020c6",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "cachix",
|
||||
"ref": "rolling",
|
||||
"repo": "devenv-nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_3": {
|
||||
"locked": {
|
||||
"lastModified": 1725910328,
|
||||
"narHash": "sha256-n9pCtzGZ0httmTwMuEbi5E78UQ4ZbQMr1pzi5N0LAG8=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "78058d810644f5ed276804ce7ea9e82d92bee293",
|
||||
"rev": "5775c2583f1801df7b790bf7f7d710a19bac66f4",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
@ -217,13 +376,38 @@
|
|||
"type": "github"
|
||||
}
|
||||
},
|
||||
"poetry2nix": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"nix-github-actions": "nix-github-actions",
|
||||
"nixpkgs": [
|
||||
"devenv",
|
||||
"cachix",
|
||||
"devenv",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1692876271,
|
||||
"narHash": "sha256-IXfZEkI0Mal5y1jr6IRWMqK8GW2/f28xJenZIPQqkY0=",
|
||||
"owner": "nix-community",
|
||||
"repo": "poetry2nix",
|
||||
"rev": "d5006be9c2c2417dafb2e2e5034d83fabd207ee3",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "poetry2nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"pre-commit-hooks": {
|
||||
"inputs": {
|
||||
"flake-compat": [
|
||||
"devenv",
|
||||
"flake-compat"
|
||||
],
|
||||
"flake-utils": "flake-utils",
|
||||
"flake-utils": "flake-utils_2",
|
||||
"gitignore": "gitignore",
|
||||
"nixpkgs": [
|
||||
"devenv",
|
||||
|
|
@ -232,11 +416,11 @@
|
|||
"nixpkgs-stable": "nixpkgs-stable"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1688056373,
|
||||
"narHash": "sha256-2+SDlNRTKsgo3LBRiMUcoEUb6sDViRNQhzJquZ4koOI=",
|
||||
"lastModified": 1713775815,
|
||||
"narHash": "sha256-Wu9cdYTnGQQwtT20QQMg7jzkANKQjwBD9iccfGKkfls=",
|
||||
"owner": "cachix",
|
||||
"repo": "pre-commit-hooks.nix",
|
||||
"rev": "5843cf069272d92b60c3ed9e55b7a8989c01d4c7",
|
||||
"rev": "2ac4dcbf55ed43f3be0bae15e181f08a57af24a4",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
@ -249,7 +433,7 @@
|
|||
"inputs": {
|
||||
"devenv": "devenv",
|
||||
"flake-parts": "flake-parts",
|
||||
"nixpkgs": "nixpkgs_2"
|
||||
"nixpkgs": "nixpkgs_3"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
|
|
@ -266,6 +450,21 @@
|
|||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems_2": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
|
|
|
|||
21
vendor/github.com/sagikazarmark/locafero/flake.nix
generated
vendored
21
vendor/github.com/sagikazarmark/locafero/flake.nix
generated
vendored
|
|
@ -20,6 +20,7 @@
|
|||
default = {
|
||||
languages = {
|
||||
go.enable = true;
|
||||
go.package = pkgs.lib.mkDefault pkgs.go_1_23;
|
||||
};
|
||||
|
||||
packages = with pkgs; [
|
||||
|
|
@ -34,11 +35,27 @@
|
|||
|
||||
ci = devenv.shells.default;
|
||||
|
||||
ci_1_20 = {
|
||||
ci_1_21 = {
|
||||
imports = [ devenv.shells.ci ];
|
||||
|
||||
languages = {
|
||||
go.package = pkgs.go_1_20;
|
||||
go.package = pkgs.go_1_21;
|
||||
};
|
||||
};
|
||||
|
||||
ci_1_22 = {
|
||||
imports = [ devenv.shells.ci ];
|
||||
|
||||
languages = {
|
||||
go.package = pkgs.go_1_22;
|
||||
};
|
||||
};
|
||||
|
||||
ci_1_23 = {
|
||||
imports = [ devenv.shells.ci ];
|
||||
|
||||
languages = {
|
||||
go.package = pkgs.go_1_23;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
|||
5
vendor/github.com/sagikazarmark/locafero/glob.go
generated
vendored
Normal file
5
vendor/github.com/sagikazarmark/locafero/glob.go
generated
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
//go:build !windows
|
||||
|
||||
package locafero
|
||||
|
||||
const globMatch = "*?[]\\^"
|
||||
8
vendor/github.com/sagikazarmark/locafero/glob_windows.go
generated
vendored
Normal file
8
vendor/github.com/sagikazarmark/locafero/glob_windows.go
generated
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
//go:build windows
|
||||
|
||||
package locafero
|
||||
|
||||
// See [filepath.Match]:
|
||||
//
|
||||
// On Windows, escaping is disabled. Instead, '\\' is treated as path separator.
|
||||
const globMatch = "*?[]^"
|
||||
|
|
@ -1,12 +1,12 @@
|
|||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_size = 4
|
||||
indent_style = space
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.go]
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
insert_final_newline = true
|
||||
|
||||
[*.{yml,yaml}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
18
vendor/github.com/spf13/afero/.golangci.yaml
generated
vendored
Normal file
18
vendor/github.com/spf13/afero/.golangci.yaml
generated
vendored
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
linters-settings:
|
||||
gci:
|
||||
sections:
|
||||
- standard
|
||||
- default
|
||||
- prefix(github.com/spf13/afero)
|
||||
|
||||
linters:
|
||||
disable-all: true
|
||||
enable:
|
||||
- gci
|
||||
- gofmt
|
||||
- gofumpt
|
||||
- staticcheck
|
||||
|
||||
issues:
|
||||
exclude-dirs:
|
||||
- gcsfs/internal/stiface
|
||||
2
vendor/github.com/spf13/afero/README.md
generated
vendored
2
vendor/github.com/spf13/afero/README.md
generated
vendored
|
|
@ -12,7 +12,7 @@ types and methods. Afero has an exceptionally clean interface and simple design
|
|||
without needless constructors or initialization methods.
|
||||
|
||||
Afero is also a library providing a base set of interoperable backend
|
||||
filesystems that make it easy to work with afero while retaining all the power
|
||||
filesystems that make it easy to work with, while retaining all the power
|
||||
and benefit of the os and ioutil packages.
|
||||
|
||||
Afero provides significant improvements over using the os package alone, most
|
||||
|
|
|
|||
1
vendor/github.com/spf13/afero/iofs.go
generated
vendored
1
vendor/github.com/spf13/afero/iofs.go
generated
vendored
|
|
@ -255,7 +255,6 @@ func (f fromIOFSFile) Readdir(count int) ([]os.FileInfo, error) {
|
|||
ret := make([]os.FileInfo, len(entries))
|
||||
for i := range entries {
|
||||
ret[i], err = entries[i].Info()
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
2
vendor/github.com/spf13/afero/memmap.go
generated
vendored
2
vendor/github.com/spf13/afero/memmap.go
generated
vendored
|
|
@ -16,11 +16,9 @@ package afero
|
|||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
|
|
|
|||
2
vendor/github.com/spf13/cast/README.md
generated
vendored
2
vendor/github.com/spf13/cast/README.md
generated
vendored
|
|
@ -1,6 +1,6 @@
|
|||
# cast
|
||||
|
||||
[](https://github.com/spf13/cast/actions/workflows/ci.yaml)
|
||||
[](https://github.com/spf13/cast/actions/workflows/test.yaml)
|
||||
[](https://pkg.go.dev/mod/github.com/spf13/cast)
|
||||

|
||||
[](https://goreportcard.com/report/github.com/spf13/cast)
|
||||
|
|
|
|||
98
vendor/github.com/spf13/cast/caste.go
generated
vendored
98
vendor/github.com/spf13/cast/caste.go
generated
vendored
|
|
@ -18,6 +18,14 @@ import (
|
|||
|
||||
var errNegativeNotAllowed = errors.New("unable to cast negative value")
|
||||
|
||||
type float64EProvider interface {
|
||||
Float64() (float64, error)
|
||||
}
|
||||
|
||||
type float64Provider interface {
|
||||
Float64() float64
|
||||
}
|
||||
|
||||
// ToTimeE casts an interface to a time.Time type.
|
||||
func ToTimeE(i interface{}) (tim time.Time, err error) {
|
||||
return ToTimeInDefaultLocationE(i, time.UTC)
|
||||
|
|
@ -77,11 +85,14 @@ func ToDurationE(i interface{}) (d time.Duration, err error) {
|
|||
d, err = time.ParseDuration(s + "ns")
|
||||
}
|
||||
return
|
||||
case json.Number:
|
||||
case float64EProvider:
|
||||
var v float64
|
||||
v, err = s.Float64()
|
||||
d = time.Duration(v)
|
||||
return
|
||||
case float64Provider:
|
||||
d = time.Duration(s.Float64())
|
||||
return
|
||||
default:
|
||||
err = fmt.Errorf("unable to cast %#v of type %T to Duration", i, i)
|
||||
return
|
||||
|
|
@ -174,12 +185,14 @@ func ToFloat64E(i interface{}) (float64, error) {
|
|||
return v, nil
|
||||
}
|
||||
return 0, fmt.Errorf("unable to cast %#v of type %T to float64", i, i)
|
||||
case json.Number:
|
||||
case float64EProvider:
|
||||
v, err := s.Float64()
|
||||
if err == nil {
|
||||
return v, nil
|
||||
}
|
||||
return 0, fmt.Errorf("unable to cast %#v of type %T to float64", i, i)
|
||||
case float64Provider:
|
||||
return s.Float64(), nil
|
||||
case bool:
|
||||
if s {
|
||||
return 1, nil
|
||||
|
|
@ -230,12 +243,14 @@ func ToFloat32E(i interface{}) (float32, error) {
|
|||
return float32(v), nil
|
||||
}
|
||||
return 0, fmt.Errorf("unable to cast %#v of type %T to float32", i, i)
|
||||
case json.Number:
|
||||
case float64EProvider:
|
||||
v, err := s.Float64()
|
||||
if err == nil {
|
||||
return float32(v), nil
|
||||
}
|
||||
return 0, fmt.Errorf("unable to cast %#v of type %T to float32", i, i)
|
||||
case float64Provider:
|
||||
return float32(s.Float64()), nil
|
||||
case bool:
|
||||
if s {
|
||||
return 1, nil
|
||||
|
|
@ -598,12 +613,12 @@ func ToUint64E(i interface{}) (uint64, error) {
|
|||
|
||||
switch s := i.(type) {
|
||||
case string:
|
||||
v, err := strconv.ParseInt(trimZeroDecimal(s), 0, 0)
|
||||
v, err := strconv.ParseUint(trimZeroDecimal(s), 0, 0)
|
||||
if err == nil {
|
||||
if v < 0 {
|
||||
return 0, errNegativeNotAllowed
|
||||
}
|
||||
return uint64(v), nil
|
||||
return v, nil
|
||||
}
|
||||
return 0, fmt.Errorf("unable to cast %#v of type %T to uint64", i, i)
|
||||
case json.Number:
|
||||
|
|
@ -917,8 +932,8 @@ func indirectToStringerOrError(a interface{}) interface{} {
|
|||
return nil
|
||||
}
|
||||
|
||||
var errorType = reflect.TypeOf((*error)(nil)).Elem()
|
||||
var fmtStringerType = reflect.TypeOf((*fmt.Stringer)(nil)).Elem()
|
||||
errorType := reflect.TypeOf((*error)(nil)).Elem()
|
||||
fmtStringerType := reflect.TypeOf((*fmt.Stringer)(nil)).Elem()
|
||||
|
||||
v := reflect.ValueOf(a)
|
||||
for !v.Type().Implements(fmtStringerType) && !v.Type().Implements(errorType) && v.Kind() == reflect.Ptr && !v.IsNil() {
|
||||
|
|
@ -987,7 +1002,7 @@ func ToStringE(i interface{}) (string, error) {
|
|||
|
||||
// ToStringMapStringE casts an interface to a map[string]string type.
|
||||
func ToStringMapStringE(i interface{}) (map[string]string, error) {
|
||||
var m = map[string]string{}
|
||||
m := map[string]string{}
|
||||
|
||||
switch v := i.(type) {
|
||||
case map[string]string:
|
||||
|
|
@ -1017,7 +1032,7 @@ func ToStringMapStringE(i interface{}) (map[string]string, error) {
|
|||
|
||||
// ToStringMapStringSliceE casts an interface to a map[string][]string type.
|
||||
func ToStringMapStringSliceE(i interface{}) (map[string][]string, error) {
|
||||
var m = map[string][]string{}
|
||||
m := map[string][]string{}
|
||||
|
||||
switch v := i.(type) {
|
||||
case map[string][]string:
|
||||
|
|
@ -1081,7 +1096,7 @@ func ToStringMapStringSliceE(i interface{}) (map[string][]string, error) {
|
|||
|
||||
// ToStringMapBoolE casts an interface to a map[string]bool type.
|
||||
func ToStringMapBoolE(i interface{}) (map[string]bool, error) {
|
||||
var m = map[string]bool{}
|
||||
m := map[string]bool{}
|
||||
|
||||
switch v := i.(type) {
|
||||
case map[interface{}]interface{}:
|
||||
|
|
@ -1106,7 +1121,7 @@ func ToStringMapBoolE(i interface{}) (map[string]bool, error) {
|
|||
|
||||
// ToStringMapE casts an interface to a map[string]interface{} type.
|
||||
func ToStringMapE(i interface{}) (map[string]interface{}, error) {
|
||||
var m = map[string]interface{}{}
|
||||
m := map[string]interface{}{}
|
||||
|
||||
switch v := i.(type) {
|
||||
case map[interface{}]interface{}:
|
||||
|
|
@ -1126,7 +1141,7 @@ func ToStringMapE(i interface{}) (map[string]interface{}, error) {
|
|||
|
||||
// ToStringMapIntE casts an interface to a map[string]int{} type.
|
||||
func ToStringMapIntE(i interface{}) (map[string]int, error) {
|
||||
var m = map[string]int{}
|
||||
m := map[string]int{}
|
||||
if i == nil {
|
||||
return m, fmt.Errorf("unable to cast %#v of type %T to map[string]int", i, i)
|
||||
}
|
||||
|
|
@ -1167,7 +1182,7 @@ func ToStringMapIntE(i interface{}) (map[string]int, error) {
|
|||
|
||||
// ToStringMapInt64E casts an interface to a map[string]int64{} type.
|
||||
func ToStringMapInt64E(i interface{}) (map[string]int64, error) {
|
||||
var m = map[string]int64{}
|
||||
m := map[string]int64{}
|
||||
if i == nil {
|
||||
return m, fmt.Errorf("unable to cast %#v of type %T to map[string]int64", i, i)
|
||||
}
|
||||
|
|
@ -1404,38 +1419,35 @@ func (f timeFormat) hasTimezone() bool {
|
|||
return f.typ >= timeFormatNumericTimezone && f.typ <= timeFormatNumericAndNamedTimezone
|
||||
}
|
||||
|
||||
var (
|
||||
timeFormats = []timeFormat{
|
||||
// Keep common formats at the top.
|
||||
{"2006-01-02", timeFormatNoTimezone},
|
||||
{time.RFC3339, timeFormatNumericTimezone},
|
||||
{"2006-01-02T15:04:05", timeFormatNoTimezone}, // iso8601 without timezone
|
||||
{time.RFC1123Z, timeFormatNumericTimezone},
|
||||
{time.RFC1123, timeFormatNamedTimezone},
|
||||
{time.RFC822Z, timeFormatNumericTimezone},
|
||||
{time.RFC822, timeFormatNamedTimezone},
|
||||
{time.RFC850, timeFormatNamedTimezone},
|
||||
{"2006-01-02 15:04:05.999999999 -0700 MST", timeFormatNumericAndNamedTimezone}, // Time.String()
|
||||
{"2006-01-02T15:04:05-0700", timeFormatNumericTimezone}, // RFC3339 without timezone hh:mm colon
|
||||
{"2006-01-02 15:04:05Z0700", timeFormatNumericTimezone}, // RFC3339 without T or timezone hh:mm colon
|
||||
{"2006-01-02 15:04:05", timeFormatNoTimezone},
|
||||
{time.ANSIC, timeFormatNoTimezone},
|
||||
{time.UnixDate, timeFormatNamedTimezone},
|
||||
{time.RubyDate, timeFormatNumericTimezone},
|
||||
{"2006-01-02 15:04:05Z07:00", timeFormatNumericTimezone},
|
||||
{"02 Jan 2006", timeFormatNoTimezone},
|
||||
{"2006-01-02 15:04:05 -07:00", timeFormatNumericTimezone},
|
||||
{"2006-01-02 15:04:05 -0700", timeFormatNumericTimezone},
|
||||
{time.Kitchen, timeFormatTimeOnly},
|
||||
{time.Stamp, timeFormatTimeOnly},
|
||||
{time.StampMilli, timeFormatTimeOnly},
|
||||
{time.StampMicro, timeFormatTimeOnly},
|
||||
{time.StampNano, timeFormatTimeOnly},
|
||||
}
|
||||
)
|
||||
var timeFormats = []timeFormat{
|
||||
// Keep common formats at the top.
|
||||
{"2006-01-02", timeFormatNoTimezone},
|
||||
{time.RFC3339, timeFormatNumericTimezone},
|
||||
{"2006-01-02T15:04:05", timeFormatNoTimezone}, // iso8601 without timezone
|
||||
{time.RFC1123Z, timeFormatNumericTimezone},
|
||||
{time.RFC1123, timeFormatNamedTimezone},
|
||||
{time.RFC822Z, timeFormatNumericTimezone},
|
||||
{time.RFC822, timeFormatNamedTimezone},
|
||||
{time.RFC850, timeFormatNamedTimezone},
|
||||
{"2006-01-02 15:04:05.999999999 -0700 MST", timeFormatNumericAndNamedTimezone}, // Time.String()
|
||||
{"2006-01-02T15:04:05-0700", timeFormatNumericTimezone}, // RFC3339 without timezone hh:mm colon
|
||||
{"2006-01-02 15:04:05Z0700", timeFormatNumericTimezone}, // RFC3339 without T or timezone hh:mm colon
|
||||
{"2006-01-02 15:04:05", timeFormatNoTimezone},
|
||||
{time.ANSIC, timeFormatNoTimezone},
|
||||
{time.UnixDate, timeFormatNamedTimezone},
|
||||
{time.RubyDate, timeFormatNumericTimezone},
|
||||
{"2006-01-02 15:04:05Z07:00", timeFormatNumericTimezone},
|
||||
{"02 Jan 2006", timeFormatNoTimezone},
|
||||
{"2006-01-02 15:04:05 -07:00", timeFormatNumericTimezone},
|
||||
{"2006-01-02 15:04:05 -0700", timeFormatNumericTimezone},
|
||||
{time.Kitchen, timeFormatTimeOnly},
|
||||
{time.Stamp, timeFormatTimeOnly},
|
||||
{time.StampMilli, timeFormatTimeOnly},
|
||||
{time.StampMicro, timeFormatTimeOnly},
|
||||
{time.StampNano, timeFormatTimeOnly},
|
||||
}
|
||||
|
||||
func parseDateWith(s string, location *time.Location, formats []timeFormat) (d time.Time, e error) {
|
||||
|
||||
for _, format := range formats {
|
||||
if d, e = time.Parse(format.format, s); e == nil {
|
||||
|
||||
|
|
|
|||
19
vendor/go.uber.org/atomic/.codecov.yml
generated
vendored
19
vendor/go.uber.org/atomic/.codecov.yml
generated
vendored
|
|
@ -1,19 +0,0 @@
|
|||
coverage:
|
||||
range: 80..100
|
||||
round: down
|
||||
precision: 2
|
||||
|
||||
status:
|
||||
project: # measuring the overall project coverage
|
||||
default: # context, you can create multiple ones with custom titles
|
||||
enabled: yes # must be yes|true to enable this status
|
||||
target: 100 # specify the target coverage for each commit status
|
||||
# option: "auto" (must increase from parent commit or pull request base)
|
||||
# option: "X%" a static target percentage to hit
|
||||
if_not_found: success # if parent is not found report status as success, error, or failure
|
||||
if_ci_failed: error # if ci fails report status as success, error, or failure
|
||||
|
||||
# Also update COVER_IGNORE_PKGS in the Makefile.
|
||||
ignore:
|
||||
- /internal/gen-atomicint/
|
||||
- /internal/gen-valuewrapper/
|
||||
15
vendor/go.uber.org/atomic/.gitignore
generated
vendored
15
vendor/go.uber.org/atomic/.gitignore
generated
vendored
|
|
@ -1,15 +0,0 @@
|
|||
/bin
|
||||
.DS_Store
|
||||
/vendor
|
||||
cover.html
|
||||
cover.out
|
||||
lint.log
|
||||
|
||||
# Binaries
|
||||
*.test
|
||||
|
||||
# Profiling output
|
||||
*.prof
|
||||
|
||||
# Output of fossa analyzer
|
||||
/fossa
|
||||
100
vendor/go.uber.org/atomic/CHANGELOG.md
generated
vendored
100
vendor/go.uber.org/atomic/CHANGELOG.md
generated
vendored
|
|
@ -1,100 +0,0 @@
|
|||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [1.9.0] - 2021-07-15
|
||||
### Added
|
||||
- Add `Float64.Swap` to match int atomic operations.
|
||||
- Add `atomic.Time` type for atomic operations on `time.Time` values.
|
||||
|
||||
[1.9.0]: https://github.com/uber-go/atomic/compare/v1.8.0...v1.9.0
|
||||
|
||||
## [1.8.0] - 2021-06-09
|
||||
### Added
|
||||
- Add `atomic.Uintptr` type for atomic operations on `uintptr` values.
|
||||
- Add `atomic.UnsafePointer` type for atomic operations on `unsafe.Pointer` values.
|
||||
|
||||
[1.8.0]: https://github.com/uber-go/atomic/compare/v1.7.0...v1.8.0
|
||||
|
||||
## [1.7.0] - 2020-09-14
|
||||
### Added
|
||||
- Support JSON serialization and deserialization of primitive atomic types.
|
||||
- Support Text marshalling and unmarshalling for string atomics.
|
||||
|
||||
### Changed
|
||||
- Disallow incorrect comparison of atomic values in a non-atomic way.
|
||||
|
||||
### Removed
|
||||
- Remove dependency on `golang.org/x/{lint, tools}`.
|
||||
|
||||
[1.7.0]: https://github.com/uber-go/atomic/compare/v1.6.0...v1.7.0
|
||||
|
||||
## [1.6.0] - 2020-02-24
|
||||
### Changed
|
||||
- Drop library dependency on `golang.org/x/{lint, tools}`.
|
||||
|
||||
[1.6.0]: https://github.com/uber-go/atomic/compare/v1.5.1...v1.6.0
|
||||
|
||||
## [1.5.1] - 2019-11-19
|
||||
- Fix bug where `Bool.CAS` and `Bool.Toggle` do work correctly together
|
||||
causing `CAS` to fail even though the old value matches.
|
||||
|
||||
[1.5.1]: https://github.com/uber-go/atomic/compare/v1.5.0...v1.5.1
|
||||
|
||||
## [1.5.0] - 2019-10-29
|
||||
### Changed
|
||||
- With Go modules, only the `go.uber.org/atomic` import path is supported now.
|
||||
If you need to use the old import path, please add a `replace` directive to
|
||||
your `go.mod`.
|
||||
|
||||
[1.5.0]: https://github.com/uber-go/atomic/compare/v1.4.0...v1.5.0
|
||||
|
||||
## [1.4.0] - 2019-05-01
|
||||
### Added
|
||||
- Add `atomic.Error` type for atomic operations on `error` values.
|
||||
|
||||
[1.4.0]: https://github.com/uber-go/atomic/compare/v1.3.2...v1.4.0
|
||||
|
||||
## [1.3.2] - 2018-05-02
|
||||
### Added
|
||||
- Add `atomic.Duration` type for atomic operations on `time.Duration` values.
|
||||
|
||||
[1.3.2]: https://github.com/uber-go/atomic/compare/v1.3.1...v1.3.2
|
||||
|
||||
## [1.3.1] - 2017-11-14
|
||||
### Fixed
|
||||
- Revert optimization for `atomic.String.Store("")` which caused data races.
|
||||
|
||||
[1.3.1]: https://github.com/uber-go/atomic/compare/v1.3.0...v1.3.1
|
||||
|
||||
## [1.3.0] - 2017-11-13
|
||||
### Added
|
||||
- Add `atomic.Bool.CAS` for compare-and-swap semantics on bools.
|
||||
|
||||
### Changed
|
||||
- Optimize `atomic.String.Store("")` by avoiding an allocation.
|
||||
|
||||
[1.3.0]: https://github.com/uber-go/atomic/compare/v1.2.0...v1.3.0
|
||||
|
||||
## [1.2.0] - 2017-04-12
|
||||
### Added
|
||||
- Shadow `atomic.Value` from `sync/atomic`.
|
||||
|
||||
[1.2.0]: https://github.com/uber-go/atomic/compare/v1.1.0...v1.2.0
|
||||
|
||||
## [1.1.0] - 2017-03-10
|
||||
### Added
|
||||
- Add atomic `Float64` type.
|
||||
|
||||
### Changed
|
||||
- Support new `go.uber.org/atomic` import path.
|
||||
|
||||
[1.1.0]: https://github.com/uber-go/atomic/compare/v1.0.0...v1.1.0
|
||||
|
||||
## [1.0.0] - 2016-07-18
|
||||
|
||||
- Initial release.
|
||||
|
||||
[1.0.0]: https://github.com/uber-go/atomic/releases/tag/v1.0.0
|
||||
19
vendor/go.uber.org/atomic/LICENSE.txt
generated
vendored
19
vendor/go.uber.org/atomic/LICENSE.txt
generated
vendored
|
|
@ -1,19 +0,0 @@
|
|||
Copyright (c) 2016 Uber Technologies, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
79
vendor/go.uber.org/atomic/Makefile
generated
vendored
79
vendor/go.uber.org/atomic/Makefile
generated
vendored
|
|
@ -1,79 +0,0 @@
|
|||
# Directory to place `go install`ed binaries into.
|
||||
export GOBIN ?= $(shell pwd)/bin
|
||||
|
||||
GOLINT = $(GOBIN)/golint
|
||||
GEN_ATOMICINT = $(GOBIN)/gen-atomicint
|
||||
GEN_ATOMICWRAPPER = $(GOBIN)/gen-atomicwrapper
|
||||
STATICCHECK = $(GOBIN)/staticcheck
|
||||
|
||||
GO_FILES ?= $(shell find . '(' -path .git -o -path vendor ')' -prune -o -name '*.go' -print)
|
||||
|
||||
# Also update ignore section in .codecov.yml.
|
||||
COVER_IGNORE_PKGS = \
|
||||
go.uber.org/atomic/internal/gen-atomicint \
|
||||
go.uber.org/atomic/internal/gen-atomicwrapper
|
||||
|
||||
.PHONY: build
|
||||
build:
|
||||
go build ./...
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
go test -race ./...
|
||||
|
||||
.PHONY: gofmt
|
||||
gofmt:
|
||||
$(eval FMT_LOG := $(shell mktemp -t gofmt.XXXXX))
|
||||
gofmt -e -s -l $(GO_FILES) > $(FMT_LOG) || true
|
||||
@[ ! -s "$(FMT_LOG)" ] || (echo "gofmt failed:" && cat $(FMT_LOG) && false)
|
||||
|
||||
$(GOLINT):
|
||||
cd tools && go install golang.org/x/lint/golint
|
||||
|
||||
$(STATICCHECK):
|
||||
cd tools && go install honnef.co/go/tools/cmd/staticcheck
|
||||
|
||||
$(GEN_ATOMICWRAPPER): $(wildcard ./internal/gen-atomicwrapper/*)
|
||||
go build -o $@ ./internal/gen-atomicwrapper
|
||||
|
||||
$(GEN_ATOMICINT): $(wildcard ./internal/gen-atomicint/*)
|
||||
go build -o $@ ./internal/gen-atomicint
|
||||
|
||||
.PHONY: golint
|
||||
golint: $(GOLINT)
|
||||
$(GOLINT) ./...
|
||||
|
||||
.PHONY: staticcheck
|
||||
staticcheck: $(STATICCHECK)
|
||||
$(STATICCHECK) ./...
|
||||
|
||||
.PHONY: lint
|
||||
lint: gofmt golint staticcheck generatenodirty
|
||||
|
||||
# comma separated list of packages to consider for code coverage.
|
||||
COVER_PKG = $(shell \
|
||||
go list -find ./... | \
|
||||
grep -v $(foreach pkg,$(COVER_IGNORE_PKGS),-e "^$(pkg)$$") | \
|
||||
paste -sd, -)
|
||||
|
||||
.PHONY: cover
|
||||
cover:
|
||||
go test -coverprofile=cover.out -coverpkg $(COVER_PKG) -v ./...
|
||||
go tool cover -html=cover.out -o cover.html
|
||||
|
||||
.PHONY: generate
|
||||
generate: $(GEN_ATOMICINT) $(GEN_ATOMICWRAPPER)
|
||||
go generate ./...
|
||||
|
||||
.PHONY: generatenodirty
|
||||
generatenodirty:
|
||||
@[ -z "$$(git status --porcelain)" ] || ( \
|
||||
echo "Working tree is dirty. Commit your changes first."; \
|
||||
git status; \
|
||||
exit 1 )
|
||||
@make generate
|
||||
@status=$$(git status --porcelain); \
|
||||
[ -z "$$status" ] || ( \
|
||||
echo "Working tree is dirty after `make generate`:"; \
|
||||
echo "$$status"; \
|
||||
echo "Please ensure that the generated code is up-to-date." )
|
||||
63
vendor/go.uber.org/atomic/README.md
generated
vendored
63
vendor/go.uber.org/atomic/README.md
generated
vendored
|
|
@ -1,63 +0,0 @@
|
|||
# atomic [![GoDoc][doc-img]][doc] [![Build Status][ci-img]][ci] [![Coverage Status][cov-img]][cov] [![Go Report Card][reportcard-img]][reportcard]
|
||||
|
||||
Simple wrappers for primitive types to enforce atomic access.
|
||||
|
||||
## Installation
|
||||
|
||||
```shell
|
||||
$ go get -u go.uber.org/atomic@v1
|
||||
```
|
||||
|
||||
### Legacy Import Path
|
||||
|
||||
As of v1.5.0, the import path `go.uber.org/atomic` is the only supported way
|
||||
of using this package. If you are using Go modules, this package will fail to
|
||||
compile with the legacy import path path `github.com/uber-go/atomic`.
|
||||
|
||||
We recommend migrating your code to the new import path but if you're unable
|
||||
to do so, or if your dependencies are still using the old import path, you
|
||||
will have to add a `replace` directive to your `go.mod` file downgrading the
|
||||
legacy import path to an older version.
|
||||
|
||||
```
|
||||
replace github.com/uber-go/atomic => github.com/uber-go/atomic v1.4.0
|
||||
```
|
||||
|
||||
You can do so automatically by running the following command.
|
||||
|
||||
```shell
|
||||
$ go mod edit -replace github.com/uber-go/atomic=github.com/uber-go/atomic@v1.4.0
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
The standard library's `sync/atomic` is powerful, but it's easy to forget which
|
||||
variables must be accessed atomically. `go.uber.org/atomic` preserves all the
|
||||
functionality of the standard library, but wraps the primitive types to
|
||||
provide a safer, more convenient API.
|
||||
|
||||
```go
|
||||
var atom atomic.Uint32
|
||||
atom.Store(42)
|
||||
atom.Sub(2)
|
||||
atom.CAS(40, 11)
|
||||
```
|
||||
|
||||
See the [documentation][doc] for a complete API specification.
|
||||
|
||||
## Development Status
|
||||
|
||||
Stable.
|
||||
|
||||
---
|
||||
|
||||
Released under the [MIT License](LICENSE.txt).
|
||||
|
||||
[doc-img]: https://godoc.org/github.com/uber-go/atomic?status.svg
|
||||
[doc]: https://godoc.org/go.uber.org/atomic
|
||||
[ci-img]: https://github.com/uber-go/atomic/actions/workflows/go.yml/badge.svg
|
||||
[ci]: https://github.com/uber-go/atomic/actions/workflows/go.yml
|
||||
[cov-img]: https://codecov.io/gh/uber-go/atomic/branch/master/graph/badge.svg
|
||||
[cov]: https://codecov.io/gh/uber-go/atomic
|
||||
[reportcard-img]: https://goreportcard.com/badge/go.uber.org/atomic
|
||||
[reportcard]: https://goreportcard.com/report/go.uber.org/atomic
|
||||
81
vendor/go.uber.org/atomic/bool.go
generated
vendored
81
vendor/go.uber.org/atomic/bool.go
generated
vendored
|
|
@ -1,81 +0,0 @@
|
|||
// @generated Code generated by gen-atomicwrapper.
|
||||
|
||||
// Copyright (c) 2020-2021 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package atomic
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// Bool is an atomic type-safe wrapper for bool values.
|
||||
type Bool struct {
|
||||
_ nocmp // disallow non-atomic comparison
|
||||
|
||||
v Uint32
|
||||
}
|
||||
|
||||
var _zeroBool bool
|
||||
|
||||
// NewBool creates a new Bool.
|
||||
func NewBool(val bool) *Bool {
|
||||
x := &Bool{}
|
||||
if val != _zeroBool {
|
||||
x.Store(val)
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
// Load atomically loads the wrapped bool.
|
||||
func (x *Bool) Load() bool {
|
||||
return truthy(x.v.Load())
|
||||
}
|
||||
|
||||
// Store atomically stores the passed bool.
|
||||
func (x *Bool) Store(val bool) {
|
||||
x.v.Store(boolToInt(val))
|
||||
}
|
||||
|
||||
// CAS is an atomic compare-and-swap for bool values.
|
||||
func (x *Bool) CAS(old, new bool) (swapped bool) {
|
||||
return x.v.CAS(boolToInt(old), boolToInt(new))
|
||||
}
|
||||
|
||||
// Swap atomically stores the given bool and returns the old
|
||||
// value.
|
||||
func (x *Bool) Swap(val bool) (old bool) {
|
||||
return truthy(x.v.Swap(boolToInt(val)))
|
||||
}
|
||||
|
||||
// MarshalJSON encodes the wrapped bool into JSON.
|
||||
func (x *Bool) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(x.Load())
|
||||
}
|
||||
|
||||
// UnmarshalJSON decodes a bool from JSON.
|
||||
func (x *Bool) UnmarshalJSON(b []byte) error {
|
||||
var v bool
|
||||
if err := json.Unmarshal(b, &v); err != nil {
|
||||
return err
|
||||
}
|
||||
x.Store(v)
|
||||
return nil
|
||||
}
|
||||
53
vendor/go.uber.org/atomic/bool_ext.go
generated
vendored
53
vendor/go.uber.org/atomic/bool_ext.go
generated
vendored
|
|
@ -1,53 +0,0 @@
|
|||
// Copyright (c) 2020 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package atomic
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
)
|
||||
|
||||
//go:generate bin/gen-atomicwrapper -name=Bool -type=bool -wrapped=Uint32 -pack=boolToInt -unpack=truthy -cas -swap -json -file=bool.go
|
||||
|
||||
func truthy(n uint32) bool {
|
||||
return n == 1
|
||||
}
|
||||
|
||||
func boolToInt(b bool) uint32 {
|
||||
if b {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Toggle atomically negates the Boolean and returns the previous value.
|
||||
func (b *Bool) Toggle() (old bool) {
|
||||
for {
|
||||
old := b.Load()
|
||||
if b.CAS(old, !old) {
|
||||
return old
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// String encodes the wrapped value as a string.
|
||||
func (b *Bool) String() string {
|
||||
return strconv.FormatBool(b.Load())
|
||||
}
|
||||
23
vendor/go.uber.org/atomic/doc.go
generated
vendored
23
vendor/go.uber.org/atomic/doc.go
generated
vendored
|
|
@ -1,23 +0,0 @@
|
|||
// Copyright (c) 2020 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
// Package atomic provides simple wrappers around numerics to enforce atomic
|
||||
// access.
|
||||
package atomic
|
||||
82
vendor/go.uber.org/atomic/duration.go
generated
vendored
82
vendor/go.uber.org/atomic/duration.go
generated
vendored
|
|
@ -1,82 +0,0 @@
|
|||
// @generated Code generated by gen-atomicwrapper.
|
||||
|
||||
// Copyright (c) 2020-2021 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package atomic
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Duration is an atomic type-safe wrapper for time.Duration values.
|
||||
type Duration struct {
|
||||
_ nocmp // disallow non-atomic comparison
|
||||
|
||||
v Int64
|
||||
}
|
||||
|
||||
var _zeroDuration time.Duration
|
||||
|
||||
// NewDuration creates a new Duration.
|
||||
func NewDuration(val time.Duration) *Duration {
|
||||
x := &Duration{}
|
||||
if val != _zeroDuration {
|
||||
x.Store(val)
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
// Load atomically loads the wrapped time.Duration.
|
||||
func (x *Duration) Load() time.Duration {
|
||||
return time.Duration(x.v.Load())
|
||||
}
|
||||
|
||||
// Store atomically stores the passed time.Duration.
|
||||
func (x *Duration) Store(val time.Duration) {
|
||||
x.v.Store(int64(val))
|
||||
}
|
||||
|
||||
// CAS is an atomic compare-and-swap for time.Duration values.
|
||||
func (x *Duration) CAS(old, new time.Duration) (swapped bool) {
|
||||
return x.v.CAS(int64(old), int64(new))
|
||||
}
|
||||
|
||||
// Swap atomically stores the given time.Duration and returns the old
|
||||
// value.
|
||||
func (x *Duration) Swap(val time.Duration) (old time.Duration) {
|
||||
return time.Duration(x.v.Swap(int64(val)))
|
||||
}
|
||||
|
||||
// MarshalJSON encodes the wrapped time.Duration into JSON.
|
||||
func (x *Duration) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(x.Load())
|
||||
}
|
||||
|
||||
// UnmarshalJSON decodes a time.Duration from JSON.
|
||||
func (x *Duration) UnmarshalJSON(b []byte) error {
|
||||
var v time.Duration
|
||||
if err := json.Unmarshal(b, &v); err != nil {
|
||||
return err
|
||||
}
|
||||
x.Store(v)
|
||||
return nil
|
||||
}
|
||||
40
vendor/go.uber.org/atomic/duration_ext.go
generated
vendored
40
vendor/go.uber.org/atomic/duration_ext.go
generated
vendored
|
|
@ -1,40 +0,0 @@
|
|||
// Copyright (c) 2020 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package atomic
|
||||
|
||||
import "time"
|
||||
|
||||
//go:generate bin/gen-atomicwrapper -name=Duration -type=time.Duration -wrapped=Int64 -pack=int64 -unpack=time.Duration -cas -swap -json -imports time -file=duration.go
|
||||
|
||||
// Add atomically adds to the wrapped time.Duration and returns the new value.
|
||||
func (d *Duration) Add(delta time.Duration) time.Duration {
|
||||
return time.Duration(d.v.Add(int64(delta)))
|
||||
}
|
||||
|
||||
// Sub atomically subtracts from the wrapped time.Duration and returns the new value.
|
||||
func (d *Duration) Sub(delta time.Duration) time.Duration {
|
||||
return time.Duration(d.v.Sub(int64(delta)))
|
||||
}
|
||||
|
||||
// String encodes the wrapped value as a string.
|
||||
func (d *Duration) String() string {
|
||||
return d.Load().String()
|
||||
}
|
||||
51
vendor/go.uber.org/atomic/error.go
generated
vendored
51
vendor/go.uber.org/atomic/error.go
generated
vendored
|
|
@ -1,51 +0,0 @@
|
|||
// @generated Code generated by gen-atomicwrapper.
|
||||
|
||||
// Copyright (c) 2020-2021 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package atomic
|
||||
|
||||
// Error is an atomic type-safe wrapper for error values.
|
||||
type Error struct {
|
||||
_ nocmp // disallow non-atomic comparison
|
||||
|
||||
v Value
|
||||
}
|
||||
|
||||
var _zeroError error
|
||||
|
||||
// NewError creates a new Error.
|
||||
func NewError(val error) *Error {
|
||||
x := &Error{}
|
||||
if val != _zeroError {
|
||||
x.Store(val)
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
// Load atomically loads the wrapped error.
|
||||
func (x *Error) Load() error {
|
||||
return unpackError(x.v.Load())
|
||||
}
|
||||
|
||||
// Store atomically stores the passed error.
|
||||
func (x *Error) Store(val error) {
|
||||
x.v.Store(packError(val))
|
||||
}
|
||||
77
vendor/go.uber.org/atomic/float64.go
generated
vendored
77
vendor/go.uber.org/atomic/float64.go
generated
vendored
|
|
@ -1,77 +0,0 @@
|
|||
// @generated Code generated by gen-atomicwrapper.
|
||||
|
||||
// Copyright (c) 2020-2021 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package atomic
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"math"
|
||||
)
|
||||
|
||||
// Float64 is an atomic type-safe wrapper for float64 values.
|
||||
type Float64 struct {
|
||||
_ nocmp // disallow non-atomic comparison
|
||||
|
||||
v Uint64
|
||||
}
|
||||
|
||||
var _zeroFloat64 float64
|
||||
|
||||
// NewFloat64 creates a new Float64.
|
||||
func NewFloat64(val float64) *Float64 {
|
||||
x := &Float64{}
|
||||
if val != _zeroFloat64 {
|
||||
x.Store(val)
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
// Load atomically loads the wrapped float64.
|
||||
func (x *Float64) Load() float64 {
|
||||
return math.Float64frombits(x.v.Load())
|
||||
}
|
||||
|
||||
// Store atomically stores the passed float64.
|
||||
func (x *Float64) Store(val float64) {
|
||||
x.v.Store(math.Float64bits(val))
|
||||
}
|
||||
|
||||
// Swap atomically stores the given float64 and returns the old
|
||||
// value.
|
||||
func (x *Float64) Swap(val float64) (old float64) {
|
||||
return math.Float64frombits(x.v.Swap(math.Float64bits(val)))
|
||||
}
|
||||
|
||||
// MarshalJSON encodes the wrapped float64 into JSON.
|
||||
func (x *Float64) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(x.Load())
|
||||
}
|
||||
|
||||
// UnmarshalJSON decodes a float64 from JSON.
|
||||
func (x *Float64) UnmarshalJSON(b []byte) error {
|
||||
var v float64
|
||||
if err := json.Unmarshal(b, &v); err != nil {
|
||||
return err
|
||||
}
|
||||
x.Store(v)
|
||||
return nil
|
||||
}
|
||||
69
vendor/go.uber.org/atomic/float64_ext.go
generated
vendored
69
vendor/go.uber.org/atomic/float64_ext.go
generated
vendored
|
|
@ -1,69 +0,0 @@
|
|||
// Copyright (c) 2020 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package atomic
|
||||
|
||||
import (
|
||||
"math"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
//go:generate bin/gen-atomicwrapper -name=Float64 -type=float64 -wrapped=Uint64 -pack=math.Float64bits -unpack=math.Float64frombits -swap -json -imports math -file=float64.go
|
||||
|
||||
// Add atomically adds to the wrapped float64 and returns the new value.
|
||||
func (f *Float64) Add(delta float64) float64 {
|
||||
for {
|
||||
old := f.Load()
|
||||
new := old + delta
|
||||
if f.CAS(old, new) {
|
||||
return new
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sub atomically subtracts from the wrapped float64 and returns the new value.
|
||||
func (f *Float64) Sub(delta float64) float64 {
|
||||
return f.Add(-delta)
|
||||
}
|
||||
|
||||
// CAS is an atomic compare-and-swap for float64 values.
|
||||
//
|
||||
// Note: CAS handles NaN incorrectly. NaN != NaN using Go's inbuilt operators
|
||||
// but CAS allows a stored NaN to compare equal to a passed in NaN.
|
||||
// This avoids typical CAS loops from blocking forever, e.g.,
|
||||
//
|
||||
// for {
|
||||
// old := atom.Load()
|
||||
// new = f(old)
|
||||
// if atom.CAS(old, new) {
|
||||
// break
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// If CAS did not match NaN to match, then the above would loop forever.
|
||||
func (f *Float64) CAS(old, new float64) (swapped bool) {
|
||||
return f.v.CAS(math.Float64bits(old), math.Float64bits(new))
|
||||
}
|
||||
|
||||
// String encodes the wrapped value as a string.
|
||||
func (f *Float64) String() string {
|
||||
// 'g' is the behavior for floats with %v.
|
||||
return strconv.FormatFloat(f.Load(), 'g', -1, 64)
|
||||
}
|
||||
27
vendor/go.uber.org/atomic/gen.go
generated
vendored
27
vendor/go.uber.org/atomic/gen.go
generated
vendored
|
|
@ -1,27 +0,0 @@
|
|||
// Copyright (c) 2020 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package atomic
|
||||
|
||||
//go:generate bin/gen-atomicint -name=Int32 -wrapped=int32 -file=int32.go
|
||||
//go:generate bin/gen-atomicint -name=Int64 -wrapped=int64 -file=int64.go
|
||||
//go:generate bin/gen-atomicint -name=Uint32 -wrapped=uint32 -unsigned -file=uint32.go
|
||||
//go:generate bin/gen-atomicint -name=Uint64 -wrapped=uint64 -unsigned -file=uint64.go
|
||||
//go:generate bin/gen-atomicint -name=Uintptr -wrapped=uintptr -unsigned -file=uintptr.go
|
||||
102
vendor/go.uber.org/atomic/int32.go
generated
vendored
102
vendor/go.uber.org/atomic/int32.go
generated
vendored
|
|
@ -1,102 +0,0 @@
|
|||
// @generated Code generated by gen-atomicint.
|
||||
|
||||
// Copyright (c) 2020-2021 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package atomic
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
// Int32 is an atomic wrapper around int32.
|
||||
type Int32 struct {
|
||||
_ nocmp // disallow non-atomic comparison
|
||||
|
||||
v int32
|
||||
}
|
||||
|
||||
// NewInt32 creates a new Int32.
|
||||
func NewInt32(val int32) *Int32 {
|
||||
return &Int32{v: val}
|
||||
}
|
||||
|
||||
// Load atomically loads the wrapped value.
|
||||
func (i *Int32) Load() int32 {
|
||||
return atomic.LoadInt32(&i.v)
|
||||
}
|
||||
|
||||
// Add atomically adds to the wrapped int32 and returns the new value.
|
||||
func (i *Int32) Add(delta int32) int32 {
|
||||
return atomic.AddInt32(&i.v, delta)
|
||||
}
|
||||
|
||||
// Sub atomically subtracts from the wrapped int32 and returns the new value.
|
||||
func (i *Int32) Sub(delta int32) int32 {
|
||||
return atomic.AddInt32(&i.v, -delta)
|
||||
}
|
||||
|
||||
// Inc atomically increments the wrapped int32 and returns the new value.
|
||||
func (i *Int32) Inc() int32 {
|
||||
return i.Add(1)
|
||||
}
|
||||
|
||||
// Dec atomically decrements the wrapped int32 and returns the new value.
|
||||
func (i *Int32) Dec() int32 {
|
||||
return i.Sub(1)
|
||||
}
|
||||
|
||||
// CAS is an atomic compare-and-swap.
|
||||
func (i *Int32) CAS(old, new int32) (swapped bool) {
|
||||
return atomic.CompareAndSwapInt32(&i.v, old, new)
|
||||
}
|
||||
|
||||
// Store atomically stores the passed value.
|
||||
func (i *Int32) Store(val int32) {
|
||||
atomic.StoreInt32(&i.v, val)
|
||||
}
|
||||
|
||||
// Swap atomically swaps the wrapped int32 and returns the old value.
|
||||
func (i *Int32) Swap(val int32) (old int32) {
|
||||
return atomic.SwapInt32(&i.v, val)
|
||||
}
|
||||
|
||||
// MarshalJSON encodes the wrapped int32 into JSON.
|
||||
func (i *Int32) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(i.Load())
|
||||
}
|
||||
|
||||
// UnmarshalJSON decodes JSON into the wrapped int32.
|
||||
func (i *Int32) UnmarshalJSON(b []byte) error {
|
||||
var v int32
|
||||
if err := json.Unmarshal(b, &v); err != nil {
|
||||
return err
|
||||
}
|
||||
i.Store(v)
|
||||
return nil
|
||||
}
|
||||
|
||||
// String encodes the wrapped value as a string.
|
||||
func (i *Int32) String() string {
|
||||
v := i.Load()
|
||||
return strconv.FormatInt(int64(v), 10)
|
||||
}
|
||||
102
vendor/go.uber.org/atomic/int64.go
generated
vendored
102
vendor/go.uber.org/atomic/int64.go
generated
vendored
|
|
@ -1,102 +0,0 @@
|
|||
// @generated Code generated by gen-atomicint.
|
||||
|
||||
// Copyright (c) 2020-2021 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package atomic
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
// Int64 is an atomic wrapper around int64.
|
||||
type Int64 struct {
|
||||
_ nocmp // disallow non-atomic comparison
|
||||
|
||||
v int64
|
||||
}
|
||||
|
||||
// NewInt64 creates a new Int64.
|
||||
func NewInt64(val int64) *Int64 {
|
||||
return &Int64{v: val}
|
||||
}
|
||||
|
||||
// Load atomically loads the wrapped value.
|
||||
func (i *Int64) Load() int64 {
|
||||
return atomic.LoadInt64(&i.v)
|
||||
}
|
||||
|
||||
// Add atomically adds to the wrapped int64 and returns the new value.
|
||||
func (i *Int64) Add(delta int64) int64 {
|
||||
return atomic.AddInt64(&i.v, delta)
|
||||
}
|
||||
|
||||
// Sub atomically subtracts from the wrapped int64 and returns the new value.
|
||||
func (i *Int64) Sub(delta int64) int64 {
|
||||
return atomic.AddInt64(&i.v, -delta)
|
||||
}
|
||||
|
||||
// Inc atomically increments the wrapped int64 and returns the new value.
|
||||
func (i *Int64) Inc() int64 {
|
||||
return i.Add(1)
|
||||
}
|
||||
|
||||
// Dec atomically decrements the wrapped int64 and returns the new value.
|
||||
func (i *Int64) Dec() int64 {
|
||||
return i.Sub(1)
|
||||
}
|
||||
|
||||
// CAS is an atomic compare-and-swap.
|
||||
func (i *Int64) CAS(old, new int64) (swapped bool) {
|
||||
return atomic.CompareAndSwapInt64(&i.v, old, new)
|
||||
}
|
||||
|
||||
// Store atomically stores the passed value.
|
||||
func (i *Int64) Store(val int64) {
|
||||
atomic.StoreInt64(&i.v, val)
|
||||
}
|
||||
|
||||
// Swap atomically swaps the wrapped int64 and returns the old value.
|
||||
func (i *Int64) Swap(val int64) (old int64) {
|
||||
return atomic.SwapInt64(&i.v, val)
|
||||
}
|
||||
|
||||
// MarshalJSON encodes the wrapped int64 into JSON.
|
||||
func (i *Int64) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(i.Load())
|
||||
}
|
||||
|
||||
// UnmarshalJSON decodes JSON into the wrapped int64.
|
||||
func (i *Int64) UnmarshalJSON(b []byte) error {
|
||||
var v int64
|
||||
if err := json.Unmarshal(b, &v); err != nil {
|
||||
return err
|
||||
}
|
||||
i.Store(v)
|
||||
return nil
|
||||
}
|
||||
|
||||
// String encodes the wrapped value as a string.
|
||||
func (i *Int64) String() string {
|
||||
v := i.Load()
|
||||
return strconv.FormatInt(int64(v), 10)
|
||||
}
|
||||
35
vendor/go.uber.org/atomic/nocmp.go
generated
vendored
35
vendor/go.uber.org/atomic/nocmp.go
generated
vendored
|
|
@ -1,35 +0,0 @@
|
|||
// Copyright (c) 2020 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package atomic
|
||||
|
||||
// nocmp is an uncomparable struct. Embed this inside another struct to make
|
||||
// it uncomparable.
|
||||
//
|
||||
// type Foo struct {
|
||||
// nocmp
|
||||
// // ...
|
||||
// }
|
||||
//
|
||||
// This DOES NOT:
|
||||
//
|
||||
// - Disallow shallow copies of structs
|
||||
// - Disallow comparison of pointers to uncomparable structs
|
||||
type nocmp [0]func()
|
||||
54
vendor/go.uber.org/atomic/string.go
generated
vendored
54
vendor/go.uber.org/atomic/string.go
generated
vendored
|
|
@ -1,54 +0,0 @@
|
|||
// @generated Code generated by gen-atomicwrapper.
|
||||
|
||||
// Copyright (c) 2020-2021 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package atomic
|
||||
|
||||
// String is an atomic type-safe wrapper for string values.
|
||||
type String struct {
|
||||
_ nocmp // disallow non-atomic comparison
|
||||
|
||||
v Value
|
||||
}
|
||||
|
||||
var _zeroString string
|
||||
|
||||
// NewString creates a new String.
|
||||
func NewString(val string) *String {
|
||||
x := &String{}
|
||||
if val != _zeroString {
|
||||
x.Store(val)
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
// Load atomically loads the wrapped string.
|
||||
func (x *String) Load() string {
|
||||
if v := x.v.Load(); v != nil {
|
||||
return v.(string)
|
||||
}
|
||||
return _zeroString
|
||||
}
|
||||
|
||||
// Store atomically stores the passed string.
|
||||
func (x *String) Store(val string) {
|
||||
x.v.Store(val)
|
||||
}
|
||||
45
vendor/go.uber.org/atomic/string_ext.go
generated
vendored
45
vendor/go.uber.org/atomic/string_ext.go
generated
vendored
|
|
@ -1,45 +0,0 @@
|
|||
// Copyright (c) 2020 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package atomic
|
||||
|
||||
//go:generate bin/gen-atomicwrapper -name=String -type=string -wrapped=Value -file=string.go
|
||||
// Note: No Swap as String wraps Value, which wraps the stdlib sync/atomic.Value which
|
||||
// only supports Swap as of go1.17: https://github.com/golang/go/issues/39351
|
||||
|
||||
// String returns the wrapped value.
|
||||
func (s *String) String() string {
|
||||
return s.Load()
|
||||
}
|
||||
|
||||
// MarshalText encodes the wrapped string into a textual form.
|
||||
//
|
||||
// This makes it encodable as JSON, YAML, XML, and more.
|
||||
func (s *String) MarshalText() ([]byte, error) {
|
||||
return []byte(s.Load()), nil
|
||||
}
|
||||
|
||||
// UnmarshalText decodes text and replaces the wrapped string with it.
|
||||
//
|
||||
// This makes it decodable from JSON, YAML, XML, and more.
|
||||
func (s *String) UnmarshalText(b []byte) error {
|
||||
s.Store(string(b))
|
||||
return nil
|
||||
}
|
||||
55
vendor/go.uber.org/atomic/time.go
generated
vendored
55
vendor/go.uber.org/atomic/time.go
generated
vendored
|
|
@ -1,55 +0,0 @@
|
|||
// @generated Code generated by gen-atomicwrapper.
|
||||
|
||||
// Copyright (c) 2020-2021 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package atomic
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// Time is an atomic type-safe wrapper for time.Time values.
|
||||
type Time struct {
|
||||
_ nocmp // disallow non-atomic comparison
|
||||
|
||||
v Value
|
||||
}
|
||||
|
||||
var _zeroTime time.Time
|
||||
|
||||
// NewTime creates a new Time.
|
||||
func NewTime(val time.Time) *Time {
|
||||
x := &Time{}
|
||||
if val != _zeroTime {
|
||||
x.Store(val)
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
// Load atomically loads the wrapped time.Time.
|
||||
func (x *Time) Load() time.Time {
|
||||
return unpackTime(x.v.Load())
|
||||
}
|
||||
|
||||
// Store atomically stores the passed time.Time.
|
||||
func (x *Time) Store(val time.Time) {
|
||||
x.v.Store(packTime(val))
|
||||
}
|
||||
36
vendor/go.uber.org/atomic/time_ext.go
generated
vendored
36
vendor/go.uber.org/atomic/time_ext.go
generated
vendored
|
|
@ -1,36 +0,0 @@
|
|||
// Copyright (c) 2021 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package atomic
|
||||
|
||||
import "time"
|
||||
|
||||
//go:generate bin/gen-atomicwrapper -name=Time -type=time.Time -wrapped=Value -pack=packTime -unpack=unpackTime -imports time -file=time.go
|
||||
|
||||
func packTime(t time.Time) interface{} {
|
||||
return t
|
||||
}
|
||||
|
||||
func unpackTime(v interface{}) time.Time {
|
||||
if t, ok := v.(time.Time); ok {
|
||||
return t
|
||||
}
|
||||
return time.Time{}
|
||||
}
|
||||
102
vendor/go.uber.org/atomic/uint32.go
generated
vendored
102
vendor/go.uber.org/atomic/uint32.go
generated
vendored
|
|
@ -1,102 +0,0 @@
|
|||
// @generated Code generated by gen-atomicint.
|
||||
|
||||
// Copyright (c) 2020-2021 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package atomic
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
// Uint32 is an atomic wrapper around uint32.
|
||||
type Uint32 struct {
|
||||
_ nocmp // disallow non-atomic comparison
|
||||
|
||||
v uint32
|
||||
}
|
||||
|
||||
// NewUint32 creates a new Uint32.
|
||||
func NewUint32(val uint32) *Uint32 {
|
||||
return &Uint32{v: val}
|
||||
}
|
||||
|
||||
// Load atomically loads the wrapped value.
|
||||
func (i *Uint32) Load() uint32 {
|
||||
return atomic.LoadUint32(&i.v)
|
||||
}
|
||||
|
||||
// Add atomically adds to the wrapped uint32 and returns the new value.
|
||||
func (i *Uint32) Add(delta uint32) uint32 {
|
||||
return atomic.AddUint32(&i.v, delta)
|
||||
}
|
||||
|
||||
// Sub atomically subtracts from the wrapped uint32 and returns the new value.
|
||||
func (i *Uint32) Sub(delta uint32) uint32 {
|
||||
return atomic.AddUint32(&i.v, ^(delta - 1))
|
||||
}
|
||||
|
||||
// Inc atomically increments the wrapped uint32 and returns the new value.
|
||||
func (i *Uint32) Inc() uint32 {
|
||||
return i.Add(1)
|
||||
}
|
||||
|
||||
// Dec atomically decrements the wrapped uint32 and returns the new value.
|
||||
func (i *Uint32) Dec() uint32 {
|
||||
return i.Sub(1)
|
||||
}
|
||||
|
||||
// CAS is an atomic compare-and-swap.
|
||||
func (i *Uint32) CAS(old, new uint32) (swapped bool) {
|
||||
return atomic.CompareAndSwapUint32(&i.v, old, new)
|
||||
}
|
||||
|
||||
// Store atomically stores the passed value.
|
||||
func (i *Uint32) Store(val uint32) {
|
||||
atomic.StoreUint32(&i.v, val)
|
||||
}
|
||||
|
||||
// Swap atomically swaps the wrapped uint32 and returns the old value.
|
||||
func (i *Uint32) Swap(val uint32) (old uint32) {
|
||||
return atomic.SwapUint32(&i.v, val)
|
||||
}
|
||||
|
||||
// MarshalJSON encodes the wrapped uint32 into JSON.
|
||||
func (i *Uint32) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(i.Load())
|
||||
}
|
||||
|
||||
// UnmarshalJSON decodes JSON into the wrapped uint32.
|
||||
func (i *Uint32) UnmarshalJSON(b []byte) error {
|
||||
var v uint32
|
||||
if err := json.Unmarshal(b, &v); err != nil {
|
||||
return err
|
||||
}
|
||||
i.Store(v)
|
||||
return nil
|
||||
}
|
||||
|
||||
// String encodes the wrapped value as a string.
|
||||
func (i *Uint32) String() string {
|
||||
v := i.Load()
|
||||
return strconv.FormatUint(uint64(v), 10)
|
||||
}
|
||||
102
vendor/go.uber.org/atomic/uint64.go
generated
vendored
102
vendor/go.uber.org/atomic/uint64.go
generated
vendored
|
|
@ -1,102 +0,0 @@
|
|||
// @generated Code generated by gen-atomicint.
|
||||
|
||||
// Copyright (c) 2020-2021 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package atomic
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
// Uint64 is an atomic wrapper around uint64.
|
||||
type Uint64 struct {
|
||||
_ nocmp // disallow non-atomic comparison
|
||||
|
||||
v uint64
|
||||
}
|
||||
|
||||
// NewUint64 creates a new Uint64.
|
||||
func NewUint64(val uint64) *Uint64 {
|
||||
return &Uint64{v: val}
|
||||
}
|
||||
|
||||
// Load atomically loads the wrapped value.
|
||||
func (i *Uint64) Load() uint64 {
|
||||
return atomic.LoadUint64(&i.v)
|
||||
}
|
||||
|
||||
// Add atomically adds to the wrapped uint64 and returns the new value.
|
||||
func (i *Uint64) Add(delta uint64) uint64 {
|
||||
return atomic.AddUint64(&i.v, delta)
|
||||
}
|
||||
|
||||
// Sub atomically subtracts from the wrapped uint64 and returns the new value.
|
||||
func (i *Uint64) Sub(delta uint64) uint64 {
|
||||
return atomic.AddUint64(&i.v, ^(delta - 1))
|
||||
}
|
||||
|
||||
// Inc atomically increments the wrapped uint64 and returns the new value.
|
||||
func (i *Uint64) Inc() uint64 {
|
||||
return i.Add(1)
|
||||
}
|
||||
|
||||
// Dec atomically decrements the wrapped uint64 and returns the new value.
|
||||
func (i *Uint64) Dec() uint64 {
|
||||
return i.Sub(1)
|
||||
}
|
||||
|
||||
// CAS is an atomic compare-and-swap.
|
||||
func (i *Uint64) CAS(old, new uint64) (swapped bool) {
|
||||
return atomic.CompareAndSwapUint64(&i.v, old, new)
|
||||
}
|
||||
|
||||
// Store atomically stores the passed value.
|
||||
func (i *Uint64) Store(val uint64) {
|
||||
atomic.StoreUint64(&i.v, val)
|
||||
}
|
||||
|
||||
// Swap atomically swaps the wrapped uint64 and returns the old value.
|
||||
func (i *Uint64) Swap(val uint64) (old uint64) {
|
||||
return atomic.SwapUint64(&i.v, val)
|
||||
}
|
||||
|
||||
// MarshalJSON encodes the wrapped uint64 into JSON.
|
||||
func (i *Uint64) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(i.Load())
|
||||
}
|
||||
|
||||
// UnmarshalJSON decodes JSON into the wrapped uint64.
|
||||
func (i *Uint64) UnmarshalJSON(b []byte) error {
|
||||
var v uint64
|
||||
if err := json.Unmarshal(b, &v); err != nil {
|
||||
return err
|
||||
}
|
||||
i.Store(v)
|
||||
return nil
|
||||
}
|
||||
|
||||
// String encodes the wrapped value as a string.
|
||||
func (i *Uint64) String() string {
|
||||
v := i.Load()
|
||||
return strconv.FormatUint(uint64(v), 10)
|
||||
}
|
||||
102
vendor/go.uber.org/atomic/uintptr.go
generated
vendored
102
vendor/go.uber.org/atomic/uintptr.go
generated
vendored
|
|
@ -1,102 +0,0 @@
|
|||
// @generated Code generated by gen-atomicint.
|
||||
|
||||
// Copyright (c) 2020-2021 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package atomic
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
// Uintptr is an atomic wrapper around uintptr.
|
||||
type Uintptr struct {
|
||||
_ nocmp // disallow non-atomic comparison
|
||||
|
||||
v uintptr
|
||||
}
|
||||
|
||||
// NewUintptr creates a new Uintptr.
|
||||
func NewUintptr(val uintptr) *Uintptr {
|
||||
return &Uintptr{v: val}
|
||||
}
|
||||
|
||||
// Load atomically loads the wrapped value.
|
||||
func (i *Uintptr) Load() uintptr {
|
||||
return atomic.LoadUintptr(&i.v)
|
||||
}
|
||||
|
||||
// Add atomically adds to the wrapped uintptr and returns the new value.
|
||||
func (i *Uintptr) Add(delta uintptr) uintptr {
|
||||
return atomic.AddUintptr(&i.v, delta)
|
||||
}
|
||||
|
||||
// Sub atomically subtracts from the wrapped uintptr and returns the new value.
|
||||
func (i *Uintptr) Sub(delta uintptr) uintptr {
|
||||
return atomic.AddUintptr(&i.v, ^(delta - 1))
|
||||
}
|
||||
|
||||
// Inc atomically increments the wrapped uintptr and returns the new value.
|
||||
func (i *Uintptr) Inc() uintptr {
|
||||
return i.Add(1)
|
||||
}
|
||||
|
||||
// Dec atomically decrements the wrapped uintptr and returns the new value.
|
||||
func (i *Uintptr) Dec() uintptr {
|
||||
return i.Sub(1)
|
||||
}
|
||||
|
||||
// CAS is an atomic compare-and-swap.
|
||||
func (i *Uintptr) CAS(old, new uintptr) (swapped bool) {
|
||||
return atomic.CompareAndSwapUintptr(&i.v, old, new)
|
||||
}
|
||||
|
||||
// Store atomically stores the passed value.
|
||||
func (i *Uintptr) Store(val uintptr) {
|
||||
atomic.StoreUintptr(&i.v, val)
|
||||
}
|
||||
|
||||
// Swap atomically swaps the wrapped uintptr and returns the old value.
|
||||
func (i *Uintptr) Swap(val uintptr) (old uintptr) {
|
||||
return atomic.SwapUintptr(&i.v, val)
|
||||
}
|
||||
|
||||
// MarshalJSON encodes the wrapped uintptr into JSON.
|
||||
func (i *Uintptr) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(i.Load())
|
||||
}
|
||||
|
||||
// UnmarshalJSON decodes JSON into the wrapped uintptr.
|
||||
func (i *Uintptr) UnmarshalJSON(b []byte) error {
|
||||
var v uintptr
|
||||
if err := json.Unmarshal(b, &v); err != nil {
|
||||
return err
|
||||
}
|
||||
i.Store(v)
|
||||
return nil
|
||||
}
|
||||
|
||||
// String encodes the wrapped value as a string.
|
||||
func (i *Uintptr) String() string {
|
||||
v := i.Load()
|
||||
return strconv.FormatUint(uint64(v), 10)
|
||||
}
|
||||
58
vendor/go.uber.org/atomic/unsafe_pointer.go
generated
vendored
58
vendor/go.uber.org/atomic/unsafe_pointer.go
generated
vendored
|
|
@ -1,58 +0,0 @@
|
|||
// Copyright (c) 2021 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package atomic
|
||||
|
||||
import (
|
||||
"sync/atomic"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// UnsafePointer is an atomic wrapper around unsafe.Pointer.
|
||||
type UnsafePointer struct {
|
||||
_ nocmp // disallow non-atomic comparison
|
||||
|
||||
v unsafe.Pointer
|
||||
}
|
||||
|
||||
// NewUnsafePointer creates a new UnsafePointer.
|
||||
func NewUnsafePointer(val unsafe.Pointer) *UnsafePointer {
|
||||
return &UnsafePointer{v: val}
|
||||
}
|
||||
|
||||
// Load atomically loads the wrapped value.
|
||||
func (p *UnsafePointer) Load() unsafe.Pointer {
|
||||
return atomic.LoadPointer(&p.v)
|
||||
}
|
||||
|
||||
// Store atomically stores the passed value.
|
||||
func (p *UnsafePointer) Store(val unsafe.Pointer) {
|
||||
atomic.StorePointer(&p.v, val)
|
||||
}
|
||||
|
||||
// Swap atomically swaps the wrapped unsafe.Pointer and returns the old value.
|
||||
func (p *UnsafePointer) Swap(val unsafe.Pointer) (old unsafe.Pointer) {
|
||||
return atomic.SwapPointer(&p.v, val)
|
||||
}
|
||||
|
||||
// CAS is an atomic compare-and-swap.
|
||||
func (p *UnsafePointer) CAS(old, new unsafe.Pointer) (swapped bool) {
|
||||
return atomic.CompareAndSwapPointer(&p.v, old, new)
|
||||
}
|
||||
31
vendor/go.uber.org/atomic/value.go
generated
vendored
31
vendor/go.uber.org/atomic/value.go
generated
vendored
|
|
@ -1,31 +0,0 @@
|
|||
// Copyright (c) 2020 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package atomic
|
||||
|
||||
import "sync/atomic"
|
||||
|
||||
// Value shadows the type of the same name from sync/atomic
|
||||
// https://godoc.org/sync/atomic#Value
|
||||
type Value struct {
|
||||
atomic.Value
|
||||
|
||||
_ nocmp // disallow non-atomic comparison
|
||||
}
|
||||
15
vendor/go.uber.org/multierr/CHANGELOG.md
generated
vendored
15
vendor/go.uber.org/multierr/CHANGELOG.md
generated
vendored
|
|
@ -1,6 +1,21 @@
|
|||
Releases
|
||||
========
|
||||
|
||||
v1.11.0 (2023-03-28)
|
||||
====================
|
||||
- `Errors` now supports any error that implements multiple-error
|
||||
interface.
|
||||
- Add `Every` function to allow checking if all errors in the chain
|
||||
satisfies `errors.Is` against the target error.
|
||||
|
||||
v1.10.0 (2023-03-08)
|
||||
====================
|
||||
|
||||
- Comply with Go 1.20's multiple-error interface.
|
||||
- Drop Go 1.18 support.
|
||||
Per the support policy, only Go 1.19 and 1.20 are supported now.
|
||||
- Drop all non-test external dependencies.
|
||||
|
||||
v1.9.0 (2022-12-12)
|
||||
===================
|
||||
|
||||
|
|
|
|||
22
vendor/go.uber.org/multierr/README.md
generated
vendored
22
vendor/go.uber.org/multierr/README.md
generated
vendored
|
|
@ -2,9 +2,29 @@
|
|||
|
||||
`multierr` allows combining one or more Go `error`s together.
|
||||
|
||||
## Features
|
||||
|
||||
- **Idiomatic**:
|
||||
multierr follows best practices in Go, and keeps your code idiomatic.
|
||||
- It keeps the underlying error type hidden,
|
||||
allowing you to deal in `error` values exclusively.
|
||||
- It provides APIs to safely append into an error from a `defer` statement.
|
||||
- **Performant**:
|
||||
multierr is optimized for performance:
|
||||
- It avoids allocations where possible.
|
||||
- It utilizes slice resizing semantics to optimize common cases
|
||||
like appending into the same error object from a loop.
|
||||
- **Interoperable**:
|
||||
multierr interoperates with the Go standard library's error APIs seamlessly:
|
||||
- The `errors.Is` and `errors.As` functions *just work*.
|
||||
- **Lightweight**:
|
||||
multierr comes with virtually no dependencies.
|
||||
|
||||
## Installation
|
||||
|
||||
go get -u go.uber.org/multierr
|
||||
```bash
|
||||
go get -u go.uber.org/multierr@latest
|
||||
```
|
||||
|
||||
## Status
|
||||
|
||||
|
|
|
|||
63
vendor/go.uber.org/multierr/error.go
generated
vendored
63
vendor/go.uber.org/multierr/error.go
generated
vendored
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2017-2021 Uber Technologies, Inc.
|
||||
// Copyright (c) 2017-2023 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
@ -147,8 +147,7 @@ import (
|
|||
"io"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"go.uber.org/atomic"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
@ -196,23 +195,7 @@ type errorGroup interface {
|
|||
//
|
||||
// Callers of this function are free to modify the returned slice.
|
||||
func Errors(err error) []error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Note that we're casting to multiError, not errorGroup. Our contract is
|
||||
// that returned errors MAY implement errorGroup. Errors, however, only
|
||||
// has special behavior for multierr-specific error objects.
|
||||
//
|
||||
// This behavior can be expanded in the future but I think it's prudent to
|
||||
// start with as little as possible in terms of contract and possibility
|
||||
// of misuse.
|
||||
eg, ok := err.(*multiError)
|
||||
if !ok {
|
||||
return []error{err}
|
||||
}
|
||||
|
||||
return append(([]error)(nil), eg.Errors()...)
|
||||
return extractErrors(err)
|
||||
}
|
||||
|
||||
// multiError is an error that holds one or more errors.
|
||||
|
|
@ -227,8 +210,6 @@ type multiError struct {
|
|||
errors []error
|
||||
}
|
||||
|
||||
var _ errorGroup = (*multiError)(nil)
|
||||
|
||||
// Errors returns the list of underlying errors.
|
||||
//
|
||||
// This slice MUST NOT be modified.
|
||||
|
|
@ -239,33 +220,6 @@ func (merr *multiError) Errors() []error {
|
|||
return merr.errors
|
||||
}
|
||||
|
||||
// As attempts to find the first error in the error list that matches the type
|
||||
// of the value that target points to.
|
||||
//
|
||||
// This function allows errors.As to traverse the values stored on the
|
||||
// multierr error.
|
||||
func (merr *multiError) As(target interface{}) bool {
|
||||
for _, err := range merr.Errors() {
|
||||
if errors.As(err, target) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Is attempts to match the provided error against errors in the error list.
|
||||
//
|
||||
// This function allows errors.Is to traverse the values stored on the
|
||||
// multierr error.
|
||||
func (merr *multiError) Is(target error) bool {
|
||||
for _, err := range merr.Errors() {
|
||||
if errors.Is(err, target) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (merr *multiError) Error() string {
|
||||
if merr == nil {
|
||||
return ""
|
||||
|
|
@ -281,6 +235,17 @@ func (merr *multiError) Error() string {
|
|||
return result
|
||||
}
|
||||
|
||||
// Every compares every error in the given err against the given target error
|
||||
// using [errors.Is], and returns true only if every comparison returned true.
|
||||
func Every(err error, target error) bool {
|
||||
for _, e := range extractErrors(err) {
|
||||
if !errors.Is(e, target) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (merr *multiError) Format(f fmt.State, c rune) {
|
||||
if c == 'v' && f.Flag('+') {
|
||||
merr.writeMultiline(f)
|
||||
|
|
|
|||
37
vendor/go.uber.org/atomic/error_ext.go → vendor/go.uber.org/multierr/error_post_go120.go
generated
vendored
37
vendor/go.uber.org/atomic/error_ext.go → vendor/go.uber.org/multierr/error_post_go120.go
generated
vendored
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2020 Uber Technologies, Inc.
|
||||
// Copyright (c) 2017-2023 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
@ -18,22 +18,31 @@
|
|||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package atomic
|
||||
//go:build go1.20
|
||||
// +build go1.20
|
||||
|
||||
// atomic.Value panics on nil inputs, or if the underlying type changes.
|
||||
// Stabilize by always storing a custom struct that we control.
|
||||
package multierr
|
||||
|
||||
//go:generate bin/gen-atomicwrapper -name=Error -type=error -wrapped=Value -pack=packError -unpack=unpackError -file=error.go
|
||||
|
||||
type packedError struct{ Value error }
|
||||
|
||||
func packError(v error) interface{} {
|
||||
return packedError{v}
|
||||
// Unwrap returns a list of errors wrapped by this multierr.
|
||||
func (merr *multiError) Unwrap() []error {
|
||||
return merr.Errors()
|
||||
}
|
||||
|
||||
func unpackError(v interface{}) error {
|
||||
if err, ok := v.(packedError); ok {
|
||||
return err.Value
|
||||
type multipleErrors interface {
|
||||
Unwrap() []error
|
||||
}
|
||||
|
||||
func extractErrors(err error) []error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
|
||||
// check if the given err is an Unwrapable error that
|
||||
// implements multipleErrors interface.
|
||||
eg, ok := err.(multipleErrors)
|
||||
if !ok {
|
||||
return []error{err}
|
||||
}
|
||||
|
||||
return append(([]error)(nil), eg.Unwrap()...)
|
||||
}
|
||||
79
vendor/go.uber.org/multierr/error_pre_go120.go
generated
vendored
Normal file
79
vendor/go.uber.org/multierr/error_pre_go120.go
generated
vendored
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
// Copyright (c) 2017-2023 Uber Technologies, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
//go:build !go1.20
|
||||
// +build !go1.20
|
||||
|
||||
package multierr
|
||||
|
||||
import "errors"
|
||||
|
||||
// Versions of Go before 1.20 did not support the Unwrap() []error method.
|
||||
// This provides a similar behavior by implementing the Is(..) and As(..)
|
||||
// methods.
|
||||
// See the errors.Join proposal for details:
|
||||
// https://github.com/golang/go/issues/53435
|
||||
|
||||
// As attempts to find the first error in the error list that matches the type
|
||||
// of the value that target points to.
|
||||
//
|
||||
// This function allows errors.As to traverse the values stored on the
|
||||
// multierr error.
|
||||
func (merr *multiError) As(target interface{}) bool {
|
||||
for _, err := range merr.Errors() {
|
||||
if errors.As(err, target) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Is attempts to match the provided error against errors in the error list.
|
||||
//
|
||||
// This function allows errors.Is to traverse the values stored on the
|
||||
// multierr error.
|
||||
func (merr *multiError) Is(target error) bool {
|
||||
for _, err := range merr.Errors() {
|
||||
if errors.Is(err, target) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func extractErrors(err error) []error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Note that we're casting to multiError, not errorGroup. Our contract is
|
||||
// that returned errors MAY implement errorGroup. Errors, however, only
|
||||
// has special behavior for multierr-specific error objects.
|
||||
//
|
||||
// This behavior can be expanded in the future but I think it's prudent to
|
||||
// start with as little as possible in terms of contract and possibility
|
||||
// of misuse.
|
||||
eg, ok := err.(*multiError)
|
||||
if !ok {
|
||||
return []error{err}
|
||||
}
|
||||
|
||||
return append(([]error)(nil), eg.Errors()...)
|
||||
}
|
||||
8
vendor/go.uber.org/multierr/glide.yaml
generated
vendored
8
vendor/go.uber.org/multierr/glide.yaml
generated
vendored
|
|
@ -1,8 +0,0 @@
|
|||
package: go.uber.org/multierr
|
||||
import:
|
||||
- package: go.uber.org/atomic
|
||||
version: ^1
|
||||
testImport:
|
||||
- package: github.com/stretchr/testify
|
||||
subpackages:
|
||||
- assert
|
||||
4
vendor/golang.org/x/exp/LICENSE
generated
vendored
4
vendor/golang.org/x/exp/LICENSE
generated
vendored
|
|
@ -1,4 +1,4 @@
|
|||
Copyright (c) 2009 The Go Authors. All rights reserved.
|
||||
Copyright 2009 The Go Authors.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
|
|
@ -10,7 +10,7 @@ notice, this list of conditions and the following disclaimer.
|
|||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
* Neither the name of Google LLC nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
|
|
|
|||
50
vendor/golang.org/x/exp/constraints/constraints.go
generated
vendored
50
vendor/golang.org/x/exp/constraints/constraints.go
generated
vendored
|
|
@ -1,50 +0,0 @@
|
|||
// Copyright 2021 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package constraints defines a set of useful constraints to be used
|
||||
// with type parameters.
|
||||
package constraints
|
||||
|
||||
// Signed is a constraint that permits any signed integer type.
|
||||
// If future releases of Go add new predeclared signed integer types,
|
||||
// this constraint will be modified to include them.
|
||||
type Signed interface {
|
||||
~int | ~int8 | ~int16 | ~int32 | ~int64
|
||||
}
|
||||
|
||||
// Unsigned is a constraint that permits any unsigned integer type.
|
||||
// If future releases of Go add new predeclared unsigned integer types,
|
||||
// this constraint will be modified to include them.
|
||||
type Unsigned interface {
|
||||
~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr
|
||||
}
|
||||
|
||||
// Integer is a constraint that permits any integer type.
|
||||
// If future releases of Go add new predeclared integer types,
|
||||
// this constraint will be modified to include them.
|
||||
type Integer interface {
|
||||
Signed | Unsigned
|
||||
}
|
||||
|
||||
// Float is a constraint that permits any floating-point type.
|
||||
// If future releases of Go add new predeclared floating-point types,
|
||||
// this constraint will be modified to include them.
|
||||
type Float interface {
|
||||
~float32 | ~float64
|
||||
}
|
||||
|
||||
// Complex is a constraint that permits any complex numeric type.
|
||||
// If future releases of Go add new predeclared complex numeric types,
|
||||
// this constraint will be modified to include them.
|
||||
type Complex interface {
|
||||
~complex64 | ~complex128
|
||||
}
|
||||
|
||||
// Ordered is a constraint that permits any ordered type: any type
|
||||
// that supports the operators < <= >= >.
|
||||
// If future releases of Go add new ordered types,
|
||||
// this constraint will be modified to include them.
|
||||
type Ordered interface {
|
||||
Integer | Float | ~string
|
||||
}
|
||||
44
vendor/golang.org/x/exp/slices/cmp.go
generated
vendored
44
vendor/golang.org/x/exp/slices/cmp.go
generated
vendored
|
|
@ -1,44 +0,0 @@
|
|||
// Copyright 2023 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package slices
|
||||
|
||||
import "golang.org/x/exp/constraints"
|
||||
|
||||
// min is a version of the predeclared function from the Go 1.21 release.
|
||||
func min[T constraints.Ordered](a, b T) T {
|
||||
if a < b || isNaN(a) {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// max is a version of the predeclared function from the Go 1.21 release.
|
||||
func max[T constraints.Ordered](a, b T) T {
|
||||
if a > b || isNaN(a) {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// cmpLess is a copy of cmp.Less from the Go 1.21 release.
|
||||
func cmpLess[T constraints.Ordered](x, y T) bool {
|
||||
return (isNaN(x) && !isNaN(y)) || x < y
|
||||
}
|
||||
|
||||
// cmpCompare is a copy of cmp.Compare from the Go 1.21 release.
|
||||
func cmpCompare[T constraints.Ordered](x, y T) int {
|
||||
xNaN := isNaN(x)
|
||||
yNaN := isNaN(y)
|
||||
if xNaN && yNaN {
|
||||
return 0
|
||||
}
|
||||
if xNaN || x < y {
|
||||
return -1
|
||||
}
|
||||
if yNaN || x > y {
|
||||
return +1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
414
vendor/golang.org/x/exp/slices/slices.go
generated
vendored
414
vendor/golang.org/x/exp/slices/slices.go
generated
vendored
|
|
@ -6,26 +6,22 @@
|
|||
package slices
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/exp/constraints"
|
||||
"cmp"
|
||||
"slices"
|
||||
)
|
||||
|
||||
// TODO(adonovan): when https://go.dev/issue/32816 is accepted, all of
|
||||
// these functions should be annotated (provisionally with "//go:fix
|
||||
// inline") so that tools can safely and automatically replace calls
|
||||
// to exp/slices with calls to std slices by inlining them.
|
||||
|
||||
// Equal reports whether two slices are equal: the same length and all
|
||||
// elements equal. If the lengths are different, Equal returns false.
|
||||
// Otherwise, the elements are compared in increasing index order, and the
|
||||
// comparison stops at the first unequal pair.
|
||||
// Floating point NaNs are not considered equal.
|
||||
func Equal[S ~[]E, E comparable](s1, s2 S) bool {
|
||||
if len(s1) != len(s2) {
|
||||
return false
|
||||
}
|
||||
for i := range s1 {
|
||||
if s1[i] != s2[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
return slices.Equal(s1, s2)
|
||||
}
|
||||
|
||||
// EqualFunc reports whether two slices are equal using an equality
|
||||
|
|
@ -34,16 +30,7 @@ func Equal[S ~[]E, E comparable](s1, s2 S) bool {
|
|||
// increasing index order, and the comparison stops at the first index
|
||||
// for which eq returns false.
|
||||
func EqualFunc[S1 ~[]E1, S2 ~[]E2, E1, E2 any](s1 S1, s2 S2, eq func(E1, E2) bool) bool {
|
||||
if len(s1) != len(s2) {
|
||||
return false
|
||||
}
|
||||
for i, v1 := range s1 {
|
||||
v2 := s2[i]
|
||||
if !eq(v1, v2) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
return slices.EqualFunc(s1, s2, eq)
|
||||
}
|
||||
|
||||
// Compare compares the elements of s1 and s2, using [cmp.Compare] on each pair
|
||||
|
|
@ -53,20 +40,8 @@ func EqualFunc[S1 ~[]E1, S2 ~[]E2, E1, E2 any](s1 S1, s2 S2, eq func(E1, E2) boo
|
|||
// If both slices are equal until one of them ends, the shorter slice is
|
||||
// considered less than the longer one.
|
||||
// The result is 0 if s1 == s2, -1 if s1 < s2, and +1 if s1 > s2.
|
||||
func Compare[S ~[]E, E constraints.Ordered](s1, s2 S) int {
|
||||
for i, v1 := range s1 {
|
||||
if i >= len(s2) {
|
||||
return +1
|
||||
}
|
||||
v2 := s2[i]
|
||||
if c := cmpCompare(v1, v2); c != 0 {
|
||||
return c
|
||||
}
|
||||
}
|
||||
if len(s1) < len(s2) {
|
||||
return -1
|
||||
}
|
||||
return 0
|
||||
func Compare[S ~[]E, E cmp.Ordered](s1, s2 S) int {
|
||||
return slices.Compare(s1, s2)
|
||||
}
|
||||
|
||||
// CompareFunc is like [Compare] but uses a custom comparison function on each
|
||||
|
|
@ -75,52 +50,30 @@ func Compare[S ~[]E, E constraints.Ordered](s1, s2 S) int {
|
|||
// returns 0 the result is 0 if len(s1) == len(s2), -1 if len(s1) < len(s2),
|
||||
// and +1 if len(s1) > len(s2).
|
||||
func CompareFunc[S1 ~[]E1, S2 ~[]E2, E1, E2 any](s1 S1, s2 S2, cmp func(E1, E2) int) int {
|
||||
for i, v1 := range s1 {
|
||||
if i >= len(s2) {
|
||||
return +1
|
||||
}
|
||||
v2 := s2[i]
|
||||
if c := cmp(v1, v2); c != 0 {
|
||||
return c
|
||||
}
|
||||
}
|
||||
if len(s1) < len(s2) {
|
||||
return -1
|
||||
}
|
||||
return 0
|
||||
return slices.CompareFunc(s1, s2, cmp)
|
||||
}
|
||||
|
||||
// Index returns the index of the first occurrence of v in s,
|
||||
// or -1 if not present.
|
||||
func Index[S ~[]E, E comparable](s S, v E) int {
|
||||
for i := range s {
|
||||
if v == s[i] {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
return slices.Index(s, v)
|
||||
}
|
||||
|
||||
// IndexFunc returns the first index i satisfying f(s[i]),
|
||||
// or -1 if none do.
|
||||
func IndexFunc[S ~[]E, E any](s S, f func(E) bool) int {
|
||||
for i := range s {
|
||||
if f(s[i]) {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
return slices.IndexFunc(s, f)
|
||||
}
|
||||
|
||||
// Contains reports whether v is present in s.
|
||||
func Contains[S ~[]E, E comparable](s S, v E) bool {
|
||||
return Index(s, v) >= 0
|
||||
return slices.Contains(s, v)
|
||||
}
|
||||
|
||||
// ContainsFunc reports whether at least one
|
||||
// element e of s satisfies f(e).
|
||||
func ContainsFunc[S ~[]E, E any](s S, f func(E) bool) bool {
|
||||
return IndexFunc(s, f) >= 0
|
||||
return slices.ContainsFunc(s, f)
|
||||
}
|
||||
|
||||
// Insert inserts the values v... into s at index i,
|
||||
|
|
@ -131,255 +84,52 @@ func ContainsFunc[S ~[]E, E any](s S, f func(E) bool) bool {
|
|||
// Insert panics if i is out of range.
|
||||
// This function is O(len(s) + len(v)).
|
||||
func Insert[S ~[]E, E any](s S, i int, v ...E) S {
|
||||
m := len(v)
|
||||
if m == 0 {
|
||||
return s
|
||||
}
|
||||
n := len(s)
|
||||
if i == n {
|
||||
return append(s, v...)
|
||||
}
|
||||
if n+m > cap(s) {
|
||||
// Use append rather than make so that we bump the size of
|
||||
// the slice up to the next storage class.
|
||||
// This is what Grow does but we don't call Grow because
|
||||
// that might copy the values twice.
|
||||
s2 := append(s[:i], make(S, n+m-i)...)
|
||||
copy(s2[i:], v)
|
||||
copy(s2[i+m:], s[i:])
|
||||
return s2
|
||||
}
|
||||
s = s[:n+m]
|
||||
|
||||
// before:
|
||||
// s: aaaaaaaabbbbccccccccdddd
|
||||
// ^ ^ ^ ^
|
||||
// i i+m n n+m
|
||||
// after:
|
||||
// s: aaaaaaaavvvvbbbbcccccccc
|
||||
// ^ ^ ^ ^
|
||||
// i i+m n n+m
|
||||
//
|
||||
// a are the values that don't move in s.
|
||||
// v are the values copied in from v.
|
||||
// b and c are the values from s that are shifted up in index.
|
||||
// d are the values that get overwritten, never to be seen again.
|
||||
|
||||
if !overlaps(v, s[i+m:]) {
|
||||
// Easy case - v does not overlap either the c or d regions.
|
||||
// (It might be in some of a or b, or elsewhere entirely.)
|
||||
// The data we copy up doesn't write to v at all, so just do it.
|
||||
|
||||
copy(s[i+m:], s[i:])
|
||||
|
||||
// Now we have
|
||||
// s: aaaaaaaabbbbbbbbcccccccc
|
||||
// ^ ^ ^ ^
|
||||
// i i+m n n+m
|
||||
// Note the b values are duplicated.
|
||||
|
||||
copy(s[i:], v)
|
||||
|
||||
// Now we have
|
||||
// s: aaaaaaaavvvvbbbbcccccccc
|
||||
// ^ ^ ^ ^
|
||||
// i i+m n n+m
|
||||
// That's the result we want.
|
||||
return s
|
||||
}
|
||||
|
||||
// The hard case - v overlaps c or d. We can't just shift up
|
||||
// the data because we'd move or clobber the values we're trying
|
||||
// to insert.
|
||||
// So instead, write v on top of d, then rotate.
|
||||
copy(s[n:], v)
|
||||
|
||||
// Now we have
|
||||
// s: aaaaaaaabbbbccccccccvvvv
|
||||
// ^ ^ ^ ^
|
||||
// i i+m n n+m
|
||||
|
||||
rotateRight(s[i:], m)
|
||||
|
||||
// Now we have
|
||||
// s: aaaaaaaavvvvbbbbcccccccc
|
||||
// ^ ^ ^ ^
|
||||
// i i+m n n+m
|
||||
// That's the result we want.
|
||||
return s
|
||||
return slices.Insert(s, i, v...)
|
||||
}
|
||||
|
||||
// Delete removes the elements s[i:j] from s, returning the modified slice.
|
||||
// Delete panics if s[i:j] is not a valid slice of s.
|
||||
// Delete is O(len(s)-j), so if many items must be deleted, it is better to
|
||||
// Delete panics if j > len(s) or s[i:j] is not a valid slice of s.
|
||||
// Delete is O(len(s)-i), so if many items must be deleted, it is better to
|
||||
// make a single call deleting them all together than to delete one at a time.
|
||||
// Delete might not modify the elements s[len(s)-(j-i):len(s)]. If those
|
||||
// elements contain pointers you might consider zeroing those elements so that
|
||||
// objects they reference can be garbage collected.
|
||||
// Delete zeroes the elements s[len(s)-(j-i):len(s)].
|
||||
func Delete[S ~[]E, E any](s S, i, j int) S {
|
||||
_ = s[i:j] // bounds check
|
||||
|
||||
return append(s[:i], s[j:]...)
|
||||
return slices.Delete(s, i, j)
|
||||
}
|
||||
|
||||
// DeleteFunc removes any elements from s for which del returns true,
|
||||
// returning the modified slice.
|
||||
// When DeleteFunc removes m elements, it might not modify the elements
|
||||
// s[len(s)-m:len(s)]. If those elements contain pointers you might consider
|
||||
// zeroing those elements so that objects they reference can be garbage
|
||||
// collected.
|
||||
// DeleteFunc zeroes the elements between the new length and the original length.
|
||||
func DeleteFunc[S ~[]E, E any](s S, del func(E) bool) S {
|
||||
i := IndexFunc(s, del)
|
||||
if i == -1 {
|
||||
return s
|
||||
}
|
||||
// Don't start copying elements until we find one to delete.
|
||||
for j := i + 1; j < len(s); j++ {
|
||||
if v := s[j]; !del(v) {
|
||||
s[i] = v
|
||||
i++
|
||||
}
|
||||
}
|
||||
return s[:i]
|
||||
return slices.DeleteFunc(s, del)
|
||||
}
|
||||
|
||||
// Replace replaces the elements s[i:j] by the given v, and returns the
|
||||
// modified slice. Replace panics if s[i:j] is not a valid slice of s.
|
||||
// When len(v) < (j-i), Replace zeroes the elements between the new length and the original length.
|
||||
func Replace[S ~[]E, E any](s S, i, j int, v ...E) S {
|
||||
_ = s[i:j] // verify that i:j is a valid subslice
|
||||
|
||||
if i == j {
|
||||
return Insert(s, i, v...)
|
||||
}
|
||||
if j == len(s) {
|
||||
return append(s[:i], v...)
|
||||
}
|
||||
|
||||
tot := len(s[:i]) + len(v) + len(s[j:])
|
||||
if tot > cap(s) {
|
||||
// Too big to fit, allocate and copy over.
|
||||
s2 := append(s[:i], make(S, tot-i)...) // See Insert
|
||||
copy(s2[i:], v)
|
||||
copy(s2[i+len(v):], s[j:])
|
||||
return s2
|
||||
}
|
||||
|
||||
r := s[:tot]
|
||||
|
||||
if i+len(v) <= j {
|
||||
// Easy, as v fits in the deleted portion.
|
||||
copy(r[i:], v)
|
||||
if i+len(v) != j {
|
||||
copy(r[i+len(v):], s[j:])
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// We are expanding (v is bigger than j-i).
|
||||
// The situation is something like this:
|
||||
// (example has i=4,j=8,len(s)=16,len(v)=6)
|
||||
// s: aaaaxxxxbbbbbbbbyy
|
||||
// ^ ^ ^ ^
|
||||
// i j len(s) tot
|
||||
// a: prefix of s
|
||||
// x: deleted range
|
||||
// b: more of s
|
||||
// y: area to expand into
|
||||
|
||||
if !overlaps(r[i+len(v):], v) {
|
||||
// Easy, as v is not clobbered by the first copy.
|
||||
copy(r[i+len(v):], s[j:])
|
||||
copy(r[i:], v)
|
||||
return r
|
||||
}
|
||||
|
||||
// This is a situation where we don't have a single place to which
|
||||
// we can copy v. Parts of it need to go to two different places.
|
||||
// We want to copy the prefix of v into y and the suffix into x, then
|
||||
// rotate |y| spots to the right.
|
||||
//
|
||||
// v[2:] v[:2]
|
||||
// | |
|
||||
// s: aaaavvvvbbbbbbbbvv
|
||||
// ^ ^ ^ ^
|
||||
// i j len(s) tot
|
||||
//
|
||||
// If either of those two destinations don't alias v, then we're good.
|
||||
y := len(v) - (j - i) // length of y portion
|
||||
|
||||
if !overlaps(r[i:j], v) {
|
||||
copy(r[i:j], v[y:])
|
||||
copy(r[len(s):], v[:y])
|
||||
rotateRight(r[i:], y)
|
||||
return r
|
||||
}
|
||||
if !overlaps(r[len(s):], v) {
|
||||
copy(r[len(s):], v[:y])
|
||||
copy(r[i:j], v[y:])
|
||||
rotateRight(r[i:], y)
|
||||
return r
|
||||
}
|
||||
|
||||
// Now we know that v overlaps both x and y.
|
||||
// That means that the entirety of b is *inside* v.
|
||||
// So we don't need to preserve b at all; instead we
|
||||
// can copy v first, then copy the b part of v out of
|
||||
// v to the right destination.
|
||||
k := startIdx(v, s[j:])
|
||||
copy(r[i:], v)
|
||||
copy(r[i+len(v):], r[i+k:])
|
||||
return r
|
||||
return slices.Replace(s, i, j, v...)
|
||||
}
|
||||
|
||||
// Clone returns a copy of the slice.
|
||||
// The elements are copied using assignment, so this is a shallow clone.
|
||||
func Clone[S ~[]E, E any](s S) S {
|
||||
// Preserve nil in case it matters.
|
||||
if s == nil {
|
||||
return nil
|
||||
}
|
||||
return append(S([]E{}), s...)
|
||||
return slices.Clone(s)
|
||||
}
|
||||
|
||||
// Compact replaces consecutive runs of equal elements with a single copy.
|
||||
// This is like the uniq command found on Unix.
|
||||
// Compact modifies the contents of the slice s and returns the modified slice,
|
||||
// which may have a smaller length.
|
||||
// When Compact discards m elements in total, it might not modify the elements
|
||||
// s[len(s)-m:len(s)]. If those elements contain pointers you might consider
|
||||
// zeroing those elements so that objects they reference can be garbage collected.
|
||||
// Compact zeroes the elements between the new length and the original length.
|
||||
func Compact[S ~[]E, E comparable](s S) S {
|
||||
if len(s) < 2 {
|
||||
return s
|
||||
}
|
||||
i := 1
|
||||
for k := 1; k < len(s); k++ {
|
||||
if s[k] != s[k-1] {
|
||||
if i != k {
|
||||
s[i] = s[k]
|
||||
}
|
||||
i++
|
||||
}
|
||||
}
|
||||
return s[:i]
|
||||
return slices.Compact(s)
|
||||
}
|
||||
|
||||
// CompactFunc is like [Compact] but uses an equality function to compare elements.
|
||||
// For runs of elements that compare equal, CompactFunc keeps the first one.
|
||||
// CompactFunc zeroes the elements between the new length and the original length.
|
||||
func CompactFunc[S ~[]E, E any](s S, eq func(E, E) bool) S {
|
||||
if len(s) < 2 {
|
||||
return s
|
||||
}
|
||||
i := 1
|
||||
for k := 1; k < len(s); k++ {
|
||||
if !eq(s[k], s[k-1]) {
|
||||
if i != k {
|
||||
s[i] = s[k]
|
||||
}
|
||||
i++
|
||||
}
|
||||
}
|
||||
return s[:i]
|
||||
return slices.CompactFunc(s, eq)
|
||||
}
|
||||
|
||||
// Grow increases the slice's capacity, if necessary, to guarantee space for
|
||||
|
|
@ -387,113 +137,15 @@ func CompactFunc[S ~[]E, E any](s S, eq func(E, E) bool) S {
|
|||
// to the slice without another allocation. If n is negative or too large to
|
||||
// allocate the memory, Grow panics.
|
||||
func Grow[S ~[]E, E any](s S, n int) S {
|
||||
if n < 0 {
|
||||
panic("cannot be negative")
|
||||
}
|
||||
if n -= cap(s) - len(s); n > 0 {
|
||||
// TODO(https://go.dev/issue/53888): Make using []E instead of S
|
||||
// to workaround a compiler bug where the runtime.growslice optimization
|
||||
// does not take effect. Revert when the compiler is fixed.
|
||||
s = append([]E(s)[:cap(s)], make([]E, n)...)[:len(s)]
|
||||
}
|
||||
return s
|
||||
return slices.Grow(s, n)
|
||||
}
|
||||
|
||||
// Clip removes unused capacity from the slice, returning s[:len(s):len(s)].
|
||||
func Clip[S ~[]E, E any](s S) S {
|
||||
return s[:len(s):len(s)]
|
||||
}
|
||||
|
||||
// Rotation algorithm explanation:
|
||||
//
|
||||
// rotate left by 2
|
||||
// start with
|
||||
// 0123456789
|
||||
// split up like this
|
||||
// 01 234567 89
|
||||
// swap first 2 and last 2
|
||||
// 89 234567 01
|
||||
// join first parts
|
||||
// 89234567 01
|
||||
// recursively rotate first left part by 2
|
||||
// 23456789 01
|
||||
// join at the end
|
||||
// 2345678901
|
||||
//
|
||||
// rotate left by 8
|
||||
// start with
|
||||
// 0123456789
|
||||
// split up like this
|
||||
// 01 234567 89
|
||||
// swap first 2 and last 2
|
||||
// 89 234567 01
|
||||
// join last parts
|
||||
// 89 23456701
|
||||
// recursively rotate second part left by 6
|
||||
// 89 01234567
|
||||
// join at the end
|
||||
// 8901234567
|
||||
|
||||
// TODO: There are other rotate algorithms.
|
||||
// This algorithm has the desirable property that it moves each element exactly twice.
|
||||
// The triple-reverse algorithm is simpler and more cache friendly, but takes more writes.
|
||||
// The follow-cycles algorithm can be 1-write but it is not very cache friendly.
|
||||
|
||||
// rotateLeft rotates b left by n spaces.
|
||||
// s_final[i] = s_orig[i+r], wrapping around.
|
||||
func rotateLeft[E any](s []E, r int) {
|
||||
for r != 0 && r != len(s) {
|
||||
if r*2 <= len(s) {
|
||||
swap(s[:r], s[len(s)-r:])
|
||||
s = s[:len(s)-r]
|
||||
} else {
|
||||
swap(s[:len(s)-r], s[r:])
|
||||
s, r = s[len(s)-r:], r*2-len(s)
|
||||
}
|
||||
}
|
||||
}
|
||||
func rotateRight[E any](s []E, r int) {
|
||||
rotateLeft(s, len(s)-r)
|
||||
}
|
||||
|
||||
// swap swaps the contents of x and y. x and y must be equal length and disjoint.
|
||||
func swap[E any](x, y []E) {
|
||||
for i := 0; i < len(x); i++ {
|
||||
x[i], y[i] = y[i], x[i]
|
||||
}
|
||||
}
|
||||
|
||||
// overlaps reports whether the memory ranges a[0:len(a)] and b[0:len(b)] overlap.
|
||||
func overlaps[E any](a, b []E) bool {
|
||||
if len(a) == 0 || len(b) == 0 {
|
||||
return false
|
||||
}
|
||||
elemSize := unsafe.Sizeof(a[0])
|
||||
if elemSize == 0 {
|
||||
return false
|
||||
}
|
||||
// TODO: use a runtime/unsafe facility once one becomes available. See issue 12445.
|
||||
// Also see crypto/internal/alias/alias.go:AnyOverlap
|
||||
return uintptr(unsafe.Pointer(&a[0])) <= uintptr(unsafe.Pointer(&b[len(b)-1]))+(elemSize-1) &&
|
||||
uintptr(unsafe.Pointer(&b[0])) <= uintptr(unsafe.Pointer(&a[len(a)-1]))+(elemSize-1)
|
||||
}
|
||||
|
||||
// startIdx returns the index in haystack where the needle starts.
|
||||
// prerequisite: the needle must be aliased entirely inside the haystack.
|
||||
func startIdx[E any](haystack, needle []E) int {
|
||||
p := &needle[0]
|
||||
for i := range haystack {
|
||||
if p == &haystack[i] {
|
||||
return i
|
||||
}
|
||||
}
|
||||
// TODO: what if the overlap is by a non-integral number of Es?
|
||||
panic("needle not found")
|
||||
return slices.Clip(s)
|
||||
}
|
||||
|
||||
// Reverse reverses the elements of the slice in place.
|
||||
func Reverse[S ~[]E, E any](s S) {
|
||||
for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
|
||||
s[i], s[j] = s[j], s[i]
|
||||
}
|
||||
slices.Reverse(s)
|
||||
}
|
||||
|
|
|
|||
147
vendor/golang.org/x/exp/slices/sort.go
generated
vendored
147
vendor/golang.org/x/exp/slices/sort.go
generated
vendored
|
|
@ -2,143 +2,86 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:generate go run $GOROOT/src/sort/gen_sort_variants.go -exp
|
||||
|
||||
package slices
|
||||
|
||||
import (
|
||||
"math/bits"
|
||||
|
||||
"golang.org/x/exp/constraints"
|
||||
"cmp"
|
||||
"slices"
|
||||
)
|
||||
|
||||
// TODO(adonovan): add a "//go:fix inline" annotation to each function
|
||||
// in this file; see https://go.dev/issue/32816.
|
||||
|
||||
// Sort sorts a slice of any ordered type in ascending order.
|
||||
// When sorting floating-point numbers, NaNs are ordered before other values.
|
||||
func Sort[S ~[]E, E constraints.Ordered](x S) {
|
||||
n := len(x)
|
||||
pdqsortOrdered(x, 0, n, bits.Len(uint(n)))
|
||||
func Sort[S ~[]E, E cmp.Ordered](x S) {
|
||||
slices.Sort(x)
|
||||
}
|
||||
|
||||
// SortFunc sorts the slice x in ascending order as determined by the cmp
|
||||
// function. This sort is not guaranteed to be stable.
|
||||
// cmp(a, b) should return a negative number when a < b, a positive number when
|
||||
// a > b and zero when a == b.
|
||||
// a > b and zero when a == b or when a is not comparable to b in the sense
|
||||
// of the formal definition of Strict Weak Ordering.
|
||||
//
|
||||
// SortFunc requires that cmp is a strict weak ordering.
|
||||
// See https://en.wikipedia.org/wiki/Weak_ordering#Strict_weak_orderings.
|
||||
// To indicate 'uncomparable', return 0 from the function.
|
||||
func SortFunc[S ~[]E, E any](x S, cmp func(a, b E) int) {
|
||||
n := len(x)
|
||||
pdqsortCmpFunc(x, 0, n, bits.Len(uint(n)), cmp)
|
||||
slices.SortFunc(x, cmp)
|
||||
}
|
||||
|
||||
// SortStableFunc sorts the slice x while keeping the original order of equal
|
||||
// elements, using cmp to compare elements in the same way as [SortFunc].
|
||||
func SortStableFunc[S ~[]E, E any](x S, cmp func(a, b E) int) {
|
||||
stableCmpFunc(x, len(x), cmp)
|
||||
slices.SortStableFunc(x, cmp)
|
||||
}
|
||||
|
||||
// IsSorted reports whether x is sorted in ascending order.
|
||||
func IsSorted[S ~[]E, E constraints.Ordered](x S) bool {
|
||||
for i := len(x) - 1; i > 0; i-- {
|
||||
if cmpLess(x[i], x[i-1]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
func IsSorted[S ~[]E, E cmp.Ordered](x S) bool {
|
||||
return slices.IsSorted(x)
|
||||
}
|
||||
|
||||
// IsSortedFunc reports whether x is sorted in ascending order, with cmp as the
|
||||
// comparison function as defined by [SortFunc].
|
||||
func IsSortedFunc[S ~[]E, E any](x S, cmp func(a, b E) int) bool {
|
||||
for i := len(x) - 1; i > 0; i-- {
|
||||
if cmp(x[i], x[i-1]) < 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
return slices.IsSortedFunc(x, cmp)
|
||||
}
|
||||
|
||||
// Min returns the minimal value in x. It panics if x is empty.
|
||||
// For floating-point numbers, Min propagates NaNs (any NaN value in x
|
||||
// forces the output to be NaN).
|
||||
func Min[S ~[]E, E constraints.Ordered](x S) E {
|
||||
if len(x) < 1 {
|
||||
panic("slices.Min: empty list")
|
||||
}
|
||||
m := x[0]
|
||||
for i := 1; i < len(x); i++ {
|
||||
m = min(m, x[i])
|
||||
}
|
||||
return m
|
||||
func Min[S ~[]E, E cmp.Ordered](x S) E {
|
||||
return slices.Min(x)
|
||||
}
|
||||
|
||||
// MinFunc returns the minimal value in x, using cmp to compare elements.
|
||||
// It panics if x is empty. If there is more than one minimal element
|
||||
// according to the cmp function, MinFunc returns the first one.
|
||||
func MinFunc[S ~[]E, E any](x S, cmp func(a, b E) int) E {
|
||||
if len(x) < 1 {
|
||||
panic("slices.MinFunc: empty list")
|
||||
}
|
||||
m := x[0]
|
||||
for i := 1; i < len(x); i++ {
|
||||
if cmp(x[i], m) < 0 {
|
||||
m = x[i]
|
||||
}
|
||||
}
|
||||
return m
|
||||
return slices.MinFunc(x, cmp)
|
||||
}
|
||||
|
||||
// Max returns the maximal value in x. It panics if x is empty.
|
||||
// For floating-point E, Max propagates NaNs (any NaN value in x
|
||||
// forces the output to be NaN).
|
||||
func Max[S ~[]E, E constraints.Ordered](x S) E {
|
||||
if len(x) < 1 {
|
||||
panic("slices.Max: empty list")
|
||||
}
|
||||
m := x[0]
|
||||
for i := 1; i < len(x); i++ {
|
||||
m = max(m, x[i])
|
||||
}
|
||||
return m
|
||||
func Max[S ~[]E, E cmp.Ordered](x S) E {
|
||||
return slices.Max(x)
|
||||
}
|
||||
|
||||
// MaxFunc returns the maximal value in x, using cmp to compare elements.
|
||||
// It panics if x is empty. If there is more than one maximal element
|
||||
// according to the cmp function, MaxFunc returns the first one.
|
||||
func MaxFunc[S ~[]E, E any](x S, cmp func(a, b E) int) E {
|
||||
if len(x) < 1 {
|
||||
panic("slices.MaxFunc: empty list")
|
||||
}
|
||||
m := x[0]
|
||||
for i := 1; i < len(x); i++ {
|
||||
if cmp(x[i], m) > 0 {
|
||||
m = x[i]
|
||||
}
|
||||
}
|
||||
return m
|
||||
return slices.MaxFunc(x, cmp)
|
||||
}
|
||||
|
||||
// BinarySearch searches for target in a sorted slice and returns the position
|
||||
// where target is found, or the position where target would appear in the
|
||||
// sort order; it also returns a bool saying whether the target is really found
|
||||
// in the slice. The slice must be sorted in increasing order.
|
||||
func BinarySearch[S ~[]E, E constraints.Ordered](x S, target E) (int, bool) {
|
||||
// Inlining is faster than calling BinarySearchFunc with a lambda.
|
||||
n := len(x)
|
||||
// Define x[-1] < target and x[n] >= target.
|
||||
// Invariant: x[i-1] < target, x[j] >= target.
|
||||
i, j := 0, n
|
||||
for i < j {
|
||||
h := int(uint(i+j) >> 1) // avoid overflow when computing h
|
||||
// i ≤ h < j
|
||||
if cmpLess(x[h], target) {
|
||||
i = h + 1 // preserves x[i-1] < target
|
||||
} else {
|
||||
j = h // preserves x[j] >= target
|
||||
}
|
||||
}
|
||||
// i == j, x[i-1] < target, and x[j] (= x[i]) >= target => answer is i.
|
||||
return i, i < n && (x[i] == target || (isNaN(x[i]) && isNaN(target)))
|
||||
func BinarySearch[S ~[]E, E cmp.Ordered](x S, target E) (int, bool) {
|
||||
return slices.BinarySearch(x, target)
|
||||
}
|
||||
|
||||
// BinarySearchFunc works like [BinarySearch], but uses a custom comparison
|
||||
|
|
@ -149,47 +92,5 @@ func BinarySearch[S ~[]E, E constraints.Ordered](x S, target E) (int, bool) {
|
|||
// cmp must implement the same ordering as the slice, such that if
|
||||
// cmp(a, t) < 0 and cmp(b, t) >= 0, then a must precede b in the slice.
|
||||
func BinarySearchFunc[S ~[]E, E, T any](x S, target T, cmp func(E, T) int) (int, bool) {
|
||||
n := len(x)
|
||||
// Define cmp(x[-1], target) < 0 and cmp(x[n], target) >= 0 .
|
||||
// Invariant: cmp(x[i - 1], target) < 0, cmp(x[j], target) >= 0.
|
||||
i, j := 0, n
|
||||
for i < j {
|
||||
h := int(uint(i+j) >> 1) // avoid overflow when computing h
|
||||
// i ≤ h < j
|
||||
if cmp(x[h], target) < 0 {
|
||||
i = h + 1 // preserves cmp(x[i - 1], target) < 0
|
||||
} else {
|
||||
j = h // preserves cmp(x[j], target) >= 0
|
||||
}
|
||||
}
|
||||
// i == j, cmp(x[i-1], target) < 0, and cmp(x[j], target) (= cmp(x[i], target)) >= 0 => answer is i.
|
||||
return i, i < n && cmp(x[i], target) == 0
|
||||
}
|
||||
|
||||
type sortedHint int // hint for pdqsort when choosing the pivot
|
||||
|
||||
const (
|
||||
unknownHint sortedHint = iota
|
||||
increasingHint
|
||||
decreasingHint
|
||||
)
|
||||
|
||||
// xorshift paper: https://www.jstatsoft.org/article/view/v008i14/xorshift.pdf
|
||||
type xorshift uint64
|
||||
|
||||
func (r *xorshift) Next() uint64 {
|
||||
*r ^= *r << 13
|
||||
*r ^= *r >> 17
|
||||
*r ^= *r << 5
|
||||
return uint64(*r)
|
||||
}
|
||||
|
||||
func nextPowerOfTwo(length int) uint {
|
||||
return 1 << bits.Len(uint(length))
|
||||
}
|
||||
|
||||
// isNaN reports whether x is a NaN without requiring the math package.
|
||||
// This will always return false if T is not floating-point.
|
||||
func isNaN[T constraints.Ordered](x T) bool {
|
||||
return x != x
|
||||
return slices.BinarySearchFunc(x, target, cmp)
|
||||
}
|
||||
|
|
|
|||
479
vendor/golang.org/x/exp/slices/zsortanyfunc.go
generated
vendored
479
vendor/golang.org/x/exp/slices/zsortanyfunc.go
generated
vendored
|
|
@ -1,479 +0,0 @@
|
|||
// Code generated by gen_sort_variants.go; DO NOT EDIT.
|
||||
|
||||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package slices
|
||||
|
||||
// insertionSortCmpFunc sorts data[a:b] using insertion sort.
|
||||
func insertionSortCmpFunc[E any](data []E, a, b int, cmp func(a, b E) int) {
|
||||
for i := a + 1; i < b; i++ {
|
||||
for j := i; j > a && (cmp(data[j], data[j-1]) < 0); j-- {
|
||||
data[j], data[j-1] = data[j-1], data[j]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// siftDownCmpFunc implements the heap property on data[lo:hi].
|
||||
// first is an offset into the array where the root of the heap lies.
|
||||
func siftDownCmpFunc[E any](data []E, lo, hi, first int, cmp func(a, b E) int) {
|
||||
root := lo
|
||||
for {
|
||||
child := 2*root + 1
|
||||
if child >= hi {
|
||||
break
|
||||
}
|
||||
if child+1 < hi && (cmp(data[first+child], data[first+child+1]) < 0) {
|
||||
child++
|
||||
}
|
||||
if !(cmp(data[first+root], data[first+child]) < 0) {
|
||||
return
|
||||
}
|
||||
data[first+root], data[first+child] = data[first+child], data[first+root]
|
||||
root = child
|
||||
}
|
||||
}
|
||||
|
||||
func heapSortCmpFunc[E any](data []E, a, b int, cmp func(a, b E) int) {
|
||||
first := a
|
||||
lo := 0
|
||||
hi := b - a
|
||||
|
||||
// Build heap with greatest element at top.
|
||||
for i := (hi - 1) / 2; i >= 0; i-- {
|
||||
siftDownCmpFunc(data, i, hi, first, cmp)
|
||||
}
|
||||
|
||||
// Pop elements, largest first, into end of data.
|
||||
for i := hi - 1; i >= 0; i-- {
|
||||
data[first], data[first+i] = data[first+i], data[first]
|
||||
siftDownCmpFunc(data, lo, i, first, cmp)
|
||||
}
|
||||
}
|
||||
|
||||
// pdqsortCmpFunc sorts data[a:b].
|
||||
// The algorithm based on pattern-defeating quicksort(pdqsort), but without the optimizations from BlockQuicksort.
|
||||
// pdqsort paper: https://arxiv.org/pdf/2106.05123.pdf
|
||||
// C++ implementation: https://github.com/orlp/pdqsort
|
||||
// Rust implementation: https://docs.rs/pdqsort/latest/pdqsort/
|
||||
// limit is the number of allowed bad (very unbalanced) pivots before falling back to heapsort.
|
||||
func pdqsortCmpFunc[E any](data []E, a, b, limit int, cmp func(a, b E) int) {
|
||||
const maxInsertion = 12
|
||||
|
||||
var (
|
||||
wasBalanced = true // whether the last partitioning was reasonably balanced
|
||||
wasPartitioned = true // whether the slice was already partitioned
|
||||
)
|
||||
|
||||
for {
|
||||
length := b - a
|
||||
|
||||
if length <= maxInsertion {
|
||||
insertionSortCmpFunc(data, a, b, cmp)
|
||||
return
|
||||
}
|
||||
|
||||
// Fall back to heapsort if too many bad choices were made.
|
||||
if limit == 0 {
|
||||
heapSortCmpFunc(data, a, b, cmp)
|
||||
return
|
||||
}
|
||||
|
||||
// If the last partitioning was imbalanced, we need to breaking patterns.
|
||||
if !wasBalanced {
|
||||
breakPatternsCmpFunc(data, a, b, cmp)
|
||||
limit--
|
||||
}
|
||||
|
||||
pivot, hint := choosePivotCmpFunc(data, a, b, cmp)
|
||||
if hint == decreasingHint {
|
||||
reverseRangeCmpFunc(data, a, b, cmp)
|
||||
// The chosen pivot was pivot-a elements after the start of the array.
|
||||
// After reversing it is pivot-a elements before the end of the array.
|
||||
// The idea came from Rust's implementation.
|
||||
pivot = (b - 1) - (pivot - a)
|
||||
hint = increasingHint
|
||||
}
|
||||
|
||||
// The slice is likely already sorted.
|
||||
if wasBalanced && wasPartitioned && hint == increasingHint {
|
||||
if partialInsertionSortCmpFunc(data, a, b, cmp) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Probably the slice contains many duplicate elements, partition the slice into
|
||||
// elements equal to and elements greater than the pivot.
|
||||
if a > 0 && !(cmp(data[a-1], data[pivot]) < 0) {
|
||||
mid := partitionEqualCmpFunc(data, a, b, pivot, cmp)
|
||||
a = mid
|
||||
continue
|
||||
}
|
||||
|
||||
mid, alreadyPartitioned := partitionCmpFunc(data, a, b, pivot, cmp)
|
||||
wasPartitioned = alreadyPartitioned
|
||||
|
||||
leftLen, rightLen := mid-a, b-mid
|
||||
balanceThreshold := length / 8
|
||||
if leftLen < rightLen {
|
||||
wasBalanced = leftLen >= balanceThreshold
|
||||
pdqsortCmpFunc(data, a, mid, limit, cmp)
|
||||
a = mid + 1
|
||||
} else {
|
||||
wasBalanced = rightLen >= balanceThreshold
|
||||
pdqsortCmpFunc(data, mid+1, b, limit, cmp)
|
||||
b = mid
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// partitionCmpFunc does one quicksort partition.
|
||||
// Let p = data[pivot]
|
||||
// Moves elements in data[a:b] around, so that data[i]<p and data[j]>=p for i<newpivot and j>newpivot.
|
||||
// On return, data[newpivot] = p
|
||||
func partitionCmpFunc[E any](data []E, a, b, pivot int, cmp func(a, b E) int) (newpivot int, alreadyPartitioned bool) {
|
||||
data[a], data[pivot] = data[pivot], data[a]
|
||||
i, j := a+1, b-1 // i and j are inclusive of the elements remaining to be partitioned
|
||||
|
||||
for i <= j && (cmp(data[i], data[a]) < 0) {
|
||||
i++
|
||||
}
|
||||
for i <= j && !(cmp(data[j], data[a]) < 0) {
|
||||
j--
|
||||
}
|
||||
if i > j {
|
||||
data[j], data[a] = data[a], data[j]
|
||||
return j, true
|
||||
}
|
||||
data[i], data[j] = data[j], data[i]
|
||||
i++
|
||||
j--
|
||||
|
||||
for {
|
||||
for i <= j && (cmp(data[i], data[a]) < 0) {
|
||||
i++
|
||||
}
|
||||
for i <= j && !(cmp(data[j], data[a]) < 0) {
|
||||
j--
|
||||
}
|
||||
if i > j {
|
||||
break
|
||||
}
|
||||
data[i], data[j] = data[j], data[i]
|
||||
i++
|
||||
j--
|
||||
}
|
||||
data[j], data[a] = data[a], data[j]
|
||||
return j, false
|
||||
}
|
||||
|
||||
// partitionEqualCmpFunc partitions data[a:b] into elements equal to data[pivot] followed by elements greater than data[pivot].
|
||||
// It assumed that data[a:b] does not contain elements smaller than the data[pivot].
|
||||
func partitionEqualCmpFunc[E any](data []E, a, b, pivot int, cmp func(a, b E) int) (newpivot int) {
|
||||
data[a], data[pivot] = data[pivot], data[a]
|
||||
i, j := a+1, b-1 // i and j are inclusive of the elements remaining to be partitioned
|
||||
|
||||
for {
|
||||
for i <= j && !(cmp(data[a], data[i]) < 0) {
|
||||
i++
|
||||
}
|
||||
for i <= j && (cmp(data[a], data[j]) < 0) {
|
||||
j--
|
||||
}
|
||||
if i > j {
|
||||
break
|
||||
}
|
||||
data[i], data[j] = data[j], data[i]
|
||||
i++
|
||||
j--
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
// partialInsertionSortCmpFunc partially sorts a slice, returns true if the slice is sorted at the end.
|
||||
func partialInsertionSortCmpFunc[E any](data []E, a, b int, cmp func(a, b E) int) bool {
|
||||
const (
|
||||
maxSteps = 5 // maximum number of adjacent out-of-order pairs that will get shifted
|
||||
shortestShifting = 50 // don't shift any elements on short arrays
|
||||
)
|
||||
i := a + 1
|
||||
for j := 0; j < maxSteps; j++ {
|
||||
for i < b && !(cmp(data[i], data[i-1]) < 0) {
|
||||
i++
|
||||
}
|
||||
|
||||
if i == b {
|
||||
return true
|
||||
}
|
||||
|
||||
if b-a < shortestShifting {
|
||||
return false
|
||||
}
|
||||
|
||||
data[i], data[i-1] = data[i-1], data[i]
|
||||
|
||||
// Shift the smaller one to the left.
|
||||
if i-a >= 2 {
|
||||
for j := i - 1; j >= 1; j-- {
|
||||
if !(cmp(data[j], data[j-1]) < 0) {
|
||||
break
|
||||
}
|
||||
data[j], data[j-1] = data[j-1], data[j]
|
||||
}
|
||||
}
|
||||
// Shift the greater one to the right.
|
||||
if b-i >= 2 {
|
||||
for j := i + 1; j < b; j++ {
|
||||
if !(cmp(data[j], data[j-1]) < 0) {
|
||||
break
|
||||
}
|
||||
data[j], data[j-1] = data[j-1], data[j]
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// breakPatternsCmpFunc scatters some elements around in an attempt to break some patterns
|
||||
// that might cause imbalanced partitions in quicksort.
|
||||
func breakPatternsCmpFunc[E any](data []E, a, b int, cmp func(a, b E) int) {
|
||||
length := b - a
|
||||
if length >= 8 {
|
||||
random := xorshift(length)
|
||||
modulus := nextPowerOfTwo(length)
|
||||
|
||||
for idx := a + (length/4)*2 - 1; idx <= a+(length/4)*2+1; idx++ {
|
||||
other := int(uint(random.Next()) & (modulus - 1))
|
||||
if other >= length {
|
||||
other -= length
|
||||
}
|
||||
data[idx], data[a+other] = data[a+other], data[idx]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// choosePivotCmpFunc chooses a pivot in data[a:b].
|
||||
//
|
||||
// [0,8): chooses a static pivot.
|
||||
// [8,shortestNinther): uses the simple median-of-three method.
|
||||
// [shortestNinther,∞): uses the Tukey ninther method.
|
||||
func choosePivotCmpFunc[E any](data []E, a, b int, cmp func(a, b E) int) (pivot int, hint sortedHint) {
|
||||
const (
|
||||
shortestNinther = 50
|
||||
maxSwaps = 4 * 3
|
||||
)
|
||||
|
||||
l := b - a
|
||||
|
||||
var (
|
||||
swaps int
|
||||
i = a + l/4*1
|
||||
j = a + l/4*2
|
||||
k = a + l/4*3
|
||||
)
|
||||
|
||||
if l >= 8 {
|
||||
if l >= shortestNinther {
|
||||
// Tukey ninther method, the idea came from Rust's implementation.
|
||||
i = medianAdjacentCmpFunc(data, i, &swaps, cmp)
|
||||
j = medianAdjacentCmpFunc(data, j, &swaps, cmp)
|
||||
k = medianAdjacentCmpFunc(data, k, &swaps, cmp)
|
||||
}
|
||||
// Find the median among i, j, k and stores it into j.
|
||||
j = medianCmpFunc(data, i, j, k, &swaps, cmp)
|
||||
}
|
||||
|
||||
switch swaps {
|
||||
case 0:
|
||||
return j, increasingHint
|
||||
case maxSwaps:
|
||||
return j, decreasingHint
|
||||
default:
|
||||
return j, unknownHint
|
||||
}
|
||||
}
|
||||
|
||||
// order2CmpFunc returns x,y where data[x] <= data[y], where x,y=a,b or x,y=b,a.
|
||||
func order2CmpFunc[E any](data []E, a, b int, swaps *int, cmp func(a, b E) int) (int, int) {
|
||||
if cmp(data[b], data[a]) < 0 {
|
||||
*swaps++
|
||||
return b, a
|
||||
}
|
||||
return a, b
|
||||
}
|
||||
|
||||
// medianCmpFunc returns x where data[x] is the median of data[a],data[b],data[c], where x is a, b, or c.
|
||||
func medianCmpFunc[E any](data []E, a, b, c int, swaps *int, cmp func(a, b E) int) int {
|
||||
a, b = order2CmpFunc(data, a, b, swaps, cmp)
|
||||
b, c = order2CmpFunc(data, b, c, swaps, cmp)
|
||||
a, b = order2CmpFunc(data, a, b, swaps, cmp)
|
||||
return b
|
||||
}
|
||||
|
||||
// medianAdjacentCmpFunc finds the median of data[a - 1], data[a], data[a + 1] and stores the index into a.
|
||||
func medianAdjacentCmpFunc[E any](data []E, a int, swaps *int, cmp func(a, b E) int) int {
|
||||
return medianCmpFunc(data, a-1, a, a+1, swaps, cmp)
|
||||
}
|
||||
|
||||
func reverseRangeCmpFunc[E any](data []E, a, b int, cmp func(a, b E) int) {
|
||||
i := a
|
||||
j := b - 1
|
||||
for i < j {
|
||||
data[i], data[j] = data[j], data[i]
|
||||
i++
|
||||
j--
|
||||
}
|
||||
}
|
||||
|
||||
func swapRangeCmpFunc[E any](data []E, a, b, n int, cmp func(a, b E) int) {
|
||||
for i := 0; i < n; i++ {
|
||||
data[a+i], data[b+i] = data[b+i], data[a+i]
|
||||
}
|
||||
}
|
||||
|
||||
func stableCmpFunc[E any](data []E, n int, cmp func(a, b E) int) {
|
||||
blockSize := 20 // must be > 0
|
||||
a, b := 0, blockSize
|
||||
for b <= n {
|
||||
insertionSortCmpFunc(data, a, b, cmp)
|
||||
a = b
|
||||
b += blockSize
|
||||
}
|
||||
insertionSortCmpFunc(data, a, n, cmp)
|
||||
|
||||
for blockSize < n {
|
||||
a, b = 0, 2*blockSize
|
||||
for b <= n {
|
||||
symMergeCmpFunc(data, a, a+blockSize, b, cmp)
|
||||
a = b
|
||||
b += 2 * blockSize
|
||||
}
|
||||
if m := a + blockSize; m < n {
|
||||
symMergeCmpFunc(data, a, m, n, cmp)
|
||||
}
|
||||
blockSize *= 2
|
||||
}
|
||||
}
|
||||
|
||||
// symMergeCmpFunc merges the two sorted subsequences data[a:m] and data[m:b] using
|
||||
// the SymMerge algorithm from Pok-Son Kim and Arne Kutzner, "Stable Minimum
|
||||
// Storage Merging by Symmetric Comparisons", in Susanne Albers and Tomasz
|
||||
// Radzik, editors, Algorithms - ESA 2004, volume 3221 of Lecture Notes in
|
||||
// Computer Science, pages 714-723. Springer, 2004.
|
||||
//
|
||||
// Let M = m-a and N = b-n. Wolog M < N.
|
||||
// The recursion depth is bound by ceil(log(N+M)).
|
||||
// The algorithm needs O(M*log(N/M + 1)) calls to data.Less.
|
||||
// The algorithm needs O((M+N)*log(M)) calls to data.Swap.
|
||||
//
|
||||
// The paper gives O((M+N)*log(M)) as the number of assignments assuming a
|
||||
// rotation algorithm which uses O(M+N+gcd(M+N)) assignments. The argumentation
|
||||
// in the paper carries through for Swap operations, especially as the block
|
||||
// swapping rotate uses only O(M+N) Swaps.
|
||||
//
|
||||
// symMerge assumes non-degenerate arguments: a < m && m < b.
|
||||
// Having the caller check this condition eliminates many leaf recursion calls,
|
||||
// which improves performance.
|
||||
func symMergeCmpFunc[E any](data []E, a, m, b int, cmp func(a, b E) int) {
|
||||
// Avoid unnecessary recursions of symMerge
|
||||
// by direct insertion of data[a] into data[m:b]
|
||||
// if data[a:m] only contains one element.
|
||||
if m-a == 1 {
|
||||
// Use binary search to find the lowest index i
|
||||
// such that data[i] >= data[a] for m <= i < b.
|
||||
// Exit the search loop with i == b in case no such index exists.
|
||||
i := m
|
||||
j := b
|
||||
for i < j {
|
||||
h := int(uint(i+j) >> 1)
|
||||
if cmp(data[h], data[a]) < 0 {
|
||||
i = h + 1
|
||||
} else {
|
||||
j = h
|
||||
}
|
||||
}
|
||||
// Swap values until data[a] reaches the position before i.
|
||||
for k := a; k < i-1; k++ {
|
||||
data[k], data[k+1] = data[k+1], data[k]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Avoid unnecessary recursions of symMerge
|
||||
// by direct insertion of data[m] into data[a:m]
|
||||
// if data[m:b] only contains one element.
|
||||
if b-m == 1 {
|
||||
// Use binary search to find the lowest index i
|
||||
// such that data[i] > data[m] for a <= i < m.
|
||||
// Exit the search loop with i == m in case no such index exists.
|
||||
i := a
|
||||
j := m
|
||||
for i < j {
|
||||
h := int(uint(i+j) >> 1)
|
||||
if !(cmp(data[m], data[h]) < 0) {
|
||||
i = h + 1
|
||||
} else {
|
||||
j = h
|
||||
}
|
||||
}
|
||||
// Swap values until data[m] reaches the position i.
|
||||
for k := m; k > i; k-- {
|
||||
data[k], data[k-1] = data[k-1], data[k]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
mid := int(uint(a+b) >> 1)
|
||||
n := mid + m
|
||||
var start, r int
|
||||
if m > mid {
|
||||
start = n - b
|
||||
r = mid
|
||||
} else {
|
||||
start = a
|
||||
r = m
|
||||
}
|
||||
p := n - 1
|
||||
|
||||
for start < r {
|
||||
c := int(uint(start+r) >> 1)
|
||||
if !(cmp(data[p-c], data[c]) < 0) {
|
||||
start = c + 1
|
||||
} else {
|
||||
r = c
|
||||
}
|
||||
}
|
||||
|
||||
end := n - start
|
||||
if start < m && m < end {
|
||||
rotateCmpFunc(data, start, m, end, cmp)
|
||||
}
|
||||
if a < start && start < mid {
|
||||
symMergeCmpFunc(data, a, start, mid, cmp)
|
||||
}
|
||||
if mid < end && end < b {
|
||||
symMergeCmpFunc(data, mid, end, b, cmp)
|
||||
}
|
||||
}
|
||||
|
||||
// rotateCmpFunc rotates two consecutive blocks u = data[a:m] and v = data[m:b] in data:
|
||||
// Data of the form 'x u v y' is changed to 'x v u y'.
|
||||
// rotate performs at most b-a many calls to data.Swap,
|
||||
// and it assumes non-degenerate arguments: a < m && m < b.
|
||||
func rotateCmpFunc[E any](data []E, a, m, b int, cmp func(a, b E) int) {
|
||||
i := m - a
|
||||
j := b - m
|
||||
|
||||
for i != j {
|
||||
if i > j {
|
||||
swapRangeCmpFunc(data, m-i, m, j, cmp)
|
||||
i -= j
|
||||
} else {
|
||||
swapRangeCmpFunc(data, m-i, m+j-i, i, cmp)
|
||||
j -= i
|
||||
}
|
||||
}
|
||||
// i == j
|
||||
swapRangeCmpFunc(data, m-i, m, i, cmp)
|
||||
}
|
||||
481
vendor/golang.org/x/exp/slices/zsortordered.go
generated
vendored
481
vendor/golang.org/x/exp/slices/zsortordered.go
generated
vendored
|
|
@ -1,481 +0,0 @@
|
|||
// Code generated by gen_sort_variants.go; DO NOT EDIT.
|
||||
|
||||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package slices
|
||||
|
||||
import "golang.org/x/exp/constraints"
|
||||
|
||||
// insertionSortOrdered sorts data[a:b] using insertion sort.
|
||||
func insertionSortOrdered[E constraints.Ordered](data []E, a, b int) {
|
||||
for i := a + 1; i < b; i++ {
|
||||
for j := i; j > a && cmpLess(data[j], data[j-1]); j-- {
|
||||
data[j], data[j-1] = data[j-1], data[j]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// siftDownOrdered implements the heap property on data[lo:hi].
|
||||
// first is an offset into the array where the root of the heap lies.
|
||||
func siftDownOrdered[E constraints.Ordered](data []E, lo, hi, first int) {
|
||||
root := lo
|
||||
for {
|
||||
child := 2*root + 1
|
||||
if child >= hi {
|
||||
break
|
||||
}
|
||||
if child+1 < hi && cmpLess(data[first+child], data[first+child+1]) {
|
||||
child++
|
||||
}
|
||||
if !cmpLess(data[first+root], data[first+child]) {
|
||||
return
|
||||
}
|
||||
data[first+root], data[first+child] = data[first+child], data[first+root]
|
||||
root = child
|
||||
}
|
||||
}
|
||||
|
||||
func heapSortOrdered[E constraints.Ordered](data []E, a, b int) {
|
||||
first := a
|
||||
lo := 0
|
||||
hi := b - a
|
||||
|
||||
// Build heap with greatest element at top.
|
||||
for i := (hi - 1) / 2; i >= 0; i-- {
|
||||
siftDownOrdered(data, i, hi, first)
|
||||
}
|
||||
|
||||
// Pop elements, largest first, into end of data.
|
||||
for i := hi - 1; i >= 0; i-- {
|
||||
data[first], data[first+i] = data[first+i], data[first]
|
||||
siftDownOrdered(data, lo, i, first)
|
||||
}
|
||||
}
|
||||
|
||||
// pdqsortOrdered sorts data[a:b].
|
||||
// The algorithm based on pattern-defeating quicksort(pdqsort), but without the optimizations from BlockQuicksort.
|
||||
// pdqsort paper: https://arxiv.org/pdf/2106.05123.pdf
|
||||
// C++ implementation: https://github.com/orlp/pdqsort
|
||||
// Rust implementation: https://docs.rs/pdqsort/latest/pdqsort/
|
||||
// limit is the number of allowed bad (very unbalanced) pivots before falling back to heapsort.
|
||||
func pdqsortOrdered[E constraints.Ordered](data []E, a, b, limit int) {
|
||||
const maxInsertion = 12
|
||||
|
||||
var (
|
||||
wasBalanced = true // whether the last partitioning was reasonably balanced
|
||||
wasPartitioned = true // whether the slice was already partitioned
|
||||
)
|
||||
|
||||
for {
|
||||
length := b - a
|
||||
|
||||
if length <= maxInsertion {
|
||||
insertionSortOrdered(data, a, b)
|
||||
return
|
||||
}
|
||||
|
||||
// Fall back to heapsort if too many bad choices were made.
|
||||
if limit == 0 {
|
||||
heapSortOrdered(data, a, b)
|
||||
return
|
||||
}
|
||||
|
||||
// If the last partitioning was imbalanced, we need to breaking patterns.
|
||||
if !wasBalanced {
|
||||
breakPatternsOrdered(data, a, b)
|
||||
limit--
|
||||
}
|
||||
|
||||
pivot, hint := choosePivotOrdered(data, a, b)
|
||||
if hint == decreasingHint {
|
||||
reverseRangeOrdered(data, a, b)
|
||||
// The chosen pivot was pivot-a elements after the start of the array.
|
||||
// After reversing it is pivot-a elements before the end of the array.
|
||||
// The idea came from Rust's implementation.
|
||||
pivot = (b - 1) - (pivot - a)
|
||||
hint = increasingHint
|
||||
}
|
||||
|
||||
// The slice is likely already sorted.
|
||||
if wasBalanced && wasPartitioned && hint == increasingHint {
|
||||
if partialInsertionSortOrdered(data, a, b) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Probably the slice contains many duplicate elements, partition the slice into
|
||||
// elements equal to and elements greater than the pivot.
|
||||
if a > 0 && !cmpLess(data[a-1], data[pivot]) {
|
||||
mid := partitionEqualOrdered(data, a, b, pivot)
|
||||
a = mid
|
||||
continue
|
||||
}
|
||||
|
||||
mid, alreadyPartitioned := partitionOrdered(data, a, b, pivot)
|
||||
wasPartitioned = alreadyPartitioned
|
||||
|
||||
leftLen, rightLen := mid-a, b-mid
|
||||
balanceThreshold := length / 8
|
||||
if leftLen < rightLen {
|
||||
wasBalanced = leftLen >= balanceThreshold
|
||||
pdqsortOrdered(data, a, mid, limit)
|
||||
a = mid + 1
|
||||
} else {
|
||||
wasBalanced = rightLen >= balanceThreshold
|
||||
pdqsortOrdered(data, mid+1, b, limit)
|
||||
b = mid
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// partitionOrdered does one quicksort partition.
|
||||
// Let p = data[pivot]
|
||||
// Moves elements in data[a:b] around, so that data[i]<p and data[j]>=p for i<newpivot and j>newpivot.
|
||||
// On return, data[newpivot] = p
|
||||
func partitionOrdered[E constraints.Ordered](data []E, a, b, pivot int) (newpivot int, alreadyPartitioned bool) {
|
||||
data[a], data[pivot] = data[pivot], data[a]
|
||||
i, j := a+1, b-1 // i and j are inclusive of the elements remaining to be partitioned
|
||||
|
||||
for i <= j && cmpLess(data[i], data[a]) {
|
||||
i++
|
||||
}
|
||||
for i <= j && !cmpLess(data[j], data[a]) {
|
||||
j--
|
||||
}
|
||||
if i > j {
|
||||
data[j], data[a] = data[a], data[j]
|
||||
return j, true
|
||||
}
|
||||
data[i], data[j] = data[j], data[i]
|
||||
i++
|
||||
j--
|
||||
|
||||
for {
|
||||
for i <= j && cmpLess(data[i], data[a]) {
|
||||
i++
|
||||
}
|
||||
for i <= j && !cmpLess(data[j], data[a]) {
|
||||
j--
|
||||
}
|
||||
if i > j {
|
||||
break
|
||||
}
|
||||
data[i], data[j] = data[j], data[i]
|
||||
i++
|
||||
j--
|
||||
}
|
||||
data[j], data[a] = data[a], data[j]
|
||||
return j, false
|
||||
}
|
||||
|
||||
// partitionEqualOrdered partitions data[a:b] into elements equal to data[pivot] followed by elements greater than data[pivot].
|
||||
// It assumed that data[a:b] does not contain elements smaller than the data[pivot].
|
||||
func partitionEqualOrdered[E constraints.Ordered](data []E, a, b, pivot int) (newpivot int) {
|
||||
data[a], data[pivot] = data[pivot], data[a]
|
||||
i, j := a+1, b-1 // i and j are inclusive of the elements remaining to be partitioned
|
||||
|
||||
for {
|
||||
for i <= j && !cmpLess(data[a], data[i]) {
|
||||
i++
|
||||
}
|
||||
for i <= j && cmpLess(data[a], data[j]) {
|
||||
j--
|
||||
}
|
||||
if i > j {
|
||||
break
|
||||
}
|
||||
data[i], data[j] = data[j], data[i]
|
||||
i++
|
||||
j--
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
// partialInsertionSortOrdered partially sorts a slice, returns true if the slice is sorted at the end.
|
||||
func partialInsertionSortOrdered[E constraints.Ordered](data []E, a, b int) bool {
|
||||
const (
|
||||
maxSteps = 5 // maximum number of adjacent out-of-order pairs that will get shifted
|
||||
shortestShifting = 50 // don't shift any elements on short arrays
|
||||
)
|
||||
i := a + 1
|
||||
for j := 0; j < maxSteps; j++ {
|
||||
for i < b && !cmpLess(data[i], data[i-1]) {
|
||||
i++
|
||||
}
|
||||
|
||||
if i == b {
|
||||
return true
|
||||
}
|
||||
|
||||
if b-a < shortestShifting {
|
||||
return false
|
||||
}
|
||||
|
||||
data[i], data[i-1] = data[i-1], data[i]
|
||||
|
||||
// Shift the smaller one to the left.
|
||||
if i-a >= 2 {
|
||||
for j := i - 1; j >= 1; j-- {
|
||||
if !cmpLess(data[j], data[j-1]) {
|
||||
break
|
||||
}
|
||||
data[j], data[j-1] = data[j-1], data[j]
|
||||
}
|
||||
}
|
||||
// Shift the greater one to the right.
|
||||
if b-i >= 2 {
|
||||
for j := i + 1; j < b; j++ {
|
||||
if !cmpLess(data[j], data[j-1]) {
|
||||
break
|
||||
}
|
||||
data[j], data[j-1] = data[j-1], data[j]
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// breakPatternsOrdered scatters some elements around in an attempt to break some patterns
|
||||
// that might cause imbalanced partitions in quicksort.
|
||||
func breakPatternsOrdered[E constraints.Ordered](data []E, a, b int) {
|
||||
length := b - a
|
||||
if length >= 8 {
|
||||
random := xorshift(length)
|
||||
modulus := nextPowerOfTwo(length)
|
||||
|
||||
for idx := a + (length/4)*2 - 1; idx <= a+(length/4)*2+1; idx++ {
|
||||
other := int(uint(random.Next()) & (modulus - 1))
|
||||
if other >= length {
|
||||
other -= length
|
||||
}
|
||||
data[idx], data[a+other] = data[a+other], data[idx]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// choosePivotOrdered chooses a pivot in data[a:b].
|
||||
//
|
||||
// [0,8): chooses a static pivot.
|
||||
// [8,shortestNinther): uses the simple median-of-three method.
|
||||
// [shortestNinther,∞): uses the Tukey ninther method.
|
||||
func choosePivotOrdered[E constraints.Ordered](data []E, a, b int) (pivot int, hint sortedHint) {
|
||||
const (
|
||||
shortestNinther = 50
|
||||
maxSwaps = 4 * 3
|
||||
)
|
||||
|
||||
l := b - a
|
||||
|
||||
var (
|
||||
swaps int
|
||||
i = a + l/4*1
|
||||
j = a + l/4*2
|
||||
k = a + l/4*3
|
||||
)
|
||||
|
||||
if l >= 8 {
|
||||
if l >= shortestNinther {
|
||||
// Tukey ninther method, the idea came from Rust's implementation.
|
||||
i = medianAdjacentOrdered(data, i, &swaps)
|
||||
j = medianAdjacentOrdered(data, j, &swaps)
|
||||
k = medianAdjacentOrdered(data, k, &swaps)
|
||||
}
|
||||
// Find the median among i, j, k and stores it into j.
|
||||
j = medianOrdered(data, i, j, k, &swaps)
|
||||
}
|
||||
|
||||
switch swaps {
|
||||
case 0:
|
||||
return j, increasingHint
|
||||
case maxSwaps:
|
||||
return j, decreasingHint
|
||||
default:
|
||||
return j, unknownHint
|
||||
}
|
||||
}
|
||||
|
||||
// order2Ordered returns x,y where data[x] <= data[y], where x,y=a,b or x,y=b,a.
|
||||
func order2Ordered[E constraints.Ordered](data []E, a, b int, swaps *int) (int, int) {
|
||||
if cmpLess(data[b], data[a]) {
|
||||
*swaps++
|
||||
return b, a
|
||||
}
|
||||
return a, b
|
||||
}
|
||||
|
||||
// medianOrdered returns x where data[x] is the median of data[a],data[b],data[c], where x is a, b, or c.
|
||||
func medianOrdered[E constraints.Ordered](data []E, a, b, c int, swaps *int) int {
|
||||
a, b = order2Ordered(data, a, b, swaps)
|
||||
b, c = order2Ordered(data, b, c, swaps)
|
||||
a, b = order2Ordered(data, a, b, swaps)
|
||||
return b
|
||||
}
|
||||
|
||||
// medianAdjacentOrdered finds the median of data[a - 1], data[a], data[a + 1] and stores the index into a.
|
||||
func medianAdjacentOrdered[E constraints.Ordered](data []E, a int, swaps *int) int {
|
||||
return medianOrdered(data, a-1, a, a+1, swaps)
|
||||
}
|
||||
|
||||
func reverseRangeOrdered[E constraints.Ordered](data []E, a, b int) {
|
||||
i := a
|
||||
j := b - 1
|
||||
for i < j {
|
||||
data[i], data[j] = data[j], data[i]
|
||||
i++
|
||||
j--
|
||||
}
|
||||
}
|
||||
|
||||
func swapRangeOrdered[E constraints.Ordered](data []E, a, b, n int) {
|
||||
for i := 0; i < n; i++ {
|
||||
data[a+i], data[b+i] = data[b+i], data[a+i]
|
||||
}
|
||||
}
|
||||
|
||||
func stableOrdered[E constraints.Ordered](data []E, n int) {
|
||||
blockSize := 20 // must be > 0
|
||||
a, b := 0, blockSize
|
||||
for b <= n {
|
||||
insertionSortOrdered(data, a, b)
|
||||
a = b
|
||||
b += blockSize
|
||||
}
|
||||
insertionSortOrdered(data, a, n)
|
||||
|
||||
for blockSize < n {
|
||||
a, b = 0, 2*blockSize
|
||||
for b <= n {
|
||||
symMergeOrdered(data, a, a+blockSize, b)
|
||||
a = b
|
||||
b += 2 * blockSize
|
||||
}
|
||||
if m := a + blockSize; m < n {
|
||||
symMergeOrdered(data, a, m, n)
|
||||
}
|
||||
blockSize *= 2
|
||||
}
|
||||
}
|
||||
|
||||
// symMergeOrdered merges the two sorted subsequences data[a:m] and data[m:b] using
|
||||
// the SymMerge algorithm from Pok-Son Kim and Arne Kutzner, "Stable Minimum
|
||||
// Storage Merging by Symmetric Comparisons", in Susanne Albers and Tomasz
|
||||
// Radzik, editors, Algorithms - ESA 2004, volume 3221 of Lecture Notes in
|
||||
// Computer Science, pages 714-723. Springer, 2004.
|
||||
//
|
||||
// Let M = m-a and N = b-n. Wolog M < N.
|
||||
// The recursion depth is bound by ceil(log(N+M)).
|
||||
// The algorithm needs O(M*log(N/M + 1)) calls to data.Less.
|
||||
// The algorithm needs O((M+N)*log(M)) calls to data.Swap.
|
||||
//
|
||||
// The paper gives O((M+N)*log(M)) as the number of assignments assuming a
|
||||
// rotation algorithm which uses O(M+N+gcd(M+N)) assignments. The argumentation
|
||||
// in the paper carries through for Swap operations, especially as the block
|
||||
// swapping rotate uses only O(M+N) Swaps.
|
||||
//
|
||||
// symMerge assumes non-degenerate arguments: a < m && m < b.
|
||||
// Having the caller check this condition eliminates many leaf recursion calls,
|
||||
// which improves performance.
|
||||
func symMergeOrdered[E constraints.Ordered](data []E, a, m, b int) {
|
||||
// Avoid unnecessary recursions of symMerge
|
||||
// by direct insertion of data[a] into data[m:b]
|
||||
// if data[a:m] only contains one element.
|
||||
if m-a == 1 {
|
||||
// Use binary search to find the lowest index i
|
||||
// such that data[i] >= data[a] for m <= i < b.
|
||||
// Exit the search loop with i == b in case no such index exists.
|
||||
i := m
|
||||
j := b
|
||||
for i < j {
|
||||
h := int(uint(i+j) >> 1)
|
||||
if cmpLess(data[h], data[a]) {
|
||||
i = h + 1
|
||||
} else {
|
||||
j = h
|
||||
}
|
||||
}
|
||||
// Swap values until data[a] reaches the position before i.
|
||||
for k := a; k < i-1; k++ {
|
||||
data[k], data[k+1] = data[k+1], data[k]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Avoid unnecessary recursions of symMerge
|
||||
// by direct insertion of data[m] into data[a:m]
|
||||
// if data[m:b] only contains one element.
|
||||
if b-m == 1 {
|
||||
// Use binary search to find the lowest index i
|
||||
// such that data[i] > data[m] for a <= i < m.
|
||||
// Exit the search loop with i == m in case no such index exists.
|
||||
i := a
|
||||
j := m
|
||||
for i < j {
|
||||
h := int(uint(i+j) >> 1)
|
||||
if !cmpLess(data[m], data[h]) {
|
||||
i = h + 1
|
||||
} else {
|
||||
j = h
|
||||
}
|
||||
}
|
||||
// Swap values until data[m] reaches the position i.
|
||||
for k := m; k > i; k-- {
|
||||
data[k], data[k-1] = data[k-1], data[k]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
mid := int(uint(a+b) >> 1)
|
||||
n := mid + m
|
||||
var start, r int
|
||||
if m > mid {
|
||||
start = n - b
|
||||
r = mid
|
||||
} else {
|
||||
start = a
|
||||
r = m
|
||||
}
|
||||
p := n - 1
|
||||
|
||||
for start < r {
|
||||
c := int(uint(start+r) >> 1)
|
||||
if !cmpLess(data[p-c], data[c]) {
|
||||
start = c + 1
|
||||
} else {
|
||||
r = c
|
||||
}
|
||||
}
|
||||
|
||||
end := n - start
|
||||
if start < m && m < end {
|
||||
rotateOrdered(data, start, m, end)
|
||||
}
|
||||
if a < start && start < mid {
|
||||
symMergeOrdered(data, a, start, mid)
|
||||
}
|
||||
if mid < end && end < b {
|
||||
symMergeOrdered(data, mid, end, b)
|
||||
}
|
||||
}
|
||||
|
||||
// rotateOrdered rotates two consecutive blocks u = data[a:m] and v = data[m:b] in data:
|
||||
// Data of the form 'x u v y' is changed to 'x v u y'.
|
||||
// rotate performs at most b-a many calls to data.Swap,
|
||||
// and it assumes non-degenerate arguments: a < m && m < b.
|
||||
func rotateOrdered[E constraints.Ordered](data []E, a, m, b int) {
|
||||
i := m - a
|
||||
j := b - m
|
||||
|
||||
for i != j {
|
||||
if i > j {
|
||||
swapRangeOrdered(data, m-i, m, j)
|
||||
i -= j
|
||||
} else {
|
||||
swapRangeOrdered(data, m-i, m+j-i, i)
|
||||
j -= i
|
||||
}
|
||||
}
|
||||
// i == j
|
||||
swapRangeOrdered(data, m-i, m, i)
|
||||
}
|
||||
18
vendor/golang.org/x/exp/slog/handler.go
generated
vendored
18
vendor/golang.org/x/exp/slog/handler.go
generated
vendored
|
|
@ -8,6 +8,7 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
|
@ -504,6 +505,23 @@ func (s *handleState) appendString(str string) {
|
|||
}
|
||||
|
||||
func (s *handleState) appendValue(v Value) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
// If it panics with a nil pointer, the most likely cases are
|
||||
// an encoding.TextMarshaler or error fails to guard against nil,
|
||||
// in which case "<nil>" seems to be the feasible choice.
|
||||
//
|
||||
// Adapted from the code in fmt/print.go.
|
||||
if v := reflect.ValueOf(v.any); v.Kind() == reflect.Pointer && v.IsNil() {
|
||||
s.appendString("<nil>")
|
||||
return
|
||||
}
|
||||
|
||||
// Otherwise just print the original panic message.
|
||||
s.appendString(fmt.Sprintf("!PANIC: %v", r))
|
||||
}
|
||||
}()
|
||||
|
||||
var err error
|
||||
if s.h.json {
|
||||
err = appendJSONValue(s, v)
|
||||
|
|
|
|||
4
vendor/golang.org/x/sys/LICENSE
generated
vendored
4
vendor/golang.org/x/sys/LICENSE
generated
vendored
|
|
@ -1,4 +1,4 @@
|
|||
Copyright (c) 2009 The Go Authors. All rights reserved.
|
||||
Copyright 2009 The Go Authors.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
|
|
@ -10,7 +10,7 @@ notice, this list of conditions and the following disclaimer.
|
|||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
* Neither the name of Google LLC nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
|
|
|
|||
2
vendor/golang.org/x/sys/unix/README.md
generated
vendored
2
vendor/golang.org/x/sys/unix/README.md
generated
vendored
|
|
@ -156,7 +156,7 @@ from the generated architecture-specific files listed below, and merge these
|
|||
into a common file for each OS.
|
||||
|
||||
The merge is performed in the following steps:
|
||||
1. Construct the set of common code that is idential in all architecture-specific files.
|
||||
1. Construct the set of common code that is identical in all architecture-specific files.
|
||||
2. Write this common code to the merged file.
|
||||
3. Remove the common code from all architecture-specific files.
|
||||
|
||||
|
|
|
|||
675
vendor/golang.org/x/sys/unix/asm_zos_s390x.s
generated
vendored
675
vendor/golang.org/x/sys/unix/asm_zos_s390x.s
generated
vendored
|
|
@ -9,9 +9,11 @@
|
|||
#define PSALAA 1208(R0)
|
||||
#define GTAB64(x) 80(x)
|
||||
#define LCA64(x) 88(x)
|
||||
#define SAVSTACK_ASYNC(x) 336(x) // in the LCA
|
||||
#define CAA(x) 8(x)
|
||||
#define EDCHPXV(x) 1016(x) // in the CAA
|
||||
#define SAVSTACK_ASYNC(x) 336(x) // in the LCA
|
||||
#define CEECAATHDID(x) 976(x) // in the CAA
|
||||
#define EDCHPXV(x) 1016(x) // in the CAA
|
||||
#define GOCB(x) 1104(x) // in the CAA
|
||||
|
||||
// SS_*, where x=SAVSTACK_ASYNC
|
||||
#define SS_LE(x) 0(x)
|
||||
|
|
@ -19,394 +21,125 @@
|
|||
#define SS_ERRNO(x) 16(x)
|
||||
#define SS_ERRNOJR(x) 20(x)
|
||||
|
||||
#define LE_CALL BYTE $0x0D; BYTE $0x76; // BL R7, R6
|
||||
// Function Descriptor Offsets
|
||||
#define __errno 0x156*16
|
||||
#define __err2ad 0x16C*16
|
||||
|
||||
TEXT ·clearErrno(SB),NOSPLIT,$0-0
|
||||
BL addrerrno<>(SB)
|
||||
MOVD $0, 0(R3)
|
||||
// Call Instructions
|
||||
#define LE_CALL BYTE $0x0D; BYTE $0x76 // BL R7, R6
|
||||
#define SVC_LOAD BYTE $0x0A; BYTE $0x08 // SVC 08 LOAD
|
||||
#define SVC_DELETE BYTE $0x0A; BYTE $0x09 // SVC 09 DELETE
|
||||
|
||||
DATA zosLibVec<>(SB)/8, $0
|
||||
GLOBL zosLibVec<>(SB), NOPTR, $8
|
||||
|
||||
TEXT ·initZosLibVec(SB), NOSPLIT|NOFRAME, $0-0
|
||||
MOVW PSALAA, R8
|
||||
MOVD LCA64(R8), R8
|
||||
MOVD CAA(R8), R8
|
||||
MOVD EDCHPXV(R8), R8
|
||||
MOVD R8, zosLibVec<>(SB)
|
||||
RET
|
||||
|
||||
TEXT ·GetZosLibVec(SB), NOSPLIT|NOFRAME, $0-0
|
||||
MOVD zosLibVec<>(SB), R8
|
||||
MOVD R8, ret+0(FP)
|
||||
RET
|
||||
|
||||
TEXT ·clearErrno(SB), NOSPLIT, $0-0
|
||||
BL addrerrno<>(SB)
|
||||
MOVD $0, 0(R3)
|
||||
RET
|
||||
|
||||
// Returns the address of errno in R3.
|
||||
TEXT addrerrno<>(SB),NOSPLIT|NOFRAME,$0-0
|
||||
TEXT addrerrno<>(SB), NOSPLIT|NOFRAME, $0-0
|
||||
// Get library control area (LCA).
|
||||
MOVW PSALAA, R8
|
||||
MOVD LCA64(R8), R8
|
||||
MOVW PSALAA, R8
|
||||
MOVD LCA64(R8), R8
|
||||
|
||||
// Get __errno FuncDesc.
|
||||
MOVD CAA(R8), R9
|
||||
MOVD EDCHPXV(R9), R9
|
||||
ADD $(0x156*16), R9
|
||||
LMG 0(R9), R5, R6
|
||||
MOVD CAA(R8), R9
|
||||
MOVD EDCHPXV(R9), R9
|
||||
ADD $(__errno), R9
|
||||
LMG 0(R9), R5, R6
|
||||
|
||||
// Switch to saved LE stack.
|
||||
MOVD SAVSTACK_ASYNC(R8), R9
|
||||
MOVD 0(R9), R4
|
||||
MOVD $0, 0(R9)
|
||||
MOVD SAVSTACK_ASYNC(R8), R9
|
||||
MOVD 0(R9), R4
|
||||
MOVD $0, 0(R9)
|
||||
|
||||
// Call __errno function.
|
||||
LE_CALL
|
||||
NOPH
|
||||
|
||||
// Switch back to Go stack.
|
||||
XOR R0, R0 // Restore R0 to $0.
|
||||
MOVD R4, 0(R9) // Save stack pointer.
|
||||
RET
|
||||
|
||||
TEXT ·syscall_syscall(SB),NOSPLIT,$0-56
|
||||
BL runtime·entersyscall(SB)
|
||||
MOVD a1+8(FP), R1
|
||||
MOVD a2+16(FP), R2
|
||||
MOVD a3+24(FP), R3
|
||||
|
||||
// Get library control area (LCA).
|
||||
MOVW PSALAA, R8
|
||||
MOVD LCA64(R8), R8
|
||||
|
||||
// Get function.
|
||||
MOVD CAA(R8), R9
|
||||
MOVD EDCHPXV(R9), R9
|
||||
MOVD trap+0(FP), R5
|
||||
SLD $4, R5
|
||||
ADD R5, R9
|
||||
LMG 0(R9), R5, R6
|
||||
|
||||
// Restore LE stack.
|
||||
MOVD SAVSTACK_ASYNC(R8), R9
|
||||
MOVD 0(R9), R4
|
||||
MOVD $0, 0(R9)
|
||||
|
||||
// Call function.
|
||||
LE_CALL
|
||||
NOPH
|
||||
XOR R0, R0 // Restore R0 to $0.
|
||||
MOVD R4, 0(R9) // Save stack pointer.
|
||||
|
||||
MOVD R3, r1+32(FP)
|
||||
MOVD R0, r2+40(FP)
|
||||
MOVD R0, err+48(FP)
|
||||
MOVW R3, R4
|
||||
CMP R4, $-1
|
||||
BNE done
|
||||
BL addrerrno<>(SB)
|
||||
MOVWZ 0(R3), R3
|
||||
MOVD R3, err+48(FP)
|
||||
done:
|
||||
BL runtime·exitsyscall(SB)
|
||||
RET
|
||||
|
||||
TEXT ·syscall_rawsyscall(SB),NOSPLIT,$0-56
|
||||
MOVD a1+8(FP), R1
|
||||
MOVD a2+16(FP), R2
|
||||
MOVD a3+24(FP), R3
|
||||
|
||||
// Get library control area (LCA).
|
||||
MOVW PSALAA, R8
|
||||
MOVD LCA64(R8), R8
|
||||
|
||||
// Get function.
|
||||
MOVD CAA(R8), R9
|
||||
MOVD EDCHPXV(R9), R9
|
||||
MOVD trap+0(FP), R5
|
||||
SLD $4, R5
|
||||
ADD R5, R9
|
||||
LMG 0(R9), R5, R6
|
||||
|
||||
// Restore LE stack.
|
||||
MOVD SAVSTACK_ASYNC(R8), R9
|
||||
MOVD 0(R9), R4
|
||||
MOVD $0, 0(R9)
|
||||
|
||||
// Call function.
|
||||
LE_CALL
|
||||
NOPH
|
||||
XOR R0, R0 // Restore R0 to $0.
|
||||
MOVD R4, 0(R9) // Save stack pointer.
|
||||
|
||||
MOVD R3, r1+32(FP)
|
||||
MOVD R0, r2+40(FP)
|
||||
MOVD R0, err+48(FP)
|
||||
MOVW R3, R4
|
||||
CMP R4, $-1
|
||||
BNE done
|
||||
BL addrerrno<>(SB)
|
||||
MOVWZ 0(R3), R3
|
||||
MOVD R3, err+48(FP)
|
||||
done:
|
||||
RET
|
||||
|
||||
TEXT ·syscall_syscall6(SB),NOSPLIT,$0-80
|
||||
BL runtime·entersyscall(SB)
|
||||
MOVD a1+8(FP), R1
|
||||
MOVD a2+16(FP), R2
|
||||
MOVD a3+24(FP), R3
|
||||
|
||||
// Get library control area (LCA).
|
||||
MOVW PSALAA, R8
|
||||
MOVD LCA64(R8), R8
|
||||
|
||||
// Get function.
|
||||
MOVD CAA(R8), R9
|
||||
MOVD EDCHPXV(R9), R9
|
||||
MOVD trap+0(FP), R5
|
||||
SLD $4, R5
|
||||
ADD R5, R9
|
||||
LMG 0(R9), R5, R6
|
||||
|
||||
// Restore LE stack.
|
||||
MOVD SAVSTACK_ASYNC(R8), R9
|
||||
MOVD 0(R9), R4
|
||||
MOVD $0, 0(R9)
|
||||
|
||||
// Fill in parameter list.
|
||||
MOVD a4+32(FP), R12
|
||||
MOVD R12, (2176+24)(R4)
|
||||
MOVD a5+40(FP), R12
|
||||
MOVD R12, (2176+32)(R4)
|
||||
MOVD a6+48(FP), R12
|
||||
MOVD R12, (2176+40)(R4)
|
||||
|
||||
// Call function.
|
||||
LE_CALL
|
||||
NOPH
|
||||
XOR R0, R0 // Restore R0 to $0.
|
||||
MOVD R4, 0(R9) // Save stack pointer.
|
||||
|
||||
MOVD R3, r1+56(FP)
|
||||
MOVD R0, r2+64(FP)
|
||||
MOVD R0, err+72(FP)
|
||||
MOVW R3, R4
|
||||
CMP R4, $-1
|
||||
BNE done
|
||||
BL addrerrno<>(SB)
|
||||
MOVWZ 0(R3), R3
|
||||
MOVD R3, err+72(FP)
|
||||
done:
|
||||
BL runtime·exitsyscall(SB)
|
||||
RET
|
||||
|
||||
TEXT ·syscall_rawsyscall6(SB),NOSPLIT,$0-80
|
||||
MOVD a1+8(FP), R1
|
||||
MOVD a2+16(FP), R2
|
||||
MOVD a3+24(FP), R3
|
||||
|
||||
// Get library control area (LCA).
|
||||
MOVW PSALAA, R8
|
||||
MOVD LCA64(R8), R8
|
||||
|
||||
// Get function.
|
||||
MOVD CAA(R8), R9
|
||||
MOVD EDCHPXV(R9), R9
|
||||
MOVD trap+0(FP), R5
|
||||
SLD $4, R5
|
||||
ADD R5, R9
|
||||
LMG 0(R9), R5, R6
|
||||
|
||||
// Restore LE stack.
|
||||
MOVD SAVSTACK_ASYNC(R8), R9
|
||||
MOVD 0(R9), R4
|
||||
MOVD $0, 0(R9)
|
||||
|
||||
// Fill in parameter list.
|
||||
MOVD a4+32(FP), R12
|
||||
MOVD R12, (2176+24)(R4)
|
||||
MOVD a5+40(FP), R12
|
||||
MOVD R12, (2176+32)(R4)
|
||||
MOVD a6+48(FP), R12
|
||||
MOVD R12, (2176+40)(R4)
|
||||
|
||||
// Call function.
|
||||
LE_CALL
|
||||
NOPH
|
||||
XOR R0, R0 // Restore R0 to $0.
|
||||
MOVD R4, 0(R9) // Save stack pointer.
|
||||
|
||||
MOVD R3, r1+56(FP)
|
||||
MOVD R0, r2+64(FP)
|
||||
MOVD R0, err+72(FP)
|
||||
MOVW R3, R4
|
||||
CMP R4, $-1
|
||||
BNE done
|
||||
BL ·rrno<>(SB)
|
||||
MOVWZ 0(R3), R3
|
||||
MOVD R3, err+72(FP)
|
||||
done:
|
||||
RET
|
||||
|
||||
TEXT ·syscall_syscall9(SB),NOSPLIT,$0
|
||||
BL runtime·entersyscall(SB)
|
||||
MOVD a1+8(FP), R1
|
||||
MOVD a2+16(FP), R2
|
||||
MOVD a3+24(FP), R3
|
||||
|
||||
// Get library control area (LCA).
|
||||
MOVW PSALAA, R8
|
||||
MOVD LCA64(R8), R8
|
||||
|
||||
// Get function.
|
||||
MOVD CAA(R8), R9
|
||||
MOVD EDCHPXV(R9), R9
|
||||
MOVD trap+0(FP), R5
|
||||
SLD $4, R5
|
||||
ADD R5, R9
|
||||
LMG 0(R9), R5, R6
|
||||
|
||||
// Restore LE stack.
|
||||
MOVD SAVSTACK_ASYNC(R8), R9
|
||||
MOVD 0(R9), R4
|
||||
MOVD $0, 0(R9)
|
||||
|
||||
// Fill in parameter list.
|
||||
MOVD a4+32(FP), R12
|
||||
MOVD R12, (2176+24)(R4)
|
||||
MOVD a5+40(FP), R12
|
||||
MOVD R12, (2176+32)(R4)
|
||||
MOVD a6+48(FP), R12
|
||||
MOVD R12, (2176+40)(R4)
|
||||
MOVD a7+56(FP), R12
|
||||
MOVD R12, (2176+48)(R4)
|
||||
MOVD a8+64(FP), R12
|
||||
MOVD R12, (2176+56)(R4)
|
||||
MOVD a9+72(FP), R12
|
||||
MOVD R12, (2176+64)(R4)
|
||||
|
||||
// Call function.
|
||||
LE_CALL
|
||||
NOPH
|
||||
XOR R0, R0 // Restore R0 to $0.
|
||||
MOVD R4, 0(R9) // Save stack pointer.
|
||||
|
||||
MOVD R3, r1+80(FP)
|
||||
MOVD R0, r2+88(FP)
|
||||
MOVD R0, err+96(FP)
|
||||
MOVW R3, R4
|
||||
CMP R4, $-1
|
||||
BNE done
|
||||
BL addrerrno<>(SB)
|
||||
MOVWZ 0(R3), R3
|
||||
MOVD R3, err+96(FP)
|
||||
done:
|
||||
BL runtime·exitsyscall(SB)
|
||||
RET
|
||||
|
||||
TEXT ·syscall_rawsyscall9(SB),NOSPLIT,$0
|
||||
MOVD a1+8(FP), R1
|
||||
MOVD a2+16(FP), R2
|
||||
MOVD a3+24(FP), R3
|
||||
|
||||
// Get library control area (LCA).
|
||||
MOVW PSALAA, R8
|
||||
MOVD LCA64(R8), R8
|
||||
|
||||
// Get function.
|
||||
MOVD CAA(R8), R9
|
||||
MOVD EDCHPXV(R9), R9
|
||||
MOVD trap+0(FP), R5
|
||||
SLD $4, R5
|
||||
ADD R5, R9
|
||||
LMG 0(R9), R5, R6
|
||||
|
||||
// Restore LE stack.
|
||||
MOVD SAVSTACK_ASYNC(R8), R9
|
||||
MOVD 0(R9), R4
|
||||
MOVD $0, 0(R9)
|
||||
|
||||
// Fill in parameter list.
|
||||
MOVD a4+32(FP), R12
|
||||
MOVD R12, (2176+24)(R4)
|
||||
MOVD a5+40(FP), R12
|
||||
MOVD R12, (2176+32)(R4)
|
||||
MOVD a6+48(FP), R12
|
||||
MOVD R12, (2176+40)(R4)
|
||||
MOVD a7+56(FP), R12
|
||||
MOVD R12, (2176+48)(R4)
|
||||
MOVD a8+64(FP), R12
|
||||
MOVD R12, (2176+56)(R4)
|
||||
MOVD a9+72(FP), R12
|
||||
MOVD R12, (2176+64)(R4)
|
||||
|
||||
// Call function.
|
||||
LE_CALL
|
||||
NOPH
|
||||
XOR R0, R0 // Restore R0 to $0.
|
||||
MOVD R4, 0(R9) // Save stack pointer.
|
||||
|
||||
MOVD R3, r1+80(FP)
|
||||
MOVD R0, r2+88(FP)
|
||||
MOVD R0, err+96(FP)
|
||||
MOVW R3, R4
|
||||
CMP R4, $-1
|
||||
BNE done
|
||||
BL addrerrno<>(SB)
|
||||
MOVWZ 0(R3), R3
|
||||
MOVD R3, err+96(FP)
|
||||
done:
|
||||
XOR R0, R0 // Restore R0 to $0.
|
||||
MOVD R4, 0(R9) // Save stack pointer.
|
||||
RET
|
||||
|
||||
// func svcCall(fnptr unsafe.Pointer, argv *unsafe.Pointer, dsa *uint64)
|
||||
TEXT ·svcCall(SB),NOSPLIT,$0
|
||||
BL runtime·save_g(SB) // Save g and stack pointer
|
||||
MOVW PSALAA, R8
|
||||
MOVD LCA64(R8), R8
|
||||
MOVD SAVSTACK_ASYNC(R8), R9
|
||||
MOVD R15, 0(R9)
|
||||
TEXT ·svcCall(SB), NOSPLIT, $0
|
||||
BL runtime·save_g(SB) // Save g and stack pointer
|
||||
MOVW PSALAA, R8
|
||||
MOVD LCA64(R8), R8
|
||||
MOVD SAVSTACK_ASYNC(R8), R9
|
||||
MOVD R15, 0(R9)
|
||||
|
||||
MOVD argv+8(FP), R1 // Move function arguments into registers
|
||||
MOVD dsa+16(FP), g
|
||||
MOVD fnptr+0(FP), R15
|
||||
MOVD argv+8(FP), R1 // Move function arguments into registers
|
||||
MOVD dsa+16(FP), g
|
||||
MOVD fnptr+0(FP), R15
|
||||
|
||||
BYTE $0x0D // Branch to function
|
||||
BYTE $0xEF
|
||||
BYTE $0x0D // Branch to function
|
||||
BYTE $0xEF
|
||||
|
||||
BL runtime·load_g(SB) // Restore g and stack pointer
|
||||
MOVW PSALAA, R8
|
||||
MOVD LCA64(R8), R8
|
||||
MOVD SAVSTACK_ASYNC(R8), R9
|
||||
MOVD 0(R9), R15
|
||||
BL runtime·load_g(SB) // Restore g and stack pointer
|
||||
MOVW PSALAA, R8
|
||||
MOVD LCA64(R8), R8
|
||||
MOVD SAVSTACK_ASYNC(R8), R9
|
||||
MOVD 0(R9), R15
|
||||
|
||||
RET
|
||||
|
||||
// func svcLoad(name *byte) unsafe.Pointer
|
||||
TEXT ·svcLoad(SB),NOSPLIT,$0
|
||||
MOVD R15, R2 // Save go stack pointer
|
||||
MOVD name+0(FP), R0 // Move SVC args into registers
|
||||
MOVD $0x80000000, R1
|
||||
MOVD $0, R15
|
||||
BYTE $0x0A // SVC 08 LOAD
|
||||
BYTE $0x08
|
||||
MOVW R15, R3 // Save return code from SVC
|
||||
MOVD R2, R15 // Restore go stack pointer
|
||||
CMP R3, $0 // Check SVC return code
|
||||
BNE error
|
||||
TEXT ·svcLoad(SB), NOSPLIT, $0
|
||||
MOVD R15, R2 // Save go stack pointer
|
||||
MOVD name+0(FP), R0 // Move SVC args into registers
|
||||
MOVD $0x80000000, R1
|
||||
MOVD $0, R15
|
||||
SVC_LOAD
|
||||
MOVW R15, R3 // Save return code from SVC
|
||||
MOVD R2, R15 // Restore go stack pointer
|
||||
CMP R3, $0 // Check SVC return code
|
||||
BNE error
|
||||
|
||||
MOVD $-2, R3 // Reset last bit of entry point to zero
|
||||
AND R0, R3
|
||||
MOVD R3, addr+8(FP) // Return entry point returned by SVC
|
||||
CMP R0, R3 // Check if last bit of entry point was set
|
||||
BNE done
|
||||
MOVD $-2, R3 // Reset last bit of entry point to zero
|
||||
AND R0, R3
|
||||
MOVD R3, ret+8(FP) // Return entry point returned by SVC
|
||||
CMP R0, R3 // Check if last bit of entry point was set
|
||||
BNE done
|
||||
|
||||
MOVD R15, R2 // Save go stack pointer
|
||||
MOVD $0, R15 // Move SVC args into registers (entry point still in r0 from SVC 08)
|
||||
BYTE $0x0A // SVC 09 DELETE
|
||||
BYTE $0x09
|
||||
MOVD R2, R15 // Restore go stack pointer
|
||||
MOVD R15, R2 // Save go stack pointer
|
||||
MOVD $0, R15 // Move SVC args into registers (entry point still in r0 from SVC 08)
|
||||
SVC_DELETE
|
||||
MOVD R2, R15 // Restore go stack pointer
|
||||
|
||||
error:
|
||||
MOVD $0, addr+8(FP) // Return 0 on failure
|
||||
MOVD $0, ret+8(FP) // Return 0 on failure
|
||||
|
||||
done:
|
||||
XOR R0, R0 // Reset r0 to 0
|
||||
XOR R0, R0 // Reset r0 to 0
|
||||
RET
|
||||
|
||||
// func svcUnload(name *byte, fnptr unsafe.Pointer) int64
|
||||
TEXT ·svcUnload(SB),NOSPLIT,$0
|
||||
MOVD R15, R2 // Save go stack pointer
|
||||
MOVD name+0(FP), R0 // Move SVC args into registers
|
||||
MOVD addr+8(FP), R15
|
||||
BYTE $0x0A // SVC 09
|
||||
BYTE $0x09
|
||||
XOR R0, R0 // Reset r0 to 0
|
||||
MOVD R15, R1 // Save SVC return code
|
||||
MOVD R2, R15 // Restore go stack pointer
|
||||
MOVD R1, rc+0(FP) // Return SVC return code
|
||||
TEXT ·svcUnload(SB), NOSPLIT, $0
|
||||
MOVD R15, R2 // Save go stack pointer
|
||||
MOVD name+0(FP), R0 // Move SVC args into registers
|
||||
MOVD fnptr+8(FP), R15
|
||||
SVC_DELETE
|
||||
XOR R0, R0 // Reset r0 to 0
|
||||
MOVD R15, R1 // Save SVC return code
|
||||
MOVD R2, R15 // Restore go stack pointer
|
||||
MOVD R1, ret+16(FP) // Return SVC return code
|
||||
RET
|
||||
|
||||
// func gettid() uint64
|
||||
|
|
@ -417,7 +150,233 @@ TEXT ·gettid(SB), NOSPLIT, $0
|
|||
|
||||
// Get CEECAATHDID
|
||||
MOVD CAA(R8), R9
|
||||
MOVD 0x3D0(R9), R9
|
||||
MOVD CEECAATHDID(R9), R9
|
||||
MOVD R9, ret+0(FP)
|
||||
|
||||
RET
|
||||
|
||||
//
|
||||
// Call LE function, if the return is -1
|
||||
// errno and errno2 is retrieved
|
||||
//
|
||||
TEXT ·CallLeFuncWithErr(SB), NOSPLIT, $0
|
||||
MOVW PSALAA, R8
|
||||
MOVD LCA64(R8), R8
|
||||
MOVD CAA(R8), R9
|
||||
MOVD g, GOCB(R9)
|
||||
|
||||
// Restore LE stack.
|
||||
MOVD SAVSTACK_ASYNC(R8), R9 // R9-> LE stack frame saving address
|
||||
MOVD 0(R9), R4 // R4-> restore previously saved stack frame pointer
|
||||
|
||||
MOVD parms_base+8(FP), R7 // R7 -> argument array
|
||||
MOVD parms_len+16(FP), R8 // R8 number of arguments
|
||||
|
||||
// arg 1 ---> R1
|
||||
CMP R8, $0
|
||||
BEQ docall
|
||||
SUB $1, R8
|
||||
MOVD 0(R7), R1
|
||||
|
||||
// arg 2 ---> R2
|
||||
CMP R8, $0
|
||||
BEQ docall
|
||||
SUB $1, R8
|
||||
ADD $8, R7
|
||||
MOVD 0(R7), R2
|
||||
|
||||
// arg 3 --> R3
|
||||
CMP R8, $0
|
||||
BEQ docall
|
||||
SUB $1, R8
|
||||
ADD $8, R7
|
||||
MOVD 0(R7), R3
|
||||
|
||||
CMP R8, $0
|
||||
BEQ docall
|
||||
MOVD $2176+16, R6 // starting LE stack address-8 to store 4th argument
|
||||
|
||||
repeat:
|
||||
ADD $8, R7
|
||||
MOVD 0(R7), R0 // advance arg pointer by 8 byte
|
||||
ADD $8, R6 // advance LE argument address by 8 byte
|
||||
MOVD R0, (R4)(R6*1) // copy argument from go-slice to le-frame
|
||||
SUB $1, R8
|
||||
CMP R8, $0
|
||||
BNE repeat
|
||||
|
||||
docall:
|
||||
MOVD funcdesc+0(FP), R8 // R8-> function descriptor
|
||||
LMG 0(R8), R5, R6
|
||||
MOVD $0, 0(R9) // R9 address of SAVSTACK_ASYNC
|
||||
LE_CALL // balr R7, R6 (return #1)
|
||||
NOPH
|
||||
MOVD R3, ret+32(FP)
|
||||
CMP R3, $-1 // compare result to -1
|
||||
BNE done
|
||||
|
||||
// retrieve errno and errno2
|
||||
MOVD zosLibVec<>(SB), R8
|
||||
ADD $(__errno), R8
|
||||
LMG 0(R8), R5, R6
|
||||
LE_CALL // balr R7, R6 __errno (return #3)
|
||||
NOPH
|
||||
MOVWZ 0(R3), R3
|
||||
MOVD R3, err+48(FP)
|
||||
MOVD zosLibVec<>(SB), R8
|
||||
ADD $(__err2ad), R8
|
||||
LMG 0(R8), R5, R6
|
||||
LE_CALL // balr R7, R6 __err2ad (return #2)
|
||||
NOPH
|
||||
MOVW (R3), R2 // retrieve errno2
|
||||
MOVD R2, errno2+40(FP) // store in return area
|
||||
|
||||
done:
|
||||
MOVD R4, 0(R9) // Save stack pointer.
|
||||
RET
|
||||
|
||||
//
|
||||
// Call LE function, if the return is 0
|
||||
// errno and errno2 is retrieved
|
||||
//
|
||||
TEXT ·CallLeFuncWithPtrReturn(SB), NOSPLIT, $0
|
||||
MOVW PSALAA, R8
|
||||
MOVD LCA64(R8), R8
|
||||
MOVD CAA(R8), R9
|
||||
MOVD g, GOCB(R9)
|
||||
|
||||
// Restore LE stack.
|
||||
MOVD SAVSTACK_ASYNC(R8), R9 // R9-> LE stack frame saving address
|
||||
MOVD 0(R9), R4 // R4-> restore previously saved stack frame pointer
|
||||
|
||||
MOVD parms_base+8(FP), R7 // R7 -> argument array
|
||||
MOVD parms_len+16(FP), R8 // R8 number of arguments
|
||||
|
||||
// arg 1 ---> R1
|
||||
CMP R8, $0
|
||||
BEQ docall
|
||||
SUB $1, R8
|
||||
MOVD 0(R7), R1
|
||||
|
||||
// arg 2 ---> R2
|
||||
CMP R8, $0
|
||||
BEQ docall
|
||||
SUB $1, R8
|
||||
ADD $8, R7
|
||||
MOVD 0(R7), R2
|
||||
|
||||
// arg 3 --> R3
|
||||
CMP R8, $0
|
||||
BEQ docall
|
||||
SUB $1, R8
|
||||
ADD $8, R7
|
||||
MOVD 0(R7), R3
|
||||
|
||||
CMP R8, $0
|
||||
BEQ docall
|
||||
MOVD $2176+16, R6 // starting LE stack address-8 to store 4th argument
|
||||
|
||||
repeat:
|
||||
ADD $8, R7
|
||||
MOVD 0(R7), R0 // advance arg pointer by 8 byte
|
||||
ADD $8, R6 // advance LE argument address by 8 byte
|
||||
MOVD R0, (R4)(R6*1) // copy argument from go-slice to le-frame
|
||||
SUB $1, R8
|
||||
CMP R8, $0
|
||||
BNE repeat
|
||||
|
||||
docall:
|
||||
MOVD funcdesc+0(FP), R8 // R8-> function descriptor
|
||||
LMG 0(R8), R5, R6
|
||||
MOVD $0, 0(R9) // R9 address of SAVSTACK_ASYNC
|
||||
LE_CALL // balr R7, R6 (return #1)
|
||||
NOPH
|
||||
MOVD R3, ret+32(FP)
|
||||
CMP R3, $0 // compare result to 0
|
||||
BNE done
|
||||
|
||||
// retrieve errno and errno2
|
||||
MOVD zosLibVec<>(SB), R8
|
||||
ADD $(__errno), R8
|
||||
LMG 0(R8), R5, R6
|
||||
LE_CALL // balr R7, R6 __errno (return #3)
|
||||
NOPH
|
||||
MOVWZ 0(R3), R3
|
||||
MOVD R3, err+48(FP)
|
||||
MOVD zosLibVec<>(SB), R8
|
||||
ADD $(__err2ad), R8
|
||||
LMG 0(R8), R5, R6
|
||||
LE_CALL // balr R7, R6 __err2ad (return #2)
|
||||
NOPH
|
||||
MOVW (R3), R2 // retrieve errno2
|
||||
MOVD R2, errno2+40(FP) // store in return area
|
||||
XOR R2, R2
|
||||
MOVWZ R2, (R3) // clear errno2
|
||||
|
||||
done:
|
||||
MOVD R4, 0(R9) // Save stack pointer.
|
||||
RET
|
||||
|
||||
//
|
||||
// function to test if a pointer can be safely dereferenced (content read)
|
||||
// return 0 for succces
|
||||
//
|
||||
TEXT ·ptrtest(SB), NOSPLIT, $0-16
|
||||
MOVD arg+0(FP), R10 // test pointer in R10
|
||||
|
||||
// set up R2 to point to CEECAADMC
|
||||
BYTE $0xE3; BYTE $0x20; BYTE $0x04; BYTE $0xB8; BYTE $0x00; BYTE $0x17 // llgt 2,1208
|
||||
BYTE $0xB9; BYTE $0x17; BYTE $0x00; BYTE $0x22 // llgtr 2,2
|
||||
BYTE $0xA5; BYTE $0x26; BYTE $0x7F; BYTE $0xFF // nilh 2,32767
|
||||
BYTE $0xE3; BYTE $0x22; BYTE $0x00; BYTE $0x58; BYTE $0x00; BYTE $0x04 // lg 2,88(2)
|
||||
BYTE $0xE3; BYTE $0x22; BYTE $0x00; BYTE $0x08; BYTE $0x00; BYTE $0x04 // lg 2,8(2)
|
||||
BYTE $0x41; BYTE $0x22; BYTE $0x03; BYTE $0x68 // la 2,872(2)
|
||||
|
||||
// set up R5 to point to the "shunt" path which set 1 to R3 (failure)
|
||||
BYTE $0xB9; BYTE $0x82; BYTE $0x00; BYTE $0x33 // xgr 3,3
|
||||
BYTE $0xA7; BYTE $0x55; BYTE $0x00; BYTE $0x04 // bras 5,lbl1
|
||||
BYTE $0xA7; BYTE $0x39; BYTE $0x00; BYTE $0x01 // lghi 3,1
|
||||
|
||||
// if r3 is not zero (failed) then branch to finish
|
||||
BYTE $0xB9; BYTE $0x02; BYTE $0x00; BYTE $0x33 // lbl1 ltgr 3,3
|
||||
BYTE $0xA7; BYTE $0x74; BYTE $0x00; BYTE $0x08 // brc b'0111',lbl2
|
||||
|
||||
// stomic store shunt address in R5 into CEECAADMC
|
||||
BYTE $0xE3; BYTE $0x52; BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x24 // stg 5,0(2)
|
||||
|
||||
// now try reading from the test pointer in R10, if it fails it branches to the "lghi" instruction above
|
||||
BYTE $0xE3; BYTE $0x9A; BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x04 // lg 9,0(10)
|
||||
|
||||
// finish here, restore 0 into CEECAADMC
|
||||
BYTE $0xB9; BYTE $0x82; BYTE $0x00; BYTE $0x99 // lbl2 xgr 9,9
|
||||
BYTE $0xE3; BYTE $0x92; BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x24 // stg 9,0(2)
|
||||
MOVD R3, ret+8(FP) // result in R3
|
||||
RET
|
||||
|
||||
//
|
||||
// function to test if a untptr can be loaded from a pointer
|
||||
// return 1: the 8-byte content
|
||||
// 2: 0 for success, 1 for failure
|
||||
//
|
||||
// func safeload(ptr uintptr) ( value uintptr, error uintptr)
|
||||
TEXT ·safeload(SB), NOSPLIT, $0-24
|
||||
MOVD ptr+0(FP), R10 // test pointer in R10
|
||||
MOVD $0x0, R6
|
||||
BYTE $0xE3; BYTE $0x20; BYTE $0x04; BYTE $0xB8; BYTE $0x00; BYTE $0x17 // llgt 2,1208
|
||||
BYTE $0xB9; BYTE $0x17; BYTE $0x00; BYTE $0x22 // llgtr 2,2
|
||||
BYTE $0xA5; BYTE $0x26; BYTE $0x7F; BYTE $0xFF // nilh 2,32767
|
||||
BYTE $0xE3; BYTE $0x22; BYTE $0x00; BYTE $0x58; BYTE $0x00; BYTE $0x04 // lg 2,88(2)
|
||||
BYTE $0xE3; BYTE $0x22; BYTE $0x00; BYTE $0x08; BYTE $0x00; BYTE $0x04 // lg 2,8(2)
|
||||
BYTE $0x41; BYTE $0x22; BYTE $0x03; BYTE $0x68 // la 2,872(2)
|
||||
BYTE $0xB9; BYTE $0x82; BYTE $0x00; BYTE $0x33 // xgr 3,3
|
||||
BYTE $0xA7; BYTE $0x55; BYTE $0x00; BYTE $0x04 // bras 5,lbl1
|
||||
BYTE $0xA7; BYTE $0x39; BYTE $0x00; BYTE $0x01 // lghi 3,1
|
||||
BYTE $0xB9; BYTE $0x02; BYTE $0x00; BYTE $0x33 // lbl1 ltgr 3,3
|
||||
BYTE $0xA7; BYTE $0x74; BYTE $0x00; BYTE $0x08 // brc b'0111',lbl2
|
||||
BYTE $0xE3; BYTE $0x52; BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x24 // stg 5,0(2)
|
||||
BYTE $0xE3; BYTE $0x6A; BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x04 // lg 6,0(10)
|
||||
BYTE $0xB9; BYTE $0x82; BYTE $0x00; BYTE $0x99 // lbl2 xgr 9,9
|
||||
BYTE $0xE3; BYTE $0x92; BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x24 // stg 9,0(2)
|
||||
MOVD R6, value+8(FP) // result in R6
|
||||
MOVD R3, error+16(FP) // error in R3
|
||||
RET
|
||||
|
|
|
|||
657
vendor/golang.org/x/sys/unix/bpxsvc_zos.go
generated
vendored
Normal file
657
vendor/golang.org/x/sys/unix/bpxsvc_zos.go
generated
vendored
Normal file
|
|
@ -0,0 +1,657 @@
|
|||
// Copyright 2024 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 zos
|
||||
|
||||
package unix
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
//go:noescape
|
||||
func bpxcall(plist []unsafe.Pointer, bpx_offset int64)
|
||||
|
||||
//go:noescape
|
||||
func A2e([]byte)
|
||||
|
||||
//go:noescape
|
||||
func E2a([]byte)
|
||||
|
||||
const (
|
||||
BPX4STA = 192 // stat
|
||||
BPX4FST = 104 // fstat
|
||||
BPX4LST = 132 // lstat
|
||||
BPX4OPN = 156 // open
|
||||
BPX4CLO = 72 // close
|
||||
BPX4CHR = 500 // chattr
|
||||
BPX4FCR = 504 // fchattr
|
||||
BPX4LCR = 1180 // lchattr
|
||||
BPX4CTW = 492 // cond_timed_wait
|
||||
BPX4GTH = 1056 // __getthent
|
||||
BPX4PTQ = 412 // pthread_quiesc
|
||||
BPX4PTR = 320 // ptrace
|
||||
)
|
||||
|
||||
const (
|
||||
//options
|
||||
//byte1
|
||||
BPX_OPNFHIGH = 0x80
|
||||
//byte2
|
||||
BPX_OPNFEXEC = 0x80
|
||||
//byte3
|
||||
BPX_O_NOLARGEFILE = 0x08
|
||||
BPX_O_LARGEFILE = 0x04
|
||||
BPX_O_ASYNCSIG = 0x02
|
||||
BPX_O_SYNC = 0x01
|
||||
//byte4
|
||||
BPX_O_CREXCL = 0xc0
|
||||
BPX_O_CREAT = 0x80
|
||||
BPX_O_EXCL = 0x40
|
||||
BPX_O_NOCTTY = 0x20
|
||||
BPX_O_TRUNC = 0x10
|
||||
BPX_O_APPEND = 0x08
|
||||
BPX_O_NONBLOCK = 0x04
|
||||
BPX_FNDELAY = 0x04
|
||||
BPX_O_RDWR = 0x03
|
||||
BPX_O_RDONLY = 0x02
|
||||
BPX_O_WRONLY = 0x01
|
||||
BPX_O_ACCMODE = 0x03
|
||||
BPX_O_GETFL = 0x0f
|
||||
|
||||
//mode
|
||||
// byte1 (file type)
|
||||
BPX_FT_DIR = 1
|
||||
BPX_FT_CHARSPEC = 2
|
||||
BPX_FT_REGFILE = 3
|
||||
BPX_FT_FIFO = 4
|
||||
BPX_FT_SYMLINK = 5
|
||||
BPX_FT_SOCKET = 6
|
||||
//byte3
|
||||
BPX_S_ISUID = 0x08
|
||||
BPX_S_ISGID = 0x04
|
||||
BPX_S_ISVTX = 0x02
|
||||
BPX_S_IRWXU1 = 0x01
|
||||
BPX_S_IRUSR = 0x01
|
||||
//byte4
|
||||
BPX_S_IRWXU2 = 0xc0
|
||||
BPX_S_IWUSR = 0x80
|
||||
BPX_S_IXUSR = 0x40
|
||||
BPX_S_IRWXG = 0x38
|
||||
BPX_S_IRGRP = 0x20
|
||||
BPX_S_IWGRP = 0x10
|
||||
BPX_S_IXGRP = 0x08
|
||||
BPX_S_IRWXOX = 0x07
|
||||
BPX_S_IROTH = 0x04
|
||||
BPX_S_IWOTH = 0x02
|
||||
BPX_S_IXOTH = 0x01
|
||||
|
||||
CW_INTRPT = 1
|
||||
CW_CONDVAR = 32
|
||||
CW_TIMEOUT = 64
|
||||
|
||||
PGTHA_NEXT = 2
|
||||
PGTHA_CURRENT = 1
|
||||
PGTHA_FIRST = 0
|
||||
PGTHA_LAST = 3
|
||||
PGTHA_PROCESS = 0x80
|
||||
PGTHA_CONTTY = 0x40
|
||||
PGTHA_PATH = 0x20
|
||||
PGTHA_COMMAND = 0x10
|
||||
PGTHA_FILEDATA = 0x08
|
||||
PGTHA_THREAD = 0x04
|
||||
PGTHA_PTAG = 0x02
|
||||
PGTHA_COMMANDLONG = 0x01
|
||||
PGTHA_THREADFAST = 0x80
|
||||
PGTHA_FILEPATH = 0x40
|
||||
PGTHA_THDSIGMASK = 0x20
|
||||
// thread quiece mode
|
||||
QUIESCE_TERM int32 = 1
|
||||
QUIESCE_FORCE int32 = 2
|
||||
QUIESCE_QUERY int32 = 3
|
||||
QUIESCE_FREEZE int32 = 4
|
||||
QUIESCE_UNFREEZE int32 = 5
|
||||
FREEZE_THIS_THREAD int32 = 6
|
||||
FREEZE_EXIT int32 = 8
|
||||
QUIESCE_SRB int32 = 9
|
||||
)
|
||||
|
||||
type Pgtha struct {
|
||||
Pid uint32 // 0
|
||||
Tid0 uint32 // 4
|
||||
Tid1 uint32
|
||||
Accesspid byte // C
|
||||
Accesstid byte // D
|
||||
Accessasid uint16 // E
|
||||
Loginname [8]byte // 10
|
||||
Flag1 byte // 18
|
||||
Flag1b2 byte // 19
|
||||
}
|
||||
|
||||
type Bpxystat_t struct { // DSECT BPXYSTAT
|
||||
St_id [4]uint8 // 0
|
||||
St_length uint16 // 0x4
|
||||
St_version uint16 // 0x6
|
||||
St_mode uint32 // 0x8
|
||||
St_ino uint32 // 0xc
|
||||
St_dev uint32 // 0x10
|
||||
St_nlink uint32 // 0x14
|
||||
St_uid uint32 // 0x18
|
||||
St_gid uint32 // 0x1c
|
||||
St_size uint64 // 0x20
|
||||
St_atime uint32 // 0x28
|
||||
St_mtime uint32 // 0x2c
|
||||
St_ctime uint32 // 0x30
|
||||
St_rdev uint32 // 0x34
|
||||
St_auditoraudit uint32 // 0x38
|
||||
St_useraudit uint32 // 0x3c
|
||||
St_blksize uint32 // 0x40
|
||||
St_createtime uint32 // 0x44
|
||||
St_auditid [4]uint32 // 0x48
|
||||
St_res01 uint32 // 0x58
|
||||
Ft_ccsid uint16 // 0x5c
|
||||
Ft_flags uint16 // 0x5e
|
||||
St_res01a [2]uint32 // 0x60
|
||||
St_res02 uint32 // 0x68
|
||||
St_blocks uint32 // 0x6c
|
||||
St_opaque [3]uint8 // 0x70
|
||||
St_visible uint8 // 0x73
|
||||
St_reftime uint32 // 0x74
|
||||
St_fid uint64 // 0x78
|
||||
St_filefmt uint8 // 0x80
|
||||
St_fspflag2 uint8 // 0x81
|
||||
St_res03 [2]uint8 // 0x82
|
||||
St_ctimemsec uint32 // 0x84
|
||||
St_seclabel [8]uint8 // 0x88
|
||||
St_res04 [4]uint8 // 0x90
|
||||
// end of version 1
|
||||
_ uint32 // 0x94
|
||||
St_atime64 uint64 // 0x98
|
||||
St_mtime64 uint64 // 0xa0
|
||||
St_ctime64 uint64 // 0xa8
|
||||
St_createtime64 uint64 // 0xb0
|
||||
St_reftime64 uint64 // 0xb8
|
||||
_ uint64 // 0xc0
|
||||
St_res05 [16]uint8 // 0xc8
|
||||
// end of version 2
|
||||
}
|
||||
|
||||
type BpxFilestatus struct {
|
||||
Oflag1 byte
|
||||
Oflag2 byte
|
||||
Oflag3 byte
|
||||
Oflag4 byte
|
||||
}
|
||||
|
||||
type BpxMode struct {
|
||||
Ftype byte
|
||||
Mode1 byte
|
||||
Mode2 byte
|
||||
Mode3 byte
|
||||
}
|
||||
|
||||
// Thr attribute structure for extended attributes
|
||||
type Bpxyatt_t struct { // DSECT BPXYATT
|
||||
Att_id [4]uint8
|
||||
Att_version uint16
|
||||
Att_res01 [2]uint8
|
||||
Att_setflags1 uint8
|
||||
Att_setflags2 uint8
|
||||
Att_setflags3 uint8
|
||||
Att_setflags4 uint8
|
||||
Att_mode uint32
|
||||
Att_uid uint32
|
||||
Att_gid uint32
|
||||
Att_opaquemask [3]uint8
|
||||
Att_visblmaskres uint8
|
||||
Att_opaque [3]uint8
|
||||
Att_visibleres uint8
|
||||
Att_size_h uint32
|
||||
Att_size_l uint32
|
||||
Att_atime uint32
|
||||
Att_mtime uint32
|
||||
Att_auditoraudit uint32
|
||||
Att_useraudit uint32
|
||||
Att_ctime uint32
|
||||
Att_reftime uint32
|
||||
// end of version 1
|
||||
Att_filefmt uint8
|
||||
Att_res02 [3]uint8
|
||||
Att_filetag uint32
|
||||
Att_res03 [8]uint8
|
||||
// end of version 2
|
||||
Att_atime64 uint64
|
||||
Att_mtime64 uint64
|
||||
Att_ctime64 uint64
|
||||
Att_reftime64 uint64
|
||||
Att_seclabel [8]uint8
|
||||
Att_ver3res02 [8]uint8
|
||||
// end of version 3
|
||||
}
|
||||
|
||||
func BpxOpen(name string, options *BpxFilestatus, mode *BpxMode) (rv int32, rc int32, rn int32) {
|
||||
if len(name) < 1024 {
|
||||
var namebuf [1024]byte
|
||||
sz := int32(copy(namebuf[:], name))
|
||||
A2e(namebuf[:sz])
|
||||
var parms [7]unsafe.Pointer
|
||||
parms[0] = unsafe.Pointer(&sz)
|
||||
parms[1] = unsafe.Pointer(&namebuf[0])
|
||||
parms[2] = unsafe.Pointer(options)
|
||||
parms[3] = unsafe.Pointer(mode)
|
||||
parms[4] = unsafe.Pointer(&rv)
|
||||
parms[5] = unsafe.Pointer(&rc)
|
||||
parms[6] = unsafe.Pointer(&rn)
|
||||
bpxcall(parms[:], BPX4OPN)
|
||||
return rv, rc, rn
|
||||
}
|
||||
return -1, -1, -1
|
||||
}
|
||||
|
||||
func BpxClose(fd int32) (rv int32, rc int32, rn int32) {
|
||||
var parms [4]unsafe.Pointer
|
||||
parms[0] = unsafe.Pointer(&fd)
|
||||
parms[1] = unsafe.Pointer(&rv)
|
||||
parms[2] = unsafe.Pointer(&rc)
|
||||
parms[3] = unsafe.Pointer(&rn)
|
||||
bpxcall(parms[:], BPX4CLO)
|
||||
return rv, rc, rn
|
||||
}
|
||||
|
||||
func BpxFileFStat(fd int32, st *Bpxystat_t) (rv int32, rc int32, rn int32) {
|
||||
st.St_id = [4]uint8{0xe2, 0xe3, 0xc1, 0xe3}
|
||||
st.St_version = 2
|
||||
stat_sz := uint32(unsafe.Sizeof(*st))
|
||||
var parms [6]unsafe.Pointer
|
||||
parms[0] = unsafe.Pointer(&fd)
|
||||
parms[1] = unsafe.Pointer(&stat_sz)
|
||||
parms[2] = unsafe.Pointer(st)
|
||||
parms[3] = unsafe.Pointer(&rv)
|
||||
parms[4] = unsafe.Pointer(&rc)
|
||||
parms[5] = unsafe.Pointer(&rn)
|
||||
bpxcall(parms[:], BPX4FST)
|
||||
return rv, rc, rn
|
||||
}
|
||||
|
||||
func BpxFileStat(name string, st *Bpxystat_t) (rv int32, rc int32, rn int32) {
|
||||
if len(name) < 1024 {
|
||||
var namebuf [1024]byte
|
||||
sz := int32(copy(namebuf[:], name))
|
||||
A2e(namebuf[:sz])
|
||||
st.St_id = [4]uint8{0xe2, 0xe3, 0xc1, 0xe3}
|
||||
st.St_version = 2
|
||||
stat_sz := uint32(unsafe.Sizeof(*st))
|
||||
var parms [7]unsafe.Pointer
|
||||
parms[0] = unsafe.Pointer(&sz)
|
||||
parms[1] = unsafe.Pointer(&namebuf[0])
|
||||
parms[2] = unsafe.Pointer(&stat_sz)
|
||||
parms[3] = unsafe.Pointer(st)
|
||||
parms[4] = unsafe.Pointer(&rv)
|
||||
parms[5] = unsafe.Pointer(&rc)
|
||||
parms[6] = unsafe.Pointer(&rn)
|
||||
bpxcall(parms[:], BPX4STA)
|
||||
return rv, rc, rn
|
||||
}
|
||||
return -1, -1, -1
|
||||
}
|
||||
|
||||
func BpxFileLStat(name string, st *Bpxystat_t) (rv int32, rc int32, rn int32) {
|
||||
if len(name) < 1024 {
|
||||
var namebuf [1024]byte
|
||||
sz := int32(copy(namebuf[:], name))
|
||||
A2e(namebuf[:sz])
|
||||
st.St_id = [4]uint8{0xe2, 0xe3, 0xc1, 0xe3}
|
||||
st.St_version = 2
|
||||
stat_sz := uint32(unsafe.Sizeof(*st))
|
||||
var parms [7]unsafe.Pointer
|
||||
parms[0] = unsafe.Pointer(&sz)
|
||||
parms[1] = unsafe.Pointer(&namebuf[0])
|
||||
parms[2] = unsafe.Pointer(&stat_sz)
|
||||
parms[3] = unsafe.Pointer(st)
|
||||
parms[4] = unsafe.Pointer(&rv)
|
||||
parms[5] = unsafe.Pointer(&rc)
|
||||
parms[6] = unsafe.Pointer(&rn)
|
||||
bpxcall(parms[:], BPX4LST)
|
||||
return rv, rc, rn
|
||||
}
|
||||
return -1, -1, -1
|
||||
}
|
||||
|
||||
func BpxChattr(path string, attr *Bpxyatt_t) (rv int32, rc int32, rn int32) {
|
||||
if len(path) >= 1024 {
|
||||
return -1, -1, -1
|
||||
}
|
||||
var namebuf [1024]byte
|
||||
sz := int32(copy(namebuf[:], path))
|
||||
A2e(namebuf[:sz])
|
||||
attr_sz := uint32(unsafe.Sizeof(*attr))
|
||||
var parms [7]unsafe.Pointer
|
||||
parms[0] = unsafe.Pointer(&sz)
|
||||
parms[1] = unsafe.Pointer(&namebuf[0])
|
||||
parms[2] = unsafe.Pointer(&attr_sz)
|
||||
parms[3] = unsafe.Pointer(attr)
|
||||
parms[4] = unsafe.Pointer(&rv)
|
||||
parms[5] = unsafe.Pointer(&rc)
|
||||
parms[6] = unsafe.Pointer(&rn)
|
||||
bpxcall(parms[:], BPX4CHR)
|
||||
return rv, rc, rn
|
||||
}
|
||||
|
||||
func BpxLchattr(path string, attr *Bpxyatt_t) (rv int32, rc int32, rn int32) {
|
||||
if len(path) >= 1024 {
|
||||
return -1, -1, -1
|
||||
}
|
||||
var namebuf [1024]byte
|
||||
sz := int32(copy(namebuf[:], path))
|
||||
A2e(namebuf[:sz])
|
||||
attr_sz := uint32(unsafe.Sizeof(*attr))
|
||||
var parms [7]unsafe.Pointer
|
||||
parms[0] = unsafe.Pointer(&sz)
|
||||
parms[1] = unsafe.Pointer(&namebuf[0])
|
||||
parms[2] = unsafe.Pointer(&attr_sz)
|
||||
parms[3] = unsafe.Pointer(attr)
|
||||
parms[4] = unsafe.Pointer(&rv)
|
||||
parms[5] = unsafe.Pointer(&rc)
|
||||
parms[6] = unsafe.Pointer(&rn)
|
||||
bpxcall(parms[:], BPX4LCR)
|
||||
return rv, rc, rn
|
||||
}
|
||||
|
||||
func BpxFchattr(fd int32, attr *Bpxyatt_t) (rv int32, rc int32, rn int32) {
|
||||
attr_sz := uint32(unsafe.Sizeof(*attr))
|
||||
var parms [6]unsafe.Pointer
|
||||
parms[0] = unsafe.Pointer(&fd)
|
||||
parms[1] = unsafe.Pointer(&attr_sz)
|
||||
parms[2] = unsafe.Pointer(attr)
|
||||
parms[3] = unsafe.Pointer(&rv)
|
||||
parms[4] = unsafe.Pointer(&rc)
|
||||
parms[5] = unsafe.Pointer(&rn)
|
||||
bpxcall(parms[:], BPX4FCR)
|
||||
return rv, rc, rn
|
||||
}
|
||||
|
||||
func BpxCondTimedWait(sec uint32, nsec uint32, events uint32, secrem *uint32, nsecrem *uint32) (rv int32, rc int32, rn int32) {
|
||||
var parms [8]unsafe.Pointer
|
||||
parms[0] = unsafe.Pointer(&sec)
|
||||
parms[1] = unsafe.Pointer(&nsec)
|
||||
parms[2] = unsafe.Pointer(&events)
|
||||
parms[3] = unsafe.Pointer(secrem)
|
||||
parms[4] = unsafe.Pointer(nsecrem)
|
||||
parms[5] = unsafe.Pointer(&rv)
|
||||
parms[6] = unsafe.Pointer(&rc)
|
||||
parms[7] = unsafe.Pointer(&rn)
|
||||
bpxcall(parms[:], BPX4CTW)
|
||||
return rv, rc, rn
|
||||
}
|
||||
func BpxGetthent(in *Pgtha, outlen *uint32, out unsafe.Pointer) (rv int32, rc int32, rn int32) {
|
||||
var parms [7]unsafe.Pointer
|
||||
inlen := uint32(26) // nothing else will work. Go says Pgtha is 28-byte because of alignment, but Pgtha is "packed" and must be 26-byte
|
||||
parms[0] = unsafe.Pointer(&inlen)
|
||||
parms[1] = unsafe.Pointer(&in)
|
||||
parms[2] = unsafe.Pointer(outlen)
|
||||
parms[3] = unsafe.Pointer(&out)
|
||||
parms[4] = unsafe.Pointer(&rv)
|
||||
parms[5] = unsafe.Pointer(&rc)
|
||||
parms[6] = unsafe.Pointer(&rn)
|
||||
bpxcall(parms[:], BPX4GTH)
|
||||
return rv, rc, rn
|
||||
}
|
||||
func ZosJobname() (jobname string, err error) {
|
||||
var pgtha Pgtha
|
||||
pgtha.Pid = uint32(Getpid())
|
||||
pgtha.Accesspid = PGTHA_CURRENT
|
||||
pgtha.Flag1 = PGTHA_PROCESS
|
||||
var out [256]byte
|
||||
var outlen uint32
|
||||
outlen = 256
|
||||
rv, rc, rn := BpxGetthent(&pgtha, &outlen, unsafe.Pointer(&out[0]))
|
||||
if rv == 0 {
|
||||
gthc := []byte{0x87, 0xa3, 0x88, 0x83} // 'gthc' in ebcdic
|
||||
ix := bytes.Index(out[:], gthc)
|
||||
if ix == -1 {
|
||||
err = fmt.Errorf("BPX4GTH: gthc return data not found")
|
||||
return
|
||||
}
|
||||
jn := out[ix+80 : ix+88] // we didn't declare Pgthc, but jobname is 8-byte at offset 80
|
||||
E2a(jn)
|
||||
jobname = string(bytes.TrimRight(jn, " "))
|
||||
|
||||
} else {
|
||||
err = fmt.Errorf("BPX4GTH: rc=%d errno=%d reason=code=0x%x", rv, rc, rn)
|
||||
}
|
||||
return
|
||||
}
|
||||
func Bpx4ptq(code int32, data string) (rv int32, rc int32, rn int32) {
|
||||
var userdata [8]byte
|
||||
var parms [5]unsafe.Pointer
|
||||
copy(userdata[:], data+" ")
|
||||
A2e(userdata[:])
|
||||
parms[0] = unsafe.Pointer(&code)
|
||||
parms[1] = unsafe.Pointer(&userdata[0])
|
||||
parms[2] = unsafe.Pointer(&rv)
|
||||
parms[3] = unsafe.Pointer(&rc)
|
||||
parms[4] = unsafe.Pointer(&rn)
|
||||
bpxcall(parms[:], BPX4PTQ)
|
||||
return rv, rc, rn
|
||||
}
|
||||
|
||||
const (
|
||||
PT_TRACE_ME = 0 // Debug this process
|
||||
PT_READ_I = 1 // Read a full word
|
||||
PT_READ_D = 2 // Read a full word
|
||||
PT_READ_U = 3 // Read control info
|
||||
PT_WRITE_I = 4 //Write a full word
|
||||
PT_WRITE_D = 5 //Write a full word
|
||||
PT_CONTINUE = 7 //Continue the process
|
||||
PT_KILL = 8 //Terminate the process
|
||||
PT_READ_GPR = 11 // Read GPR, CR, PSW
|
||||
PT_READ_FPR = 12 // Read FPR
|
||||
PT_READ_VR = 13 // Read VR
|
||||
PT_WRITE_GPR = 14 // Write GPR, CR, PSW
|
||||
PT_WRITE_FPR = 15 // Write FPR
|
||||
PT_WRITE_VR = 16 // Write VR
|
||||
PT_READ_BLOCK = 17 // Read storage
|
||||
PT_WRITE_BLOCK = 19 // Write storage
|
||||
PT_READ_GPRH = 20 // Read GPRH
|
||||
PT_WRITE_GPRH = 21 // Write GPRH
|
||||
PT_REGHSET = 22 // Read all GPRHs
|
||||
PT_ATTACH = 30 // Attach to a process
|
||||
PT_DETACH = 31 // Detach from a process
|
||||
PT_REGSET = 32 // Read all GPRs
|
||||
PT_REATTACH = 33 // Reattach to a process
|
||||
PT_LDINFO = 34 // Read loader info
|
||||
PT_MULTI = 35 // Multi process mode
|
||||
PT_LD64INFO = 36 // RMODE64 Info Area
|
||||
PT_BLOCKREQ = 40 // Block request
|
||||
PT_THREAD_INFO = 60 // Read thread info
|
||||
PT_THREAD_MODIFY = 61
|
||||
PT_THREAD_READ_FOCUS = 62
|
||||
PT_THREAD_WRITE_FOCUS = 63
|
||||
PT_THREAD_HOLD = 64
|
||||
PT_THREAD_SIGNAL = 65
|
||||
PT_EXPLAIN = 66
|
||||
PT_EVENTS = 67
|
||||
PT_THREAD_INFO_EXTENDED = 68
|
||||
PT_REATTACH2 = 71
|
||||
PT_CAPTURE = 72
|
||||
PT_UNCAPTURE = 73
|
||||
PT_GET_THREAD_TCB = 74
|
||||
PT_GET_ALET = 75
|
||||
PT_SWAPIN = 76
|
||||
PT_EXTENDED_EVENT = 98
|
||||
PT_RECOVER = 99 // Debug a program check
|
||||
PT_GPR0 = 0 // General purpose register 0
|
||||
PT_GPR1 = 1 // General purpose register 1
|
||||
PT_GPR2 = 2 // General purpose register 2
|
||||
PT_GPR3 = 3 // General purpose register 3
|
||||
PT_GPR4 = 4 // General purpose register 4
|
||||
PT_GPR5 = 5 // General purpose register 5
|
||||
PT_GPR6 = 6 // General purpose register 6
|
||||
PT_GPR7 = 7 // General purpose register 7
|
||||
PT_GPR8 = 8 // General purpose register 8
|
||||
PT_GPR9 = 9 // General purpose register 9
|
||||
PT_GPR10 = 10 // General purpose register 10
|
||||
PT_GPR11 = 11 // General purpose register 11
|
||||
PT_GPR12 = 12 // General purpose register 12
|
||||
PT_GPR13 = 13 // General purpose register 13
|
||||
PT_GPR14 = 14 // General purpose register 14
|
||||
PT_GPR15 = 15 // General purpose register 15
|
||||
PT_FPR0 = 16 // Floating point register 0
|
||||
PT_FPR1 = 17 // Floating point register 1
|
||||
PT_FPR2 = 18 // Floating point register 2
|
||||
PT_FPR3 = 19 // Floating point register 3
|
||||
PT_FPR4 = 20 // Floating point register 4
|
||||
PT_FPR5 = 21 // Floating point register 5
|
||||
PT_FPR6 = 22 // Floating point register 6
|
||||
PT_FPR7 = 23 // Floating point register 7
|
||||
PT_FPR8 = 24 // Floating point register 8
|
||||
PT_FPR9 = 25 // Floating point register 9
|
||||
PT_FPR10 = 26 // Floating point register 10
|
||||
PT_FPR11 = 27 // Floating point register 11
|
||||
PT_FPR12 = 28 // Floating point register 12
|
||||
PT_FPR13 = 29 // Floating point register 13
|
||||
PT_FPR14 = 30 // Floating point register 14
|
||||
PT_FPR15 = 31 // Floating point register 15
|
||||
PT_FPC = 32 // Floating point control register
|
||||
PT_PSW = 40 // PSW
|
||||
PT_PSW0 = 40 // Left half of the PSW
|
||||
PT_PSW1 = 41 // Right half of the PSW
|
||||
PT_CR0 = 42 // Control register 0
|
||||
PT_CR1 = 43 // Control register 1
|
||||
PT_CR2 = 44 // Control register 2
|
||||
PT_CR3 = 45 // Control register 3
|
||||
PT_CR4 = 46 // Control register 4
|
||||
PT_CR5 = 47 // Control register 5
|
||||
PT_CR6 = 48 // Control register 6
|
||||
PT_CR7 = 49 // Control register 7
|
||||
PT_CR8 = 50 // Control register 8
|
||||
PT_CR9 = 51 // Control register 9
|
||||
PT_CR10 = 52 // Control register 10
|
||||
PT_CR11 = 53 // Control register 11
|
||||
PT_CR12 = 54 // Control register 12
|
||||
PT_CR13 = 55 // Control register 13
|
||||
PT_CR14 = 56 // Control register 14
|
||||
PT_CR15 = 57 // Control register 15
|
||||
PT_GPRH0 = 58 // GP High register 0
|
||||
PT_GPRH1 = 59 // GP High register 1
|
||||
PT_GPRH2 = 60 // GP High register 2
|
||||
PT_GPRH3 = 61 // GP High register 3
|
||||
PT_GPRH4 = 62 // GP High register 4
|
||||
PT_GPRH5 = 63 // GP High register 5
|
||||
PT_GPRH6 = 64 // GP High register 6
|
||||
PT_GPRH7 = 65 // GP High register 7
|
||||
PT_GPRH8 = 66 // GP High register 8
|
||||
PT_GPRH9 = 67 // GP High register 9
|
||||
PT_GPRH10 = 68 // GP High register 10
|
||||
PT_GPRH11 = 69 // GP High register 11
|
||||
PT_GPRH12 = 70 // GP High register 12
|
||||
PT_GPRH13 = 71 // GP High register 13
|
||||
PT_GPRH14 = 72 // GP High register 14
|
||||
PT_GPRH15 = 73 // GP High register 15
|
||||
PT_VR0 = 74 // Vector register 0
|
||||
PT_VR1 = 75 // Vector register 1
|
||||
PT_VR2 = 76 // Vector register 2
|
||||
PT_VR3 = 77 // Vector register 3
|
||||
PT_VR4 = 78 // Vector register 4
|
||||
PT_VR5 = 79 // Vector register 5
|
||||
PT_VR6 = 80 // Vector register 6
|
||||
PT_VR7 = 81 // Vector register 7
|
||||
PT_VR8 = 82 // Vector register 8
|
||||
PT_VR9 = 83 // Vector register 9
|
||||
PT_VR10 = 84 // Vector register 10
|
||||
PT_VR11 = 85 // Vector register 11
|
||||
PT_VR12 = 86 // Vector register 12
|
||||
PT_VR13 = 87 // Vector register 13
|
||||
PT_VR14 = 88 // Vector register 14
|
||||
PT_VR15 = 89 // Vector register 15
|
||||
PT_VR16 = 90 // Vector register 16
|
||||
PT_VR17 = 91 // Vector register 17
|
||||
PT_VR18 = 92 // Vector register 18
|
||||
PT_VR19 = 93 // Vector register 19
|
||||
PT_VR20 = 94 // Vector register 20
|
||||
PT_VR21 = 95 // Vector register 21
|
||||
PT_VR22 = 96 // Vector register 22
|
||||
PT_VR23 = 97 // Vector register 23
|
||||
PT_VR24 = 98 // Vector register 24
|
||||
PT_VR25 = 99 // Vector register 25
|
||||
PT_VR26 = 100 // Vector register 26
|
||||
PT_VR27 = 101 // Vector register 27
|
||||
PT_VR28 = 102 // Vector register 28
|
||||
PT_VR29 = 103 // Vector register 29
|
||||
PT_VR30 = 104 // Vector register 30
|
||||
PT_VR31 = 105 // Vector register 31
|
||||
PT_PSWG = 106 // PSWG
|
||||
PT_PSWG0 = 106 // Bytes 0-3
|
||||
PT_PSWG1 = 107 // Bytes 4-7
|
||||
PT_PSWG2 = 108 // Bytes 8-11 (IA high word)
|
||||
PT_PSWG3 = 109 // Bytes 12-15 (IA low word)
|
||||
)
|
||||
|
||||
func Bpx4ptr(request int32, pid int32, addr unsafe.Pointer, data unsafe.Pointer, buffer unsafe.Pointer) (rv int32, rc int32, rn int32) {
|
||||
var parms [8]unsafe.Pointer
|
||||
parms[0] = unsafe.Pointer(&request)
|
||||
parms[1] = unsafe.Pointer(&pid)
|
||||
parms[2] = unsafe.Pointer(&addr)
|
||||
parms[3] = unsafe.Pointer(&data)
|
||||
parms[4] = unsafe.Pointer(&buffer)
|
||||
parms[5] = unsafe.Pointer(&rv)
|
||||
parms[6] = unsafe.Pointer(&rc)
|
||||
parms[7] = unsafe.Pointer(&rn)
|
||||
bpxcall(parms[:], BPX4PTR)
|
||||
return rv, rc, rn
|
||||
}
|
||||
|
||||
func copyU8(val uint8, dest []uint8) int {
|
||||
if len(dest) < 1 {
|
||||
return 0
|
||||
}
|
||||
dest[0] = val
|
||||
return 1
|
||||
}
|
||||
|
||||
func copyU8Arr(src, dest []uint8) int {
|
||||
if len(dest) < len(src) {
|
||||
return 0
|
||||
}
|
||||
for i, v := range src {
|
||||
dest[i] = v
|
||||
}
|
||||
return len(src)
|
||||
}
|
||||
|
||||
func copyU16(val uint16, dest []uint16) int {
|
||||
if len(dest) < 1 {
|
||||
return 0
|
||||
}
|
||||
dest[0] = val
|
||||
return 1
|
||||
}
|
||||
|
||||
func copyU32(val uint32, dest []uint32) int {
|
||||
if len(dest) < 1 {
|
||||
return 0
|
||||
}
|
||||
dest[0] = val
|
||||
return 1
|
||||
}
|
||||
|
||||
func copyU32Arr(src, dest []uint32) int {
|
||||
if len(dest) < len(src) {
|
||||
return 0
|
||||
}
|
||||
for i, v := range src {
|
||||
dest[i] = v
|
||||
}
|
||||
return len(src)
|
||||
}
|
||||
|
||||
func copyU64(val uint64, dest []uint64) int {
|
||||
if len(dest) < 1 {
|
||||
return 0
|
||||
}
|
||||
dest[0] = val
|
||||
return 1
|
||||
}
|
||||
192
vendor/golang.org/x/sys/unix/bpxsvc_zos.s
generated
vendored
Normal file
192
vendor/golang.org/x/sys/unix/bpxsvc_zos.s
generated
vendored
Normal file
|
|
@ -0,0 +1,192 @@
|
|||
// Copyright 2024 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.
|
||||
|
||||
#include "go_asm.h"
|
||||
#include "textflag.h"
|
||||
|
||||
// function to call USS assembly language services
|
||||
//
|
||||
// doc: https://www.ibm.com/support/knowledgecenter/en/SSLTBW_3.1.0/com.ibm.zos.v3r1.bpxb100/bit64env.htm
|
||||
//
|
||||
// arg1 unsafe.Pointer array that ressembles an OS PLIST
|
||||
//
|
||||
// arg2 function offset as in
|
||||
// doc: https://www.ibm.com/support/knowledgecenter/en/SSLTBW_3.1.0/com.ibm.zos.v3r1.bpxb100/bpx2cr_List_of_offsets.htm
|
||||
//
|
||||
// func bpxcall(plist []unsafe.Pointer, bpx_offset int64)
|
||||
|
||||
TEXT ·bpxcall(SB), NOSPLIT|NOFRAME, $0
|
||||
MOVD plist_base+0(FP), R1 // r1 points to plist
|
||||
MOVD bpx_offset+24(FP), R2 // r2 offset to BPX vector table
|
||||
MOVD R14, R7 // save r14
|
||||
MOVD R15, R8 // save r15
|
||||
MOVWZ 16(R0), R9
|
||||
MOVWZ 544(R9), R9
|
||||
MOVWZ 24(R9), R9 // call vector in r9
|
||||
ADD R2, R9 // add offset to vector table
|
||||
MOVWZ (R9), R9 // r9 points to entry point
|
||||
BYTE $0x0D // BL R14,R9 --> basr r14,r9
|
||||
BYTE $0xE9 // clobbers 0,1,14,15
|
||||
MOVD R8, R15 // restore 15
|
||||
JMP R7 // return via saved return address
|
||||
|
||||
// func A2e(arr [] byte)
|
||||
// code page conversion from 819 to 1047
|
||||
TEXT ·A2e(SB), NOSPLIT|NOFRAME, $0
|
||||
MOVD arg_base+0(FP), R2 // pointer to arry of characters
|
||||
MOVD arg_len+8(FP), R3 // count
|
||||
XOR R0, R0
|
||||
XOR R1, R1
|
||||
BYTE $0xA7; BYTE $0x15; BYTE $0x00; BYTE $0x82 // BRAS 1,(2+(256/2))
|
||||
|
||||
// ASCII -> EBCDIC conversion table:
|
||||
BYTE $0x00; BYTE $0x01; BYTE $0x02; BYTE $0x03
|
||||
BYTE $0x37; BYTE $0x2d; BYTE $0x2e; BYTE $0x2f
|
||||
BYTE $0x16; BYTE $0x05; BYTE $0x15; BYTE $0x0b
|
||||
BYTE $0x0c; BYTE $0x0d; BYTE $0x0e; BYTE $0x0f
|
||||
BYTE $0x10; BYTE $0x11; BYTE $0x12; BYTE $0x13
|
||||
BYTE $0x3c; BYTE $0x3d; BYTE $0x32; BYTE $0x26
|
||||
BYTE $0x18; BYTE $0x19; BYTE $0x3f; BYTE $0x27
|
||||
BYTE $0x1c; BYTE $0x1d; BYTE $0x1e; BYTE $0x1f
|
||||
BYTE $0x40; BYTE $0x5a; BYTE $0x7f; BYTE $0x7b
|
||||
BYTE $0x5b; BYTE $0x6c; BYTE $0x50; BYTE $0x7d
|
||||
BYTE $0x4d; BYTE $0x5d; BYTE $0x5c; BYTE $0x4e
|
||||
BYTE $0x6b; BYTE $0x60; BYTE $0x4b; BYTE $0x61
|
||||
BYTE $0xf0; BYTE $0xf1; BYTE $0xf2; BYTE $0xf3
|
||||
BYTE $0xf4; BYTE $0xf5; BYTE $0xf6; BYTE $0xf7
|
||||
BYTE $0xf8; BYTE $0xf9; BYTE $0x7a; BYTE $0x5e
|
||||
BYTE $0x4c; BYTE $0x7e; BYTE $0x6e; BYTE $0x6f
|
||||
BYTE $0x7c; BYTE $0xc1; BYTE $0xc2; BYTE $0xc3
|
||||
BYTE $0xc4; BYTE $0xc5; BYTE $0xc6; BYTE $0xc7
|
||||
BYTE $0xc8; BYTE $0xc9; BYTE $0xd1; BYTE $0xd2
|
||||
BYTE $0xd3; BYTE $0xd4; BYTE $0xd5; BYTE $0xd6
|
||||
BYTE $0xd7; BYTE $0xd8; BYTE $0xd9; BYTE $0xe2
|
||||
BYTE $0xe3; BYTE $0xe4; BYTE $0xe5; BYTE $0xe6
|
||||
BYTE $0xe7; BYTE $0xe8; BYTE $0xe9; BYTE $0xad
|
||||
BYTE $0xe0; BYTE $0xbd; BYTE $0x5f; BYTE $0x6d
|
||||
BYTE $0x79; BYTE $0x81; BYTE $0x82; BYTE $0x83
|
||||
BYTE $0x84; BYTE $0x85; BYTE $0x86; BYTE $0x87
|
||||
BYTE $0x88; BYTE $0x89; BYTE $0x91; BYTE $0x92
|
||||
BYTE $0x93; BYTE $0x94; BYTE $0x95; BYTE $0x96
|
||||
BYTE $0x97; BYTE $0x98; BYTE $0x99; BYTE $0xa2
|
||||
BYTE $0xa3; BYTE $0xa4; BYTE $0xa5; BYTE $0xa6
|
||||
BYTE $0xa7; BYTE $0xa8; BYTE $0xa9; BYTE $0xc0
|
||||
BYTE $0x4f; BYTE $0xd0; BYTE $0xa1; BYTE $0x07
|
||||
BYTE $0x20; BYTE $0x21; BYTE $0x22; BYTE $0x23
|
||||
BYTE $0x24; BYTE $0x25; BYTE $0x06; BYTE $0x17
|
||||
BYTE $0x28; BYTE $0x29; BYTE $0x2a; BYTE $0x2b
|
||||
BYTE $0x2c; BYTE $0x09; BYTE $0x0a; BYTE $0x1b
|
||||
BYTE $0x30; BYTE $0x31; BYTE $0x1a; BYTE $0x33
|
||||
BYTE $0x34; BYTE $0x35; BYTE $0x36; BYTE $0x08
|
||||
BYTE $0x38; BYTE $0x39; BYTE $0x3a; BYTE $0x3b
|
||||
BYTE $0x04; BYTE $0x14; BYTE $0x3e; BYTE $0xff
|
||||
BYTE $0x41; BYTE $0xaa; BYTE $0x4a; BYTE $0xb1
|
||||
BYTE $0x9f; BYTE $0xb2; BYTE $0x6a; BYTE $0xb5
|
||||
BYTE $0xbb; BYTE $0xb4; BYTE $0x9a; BYTE $0x8a
|
||||
BYTE $0xb0; BYTE $0xca; BYTE $0xaf; BYTE $0xbc
|
||||
BYTE $0x90; BYTE $0x8f; BYTE $0xea; BYTE $0xfa
|
||||
BYTE $0xbe; BYTE $0xa0; BYTE $0xb6; BYTE $0xb3
|
||||
BYTE $0x9d; BYTE $0xda; BYTE $0x9b; BYTE $0x8b
|
||||
BYTE $0xb7; BYTE $0xb8; BYTE $0xb9; BYTE $0xab
|
||||
BYTE $0x64; BYTE $0x65; BYTE $0x62; BYTE $0x66
|
||||
BYTE $0x63; BYTE $0x67; BYTE $0x9e; BYTE $0x68
|
||||
BYTE $0x74; BYTE $0x71; BYTE $0x72; BYTE $0x73
|
||||
BYTE $0x78; BYTE $0x75; BYTE $0x76; BYTE $0x77
|
||||
BYTE $0xac; BYTE $0x69; BYTE $0xed; BYTE $0xee
|
||||
BYTE $0xeb; BYTE $0xef; BYTE $0xec; BYTE $0xbf
|
||||
BYTE $0x80; BYTE $0xfd; BYTE $0xfe; BYTE $0xfb
|
||||
BYTE $0xfc; BYTE $0xba; BYTE $0xae; BYTE $0x59
|
||||
BYTE $0x44; BYTE $0x45; BYTE $0x42; BYTE $0x46
|
||||
BYTE $0x43; BYTE $0x47; BYTE $0x9c; BYTE $0x48
|
||||
BYTE $0x54; BYTE $0x51; BYTE $0x52; BYTE $0x53
|
||||
BYTE $0x58; BYTE $0x55; BYTE $0x56; BYTE $0x57
|
||||
BYTE $0x8c; BYTE $0x49; BYTE $0xcd; BYTE $0xce
|
||||
BYTE $0xcb; BYTE $0xcf; BYTE $0xcc; BYTE $0xe1
|
||||
BYTE $0x70; BYTE $0xdd; BYTE $0xde; BYTE $0xdb
|
||||
BYTE $0xdc; BYTE $0x8d; BYTE $0x8e; BYTE $0xdf
|
||||
|
||||
retry:
|
||||
WORD $0xB9931022 // TROO 2,2,b'0001'
|
||||
BVS retry
|
||||
RET
|
||||
|
||||
// func e2a(arr [] byte)
|
||||
// code page conversion from 1047 to 819
|
||||
TEXT ·E2a(SB), NOSPLIT|NOFRAME, $0
|
||||
MOVD arg_base+0(FP), R2 // pointer to arry of characters
|
||||
MOVD arg_len+8(FP), R3 // count
|
||||
XOR R0, R0
|
||||
XOR R1, R1
|
||||
BYTE $0xA7; BYTE $0x15; BYTE $0x00; BYTE $0x82 // BRAS 1,(2+(256/2))
|
||||
|
||||
// EBCDIC -> ASCII conversion table:
|
||||
BYTE $0x00; BYTE $0x01; BYTE $0x02; BYTE $0x03
|
||||
BYTE $0x9c; BYTE $0x09; BYTE $0x86; BYTE $0x7f
|
||||
BYTE $0x97; BYTE $0x8d; BYTE $0x8e; BYTE $0x0b
|
||||
BYTE $0x0c; BYTE $0x0d; BYTE $0x0e; BYTE $0x0f
|
||||
BYTE $0x10; BYTE $0x11; BYTE $0x12; BYTE $0x13
|
||||
BYTE $0x9d; BYTE $0x0a; BYTE $0x08; BYTE $0x87
|
||||
BYTE $0x18; BYTE $0x19; BYTE $0x92; BYTE $0x8f
|
||||
BYTE $0x1c; BYTE $0x1d; BYTE $0x1e; BYTE $0x1f
|
||||
BYTE $0x80; BYTE $0x81; BYTE $0x82; BYTE $0x83
|
||||
BYTE $0x84; BYTE $0x85; BYTE $0x17; BYTE $0x1b
|
||||
BYTE $0x88; BYTE $0x89; BYTE $0x8a; BYTE $0x8b
|
||||
BYTE $0x8c; BYTE $0x05; BYTE $0x06; BYTE $0x07
|
||||
BYTE $0x90; BYTE $0x91; BYTE $0x16; BYTE $0x93
|
||||
BYTE $0x94; BYTE $0x95; BYTE $0x96; BYTE $0x04
|
||||
BYTE $0x98; BYTE $0x99; BYTE $0x9a; BYTE $0x9b
|
||||
BYTE $0x14; BYTE $0x15; BYTE $0x9e; BYTE $0x1a
|
||||
BYTE $0x20; BYTE $0xa0; BYTE $0xe2; BYTE $0xe4
|
||||
BYTE $0xe0; BYTE $0xe1; BYTE $0xe3; BYTE $0xe5
|
||||
BYTE $0xe7; BYTE $0xf1; BYTE $0xa2; BYTE $0x2e
|
||||
BYTE $0x3c; BYTE $0x28; BYTE $0x2b; BYTE $0x7c
|
||||
BYTE $0x26; BYTE $0xe9; BYTE $0xea; BYTE $0xeb
|
||||
BYTE $0xe8; BYTE $0xed; BYTE $0xee; BYTE $0xef
|
||||
BYTE $0xec; BYTE $0xdf; BYTE $0x21; BYTE $0x24
|
||||
BYTE $0x2a; BYTE $0x29; BYTE $0x3b; BYTE $0x5e
|
||||
BYTE $0x2d; BYTE $0x2f; BYTE $0xc2; BYTE $0xc4
|
||||
BYTE $0xc0; BYTE $0xc1; BYTE $0xc3; BYTE $0xc5
|
||||
BYTE $0xc7; BYTE $0xd1; BYTE $0xa6; BYTE $0x2c
|
||||
BYTE $0x25; BYTE $0x5f; BYTE $0x3e; BYTE $0x3f
|
||||
BYTE $0xf8; BYTE $0xc9; BYTE $0xca; BYTE $0xcb
|
||||
BYTE $0xc8; BYTE $0xcd; BYTE $0xce; BYTE $0xcf
|
||||
BYTE $0xcc; BYTE $0x60; BYTE $0x3a; BYTE $0x23
|
||||
BYTE $0x40; BYTE $0x27; BYTE $0x3d; BYTE $0x22
|
||||
BYTE $0xd8; BYTE $0x61; BYTE $0x62; BYTE $0x63
|
||||
BYTE $0x64; BYTE $0x65; BYTE $0x66; BYTE $0x67
|
||||
BYTE $0x68; BYTE $0x69; BYTE $0xab; BYTE $0xbb
|
||||
BYTE $0xf0; BYTE $0xfd; BYTE $0xfe; BYTE $0xb1
|
||||
BYTE $0xb0; BYTE $0x6a; BYTE $0x6b; BYTE $0x6c
|
||||
BYTE $0x6d; BYTE $0x6e; BYTE $0x6f; BYTE $0x70
|
||||
BYTE $0x71; BYTE $0x72; BYTE $0xaa; BYTE $0xba
|
||||
BYTE $0xe6; BYTE $0xb8; BYTE $0xc6; BYTE $0xa4
|
||||
BYTE $0xb5; BYTE $0x7e; BYTE $0x73; BYTE $0x74
|
||||
BYTE $0x75; BYTE $0x76; BYTE $0x77; BYTE $0x78
|
||||
BYTE $0x79; BYTE $0x7a; BYTE $0xa1; BYTE $0xbf
|
||||
BYTE $0xd0; BYTE $0x5b; BYTE $0xde; BYTE $0xae
|
||||
BYTE $0xac; BYTE $0xa3; BYTE $0xa5; BYTE $0xb7
|
||||
BYTE $0xa9; BYTE $0xa7; BYTE $0xb6; BYTE $0xbc
|
||||
BYTE $0xbd; BYTE $0xbe; BYTE $0xdd; BYTE $0xa8
|
||||
BYTE $0xaf; BYTE $0x5d; BYTE $0xb4; BYTE $0xd7
|
||||
BYTE $0x7b; BYTE $0x41; BYTE $0x42; BYTE $0x43
|
||||
BYTE $0x44; BYTE $0x45; BYTE $0x46; BYTE $0x47
|
||||
BYTE $0x48; BYTE $0x49; BYTE $0xad; BYTE $0xf4
|
||||
BYTE $0xf6; BYTE $0xf2; BYTE $0xf3; BYTE $0xf5
|
||||
BYTE $0x7d; BYTE $0x4a; BYTE $0x4b; BYTE $0x4c
|
||||
BYTE $0x4d; BYTE $0x4e; BYTE $0x4f; BYTE $0x50
|
||||
BYTE $0x51; BYTE $0x52; BYTE $0xb9; BYTE $0xfb
|
||||
BYTE $0xfc; BYTE $0xf9; BYTE $0xfa; BYTE $0xff
|
||||
BYTE $0x5c; BYTE $0xf7; BYTE $0x53; BYTE $0x54
|
||||
BYTE $0x55; BYTE $0x56; BYTE $0x57; BYTE $0x58
|
||||
BYTE $0x59; BYTE $0x5a; BYTE $0xb2; BYTE $0xd4
|
||||
BYTE $0xd6; BYTE $0xd2; BYTE $0xd3; BYTE $0xd5
|
||||
BYTE $0x30; BYTE $0x31; BYTE $0x32; BYTE $0x33
|
||||
BYTE $0x34; BYTE $0x35; BYTE $0x36; BYTE $0x37
|
||||
BYTE $0x38; BYTE $0x39; BYTE $0xb3; BYTE $0xdb
|
||||
BYTE $0xdc; BYTE $0xd9; BYTE $0xda; BYTE $0x9f
|
||||
|
||||
retry:
|
||||
WORD $0xB9931022 // TROO 2,2,b'0001'
|
||||
BVS retry
|
||||
RET
|
||||
220
vendor/golang.org/x/sys/unix/epoll_zos.go
generated
vendored
220
vendor/golang.org/x/sys/unix/epoll_zos.go
generated
vendored
|
|
@ -1,220 +0,0 @@
|
|||
// Copyright 2020 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 zos && s390x
|
||||
|
||||
package unix
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
// This file simulates epoll on z/OS using poll.
|
||||
|
||||
// Analogous to epoll_event on Linux.
|
||||
// TODO(neeilan): Pad is because the Linux kernel expects a 96-bit struct. We never pass this to the kernel; remove?
|
||||
type EpollEvent struct {
|
||||
Events uint32
|
||||
Fd int32
|
||||
Pad int32
|
||||
}
|
||||
|
||||
const (
|
||||
EPOLLERR = 0x8
|
||||
EPOLLHUP = 0x10
|
||||
EPOLLIN = 0x1
|
||||
EPOLLMSG = 0x400
|
||||
EPOLLOUT = 0x4
|
||||
EPOLLPRI = 0x2
|
||||
EPOLLRDBAND = 0x80
|
||||
EPOLLRDNORM = 0x40
|
||||
EPOLLWRBAND = 0x200
|
||||
EPOLLWRNORM = 0x100
|
||||
EPOLL_CTL_ADD = 0x1
|
||||
EPOLL_CTL_DEL = 0x2
|
||||
EPOLL_CTL_MOD = 0x3
|
||||
// The following constants are part of the epoll API, but represent
|
||||
// currently unsupported functionality on z/OS.
|
||||
// EPOLL_CLOEXEC = 0x80000
|
||||
// EPOLLET = 0x80000000
|
||||
// EPOLLONESHOT = 0x40000000
|
||||
// EPOLLRDHUP = 0x2000 // Typically used with edge-triggered notis
|
||||
// EPOLLEXCLUSIVE = 0x10000000 // Exclusive wake-up mode
|
||||
// EPOLLWAKEUP = 0x20000000 // Relies on Linux's BLOCK_SUSPEND capability
|
||||
)
|
||||
|
||||
// TODO(neeilan): We can eliminate these epToPoll / pToEpoll calls by using identical mask values for POLL/EPOLL
|
||||
// constants where possible The lower 16 bits of epoll events (uint32) can fit any system poll event (int16).
|
||||
|
||||
// epToPollEvt converts epoll event field to poll equivalent.
|
||||
// In epoll, Events is a 32-bit field, while poll uses 16 bits.
|
||||
func epToPollEvt(events uint32) int16 {
|
||||
var ep2p = map[uint32]int16{
|
||||
EPOLLIN: POLLIN,
|
||||
EPOLLOUT: POLLOUT,
|
||||
EPOLLHUP: POLLHUP,
|
||||
EPOLLPRI: POLLPRI,
|
||||
EPOLLERR: POLLERR,
|
||||
}
|
||||
|
||||
var pollEvts int16 = 0
|
||||
for epEvt, pEvt := range ep2p {
|
||||
if (events & epEvt) != 0 {
|
||||
pollEvts |= pEvt
|
||||
}
|
||||
}
|
||||
|
||||
return pollEvts
|
||||
}
|
||||
|
||||
// pToEpollEvt converts 16 bit poll event bitfields to 32-bit epoll event fields.
|
||||
func pToEpollEvt(revents int16) uint32 {
|
||||
var p2ep = map[int16]uint32{
|
||||
POLLIN: EPOLLIN,
|
||||
POLLOUT: EPOLLOUT,
|
||||
POLLHUP: EPOLLHUP,
|
||||
POLLPRI: EPOLLPRI,
|
||||
POLLERR: EPOLLERR,
|
||||
}
|
||||
|
||||
var epollEvts uint32 = 0
|
||||
for pEvt, epEvt := range p2ep {
|
||||
if (revents & pEvt) != 0 {
|
||||
epollEvts |= epEvt
|
||||
}
|
||||
}
|
||||
|
||||
return epollEvts
|
||||
}
|
||||
|
||||
// Per-process epoll implementation.
|
||||
type epollImpl struct {
|
||||
mu sync.Mutex
|
||||
epfd2ep map[int]*eventPoll
|
||||
nextEpfd int
|
||||
}
|
||||
|
||||
// eventPoll holds a set of file descriptors being watched by the process. A process can have multiple epoll instances.
|
||||
// On Linux, this is an in-kernel data structure accessed through a fd.
|
||||
type eventPoll struct {
|
||||
mu sync.Mutex
|
||||
fds map[int]*EpollEvent
|
||||
}
|
||||
|
||||
// epoll impl for this process.
|
||||
var impl epollImpl = epollImpl{
|
||||
epfd2ep: make(map[int]*eventPoll),
|
||||
nextEpfd: 0,
|
||||
}
|
||||
|
||||
func (e *epollImpl) epollcreate(size int) (epfd int, err error) {
|
||||
e.mu.Lock()
|
||||
defer e.mu.Unlock()
|
||||
epfd = e.nextEpfd
|
||||
e.nextEpfd++
|
||||
|
||||
e.epfd2ep[epfd] = &eventPoll{
|
||||
fds: make(map[int]*EpollEvent),
|
||||
}
|
||||
return epfd, nil
|
||||
}
|
||||
|
||||
func (e *epollImpl) epollcreate1(flag int) (fd int, err error) {
|
||||
return e.epollcreate(4)
|
||||
}
|
||||
|
||||
func (e *epollImpl) epollctl(epfd int, op int, fd int, event *EpollEvent) (err error) {
|
||||
e.mu.Lock()
|
||||
defer e.mu.Unlock()
|
||||
|
||||
ep, ok := e.epfd2ep[epfd]
|
||||
if !ok {
|
||||
|
||||
return EBADF
|
||||
}
|
||||
|
||||
switch op {
|
||||
case EPOLL_CTL_ADD:
|
||||
// TODO(neeilan): When we make epfds and fds disjoint, detect epoll
|
||||
// loops here (instances watching each other) and return ELOOP.
|
||||
if _, ok := ep.fds[fd]; ok {
|
||||
return EEXIST
|
||||
}
|
||||
ep.fds[fd] = event
|
||||
case EPOLL_CTL_MOD:
|
||||
if _, ok := ep.fds[fd]; !ok {
|
||||
return ENOENT
|
||||
}
|
||||
ep.fds[fd] = event
|
||||
case EPOLL_CTL_DEL:
|
||||
if _, ok := ep.fds[fd]; !ok {
|
||||
return ENOENT
|
||||
}
|
||||
delete(ep.fds, fd)
|
||||
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Must be called while holding ep.mu
|
||||
func (ep *eventPoll) getFds() []int {
|
||||
fds := make([]int, len(ep.fds))
|
||||
for fd := range ep.fds {
|
||||
fds = append(fds, fd)
|
||||
}
|
||||
return fds
|
||||
}
|
||||
|
||||
func (e *epollImpl) epollwait(epfd int, events []EpollEvent, msec int) (n int, err error) {
|
||||
e.mu.Lock() // in [rare] case of concurrent epollcreate + epollwait
|
||||
ep, ok := e.epfd2ep[epfd]
|
||||
|
||||
if !ok {
|
||||
e.mu.Unlock()
|
||||
return 0, EBADF
|
||||
}
|
||||
|
||||
pollfds := make([]PollFd, 4)
|
||||
for fd, epollevt := range ep.fds {
|
||||
pollfds = append(pollfds, PollFd{Fd: int32(fd), Events: epToPollEvt(epollevt.Events)})
|
||||
}
|
||||
e.mu.Unlock()
|
||||
|
||||
n, err = Poll(pollfds, msec)
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
|
||||
i := 0
|
||||
for _, pFd := range pollfds {
|
||||
if pFd.Revents != 0 {
|
||||
events[i] = EpollEvent{Fd: pFd.Fd, Events: pToEpollEvt(pFd.Revents)}
|
||||
i++
|
||||
}
|
||||
|
||||
if i == n {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func EpollCreate(size int) (fd int, err error) {
|
||||
return impl.epollcreate(size)
|
||||
}
|
||||
|
||||
func EpollCreate1(flag int) (fd int, err error) {
|
||||
return impl.epollcreate1(flag)
|
||||
}
|
||||
|
||||
func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) {
|
||||
return impl.epollctl(epfd, op, fd, event)
|
||||
}
|
||||
|
||||
// Because EpollWait mutates events, the caller is expected to coordinate
|
||||
// concurrent access if calling with the same epfd from multiple goroutines.
|
||||
func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
|
||||
return impl.epollwait(epfd, events, msec)
|
||||
}
|
||||
163
vendor/golang.org/x/sys/unix/fstatfs_zos.go
generated
vendored
163
vendor/golang.org/x/sys/unix/fstatfs_zos.go
generated
vendored
|
|
@ -1,163 +0,0 @@
|
|||
// Copyright 2020 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 zos && s390x
|
||||
|
||||
package unix
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// This file simulates fstatfs on z/OS using fstatvfs and w_getmntent.
|
||||
|
||||
func Fstatfs(fd int, stat *Statfs_t) (err error) {
|
||||
var stat_v Statvfs_t
|
||||
err = Fstatvfs(fd, &stat_v)
|
||||
if err == nil {
|
||||
// populate stat
|
||||
stat.Type = 0
|
||||
stat.Bsize = stat_v.Bsize
|
||||
stat.Blocks = stat_v.Blocks
|
||||
stat.Bfree = stat_v.Bfree
|
||||
stat.Bavail = stat_v.Bavail
|
||||
stat.Files = stat_v.Files
|
||||
stat.Ffree = stat_v.Ffree
|
||||
stat.Fsid = stat_v.Fsid
|
||||
stat.Namelen = stat_v.Namemax
|
||||
stat.Frsize = stat_v.Frsize
|
||||
stat.Flags = stat_v.Flag
|
||||
for passn := 0; passn < 5; passn++ {
|
||||
switch passn {
|
||||
case 0:
|
||||
err = tryGetmntent64(stat)
|
||||
break
|
||||
case 1:
|
||||
err = tryGetmntent128(stat)
|
||||
break
|
||||
case 2:
|
||||
err = tryGetmntent256(stat)
|
||||
break
|
||||
case 3:
|
||||
err = tryGetmntent512(stat)
|
||||
break
|
||||
case 4:
|
||||
err = tryGetmntent1024(stat)
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
//proceed to return if: err is nil (found), err is nonnil but not ERANGE (another error occurred)
|
||||
if err == nil || err != nil && err != ERANGE {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func tryGetmntent64(stat *Statfs_t) (err error) {
|
||||
var mnt_ent_buffer struct {
|
||||
header W_Mnth
|
||||
filesys_info [64]W_Mntent
|
||||
}
|
||||
var buffer_size int = int(unsafe.Sizeof(mnt_ent_buffer))
|
||||
fs_count, err := W_Getmntent((*byte)(unsafe.Pointer(&mnt_ent_buffer)), buffer_size)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = ERANGE //return ERANGE if no match is found in this batch
|
||||
for i := 0; i < fs_count; i++ {
|
||||
if stat.Fsid == uint64(mnt_ent_buffer.filesys_info[i].Dev) {
|
||||
stat.Type = uint32(mnt_ent_buffer.filesys_info[i].Fstname[0])
|
||||
err = nil
|
||||
break
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func tryGetmntent128(stat *Statfs_t) (err error) {
|
||||
var mnt_ent_buffer struct {
|
||||
header W_Mnth
|
||||
filesys_info [128]W_Mntent
|
||||
}
|
||||
var buffer_size int = int(unsafe.Sizeof(mnt_ent_buffer))
|
||||
fs_count, err := W_Getmntent((*byte)(unsafe.Pointer(&mnt_ent_buffer)), buffer_size)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = ERANGE //return ERANGE if no match is found in this batch
|
||||
for i := 0; i < fs_count; i++ {
|
||||
if stat.Fsid == uint64(mnt_ent_buffer.filesys_info[i].Dev) {
|
||||
stat.Type = uint32(mnt_ent_buffer.filesys_info[i].Fstname[0])
|
||||
err = nil
|
||||
break
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func tryGetmntent256(stat *Statfs_t) (err error) {
|
||||
var mnt_ent_buffer struct {
|
||||
header W_Mnth
|
||||
filesys_info [256]W_Mntent
|
||||
}
|
||||
var buffer_size int = int(unsafe.Sizeof(mnt_ent_buffer))
|
||||
fs_count, err := W_Getmntent((*byte)(unsafe.Pointer(&mnt_ent_buffer)), buffer_size)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = ERANGE //return ERANGE if no match is found in this batch
|
||||
for i := 0; i < fs_count; i++ {
|
||||
if stat.Fsid == uint64(mnt_ent_buffer.filesys_info[i].Dev) {
|
||||
stat.Type = uint32(mnt_ent_buffer.filesys_info[i].Fstname[0])
|
||||
err = nil
|
||||
break
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func tryGetmntent512(stat *Statfs_t) (err error) {
|
||||
var mnt_ent_buffer struct {
|
||||
header W_Mnth
|
||||
filesys_info [512]W_Mntent
|
||||
}
|
||||
var buffer_size int = int(unsafe.Sizeof(mnt_ent_buffer))
|
||||
fs_count, err := W_Getmntent((*byte)(unsafe.Pointer(&mnt_ent_buffer)), buffer_size)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = ERANGE //return ERANGE if no match is found in this batch
|
||||
for i := 0; i < fs_count; i++ {
|
||||
if stat.Fsid == uint64(mnt_ent_buffer.filesys_info[i].Dev) {
|
||||
stat.Type = uint32(mnt_ent_buffer.filesys_info[i].Fstname[0])
|
||||
err = nil
|
||||
break
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func tryGetmntent1024(stat *Statfs_t) (err error) {
|
||||
var mnt_ent_buffer struct {
|
||||
header W_Mnth
|
||||
filesys_info [1024]W_Mntent
|
||||
}
|
||||
var buffer_size int = int(unsafe.Sizeof(mnt_ent_buffer))
|
||||
fs_count, err := W_Getmntent((*byte)(unsafe.Pointer(&mnt_ent_buffer)), buffer_size)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = ERANGE //return ERANGE if no match is found in this batch
|
||||
for i := 0; i < fs_count; i++ {
|
||||
if stat.Fsid == uint64(mnt_ent_buffer.filesys_info[i].Dev) {
|
||||
stat.Type = uint32(mnt_ent_buffer.filesys_info[i].Fstname[0])
|
||||
err = nil
|
||||
break
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Reference in a new issue