mirror of
https://github.com/k3s-io/k3s.git
synced 2024-06-07 19:41:36 +00:00
Update vendor
This commit is contained in:
parent
62c62cc7b4
commit
fa08d6076c
482
trash.lock
482
trash.lock
@ -1,246 +1,294 @@
|
|||||||
package: package=github.com/rancher/rio
|
package: package=github.com/rancher/k3s
|
||||||
import:
|
import:
|
||||||
|
- package: github.com/BurntSushi/toml
|
||||||
|
version: a368813c5e648fee92e5f6c30e3944ff9d5e8895
|
||||||
|
- package: github.com/Microsoft/go-winio
|
||||||
|
version: v0.4.11
|
||||||
|
- package: github.com/Microsoft/hcsshim
|
||||||
|
version: v0.8.3
|
||||||
|
- package: github.com/alexflint/go-filemutex
|
||||||
|
version: 72bdc8eae2aef913234599b837f5dda445ca9bd9
|
||||||
|
- package: github.com/beorn7/perks
|
||||||
|
version: 4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9
|
||||||
|
- package: github.com/blang/semver
|
||||||
|
version: v3.1.0
|
||||||
|
- package: github.com/containerd/cgroups
|
||||||
|
version: 5e610833b72089b37d0e615de9a92dfc043757c2
|
||||||
|
- package: github.com/containerd/console
|
||||||
|
version: c12b1e7919c14469339a5d38f2f8ed9b64a9de23
|
||||||
|
- package: github.com/containerd/containerd
|
||||||
|
version: v1.2.1
|
||||||
|
- package: github.com/containerd/continuity
|
||||||
|
version: bd77b46c8352f74eb12c85bdc01f4b90f69d66b4
|
||||||
|
- package: github.com/containerd/cri
|
||||||
|
version: 0ca1e3c2b73b5c38e72f29bb76338d0078b23d6c
|
||||||
|
- package: github.com/containerd/fifo
|
||||||
|
version: 3d5202aec260678c48179c56f40e6f38a095738c
|
||||||
|
- package: github.com/containerd/go-cni
|
||||||
|
version: 40bcf8ec8acd7372be1d77031d585d5d8e561c90
|
||||||
|
- package: github.com/containerd/go-runc
|
||||||
|
version: 5a6d9f37cfa36b15efba46dc7ea349fa9b7143c3
|
||||||
|
- package: github.com/containerd/ttrpc
|
||||||
|
version: 2a805f71863501300ae1976d29f0454ae003e85a
|
||||||
|
- package: github.com/containerd/typeurl
|
||||||
|
version: a93fcdb778cd272c6e9b3028b2f42d813e785d40
|
||||||
|
- package: github.com/containernetworking/cni
|
||||||
|
version: v0.6.0
|
||||||
|
- package: github.com/containernetworking/plugins
|
||||||
|
version: 9810b7d5137b171c4e07ce59bb18be9feccec557
|
||||||
|
repo: https://github.com/ibuildthecloud/plugins.git
|
||||||
- package: github.com/coreos/flannel
|
- package: github.com/coreos/flannel
|
||||||
version: 39af3d7e46f2efa156644e247bdcf3b5bc5f1394
|
version: 3d7cff78e2ca4cade87c6c7d44adf27fe3de2709
|
||||||
|
repo: https://github.com/ibuildthecloud/flannel.git
|
||||||
|
- package: github.com/coreos/go-iptables
|
||||||
|
version: 47f22b0dd3355c0ba570ba12b0b8a36bf214c04b
|
||||||
|
- package: github.com/coreos/go-systemd
|
||||||
|
version: 48702e0da86bd25e76cfef347e2adeb434a0d0a6
|
||||||
|
- package: github.com/davecgh/go-spew
|
||||||
|
version: v1.1.0
|
||||||
|
- package: github.com/docker/distribution
|
||||||
|
version: b38e5838b7b2f2ad48e06ec4b500011976080621
|
||||||
|
- package: github.com/docker/go-events
|
||||||
|
version: 9461782956ad83b30282bf90e31fa6a70c255ba9
|
||||||
|
- package: github.com/docker/go-metrics
|
||||||
|
version: 4ea375f7759c82740c893fc030bc37088d2ec098
|
||||||
|
- package: github.com/docker/go-units
|
||||||
|
version: v0.3.1
|
||||||
|
- package: github.com/docker/spdystream
|
||||||
|
version: 449fdfce4d962303d702fec724ef0ad181c92528
|
||||||
|
- package: github.com/emicklei/go-restful
|
||||||
|
version: v2.2.1
|
||||||
|
- package: github.com/ghodss/yaml
|
||||||
|
version: v1.0.0
|
||||||
|
- package: github.com/godbus/dbus
|
||||||
|
version: c7fdd8b5cd55e87b4e1f4e372cdb1db61dd6c66f
|
||||||
|
- package: github.com/gogo/googleapis
|
||||||
|
version: 08a7655d27152912db7aaf4f983275eaf8d128ef
|
||||||
|
- package: github.com/gogo/protobuf
|
||||||
|
version: v1.0.0
|
||||||
|
- package: github.com/golang/protobuf
|
||||||
|
version: v1.1.0
|
||||||
|
- package: github.com/google/gofuzz
|
||||||
|
version: 44d81051d367757e1c7c6a5a86423ece9afcf63c
|
||||||
- package: github.com/gorilla/mux
|
- package: github.com/gorilla/mux
|
||||||
version: v1.6.2
|
version: v1.6.2
|
||||||
- package: github.com/gorilla/websocket
|
- package: github.com/gorilla/websocket
|
||||||
version: v1.2.0
|
version: v1.2.0
|
||||||
|
- package: github.com/grpc-ecosystem/go-grpc-prometheus
|
||||||
|
version: 6b7015e65d366bf3f19b2b2a000a831940f0f7e0
|
||||||
|
- package: github.com/hashicorp/errwrap
|
||||||
|
version: 7554cd9344cec97297fa6649b055a8c98c2a1e55
|
||||||
|
- package: github.com/hashicorp/go-multierror
|
||||||
|
version: ed905158d87462226a13fe39ddf685ea65f1c11f
|
||||||
|
- package: github.com/j-keck/arping
|
||||||
|
version: 2cf9dc699c5640a7e2c81403a44127bf28033600
|
||||||
|
- package: github.com/json-iterator/go
|
||||||
|
version: 1.1.5
|
||||||
- package: github.com/mattn/go-sqlite3
|
- package: github.com/mattn/go-sqlite3
|
||||||
version: v1.9.0
|
version: v1.9.0
|
||||||
- package: github.com/natefinch/lumberjack
|
- package: github.com/matttproud/golang_protobuf_extensions
|
||||||
version: aee4629129445bbdfb69aa565537dcfa16544311
|
|
||||||
- package: github.com/rancher/norman
|
|
||||||
version: 5726ebfba191eef161af9638e85bf4fcaa58e008
|
|
||||||
repo: https://github.com/ibuildthecloud/norman.git
|
|
||||||
- package: github.com/urfave/cli
|
|
||||||
version: 8e01ec4cd3e2d84ab2fe90d8210528ffbb06d8ff
|
|
||||||
- package: golang.org/x/crypto
|
|
||||||
version: a49355c7e3f8fe157a85be2f77e6e269a0f89602
|
|
||||||
- package: golang.org/x/sync
|
|
||||||
version: 450f422ab23cf9881c94e2db30cac0eb1b7cf80c
|
|
||||||
- package: gopkg.in/freddierice/go-losetup.v1
|
|
||||||
version: fc9adea44124401d8bfef3a97eaf61b5d44cc2c6
|
|
||||||
- package: k8s.io/kubernetes
|
|
||||||
version: a1d7d1b140f43b6503311ffc1dd80017c553bf8e
|
|
||||||
repo: file:///home/darren/src/kuberlite/.git
|
|
||||||
transitive: true
|
|
||||||
staging: true
|
|
||||||
- package: github.com/pborman/uuid
|
|
||||||
version: ca53cad383cad2479bbba7f7a1a05797ec1386e4
|
|
||||||
- package: github.com/prometheus/client_model
|
|
||||||
version: model-0.0.2-12-gfa8ad6fec33561
|
|
||||||
- package: github.com/prometheus/common
|
|
||||||
version: 13ba4ddd0caa9c28ca7b7bffe1dfa9ed8d5ef207
|
|
||||||
- package: github.com/golang/protobuf
|
|
||||||
version: v1.1.0
|
|
||||||
- package: golang.org/x/sys
|
|
||||||
version: 95c6576299259db960f6c5b9b69ea52422860fce
|
|
||||||
- package: github.com/ugorji/go
|
|
||||||
version: bdcc60b419d136a85cdf2e7cbcac34b3f1cd6e57
|
|
||||||
- package: github.com/vishvananda/netns
|
|
||||||
version: be1fbeda19366dea804f00efff2dd73a1642fdcc
|
|
||||||
- package: gopkg.in/natefinch/lumberjack.v2
|
|
||||||
version: v1.0-16-g20b71e5b60d756
|
|
||||||
- package: vbom.ml/util
|
|
||||||
version: db5cfe13f5cc80a4990d98e2e1b0707a4d1a5394
|
|
||||||
- package: github.com/exponent-io/jsonpath
|
|
||||||
version: d6023ce2651d8eafb5c75bb0c7167536102ec9f5
|
|
||||||
- package: github.com/google/certificate-transparency-go
|
|
||||||
version: v1.0.21
|
|
||||||
- package: github.com/coreos/go-semver
|
|
||||||
version: v0.2.0-9-ge214231b295a8e
|
|
||||||
- package: github.com/docker/spdystream
|
|
||||||
version: 449fdfce4d962303d702fec724ef0ad181c92528
|
|
||||||
- package: github.com/renstrom/dedent
|
|
||||||
version: v1.0.0-3-g020d11c3b9c0c7
|
|
||||||
- package: golang.org/x/text
|
|
||||||
version: b19bf474d317b857955b12035d2c5acb57ce8b01
|
|
||||||
- package: github.com/container-storage-interface/spec
|
|
||||||
version: v1.0.0
|
version: v1.0.0
|
||||||
- package: github.com/evanphx/json-patch
|
|
||||||
version: v4.0.0-3-g36442dbdb58521
|
|
||||||
- package: github.com/sigma/go-inotify
|
|
||||||
version: c87b6cf5033d2c6486046f045eeebdc3d910fd38
|
|
||||||
- package: github.com/blang/semver
|
|
||||||
version: v3.5.0
|
|
||||||
- package: github.com/docker/libnetwork
|
|
||||||
version: v0.8.0-dev.2-1265-ga9cd636e378982
|
|
||||||
- package: github.com/fatih/camelcase
|
|
||||||
version: f6a740d52f961c60348ebb109adde9f4635d7540
|
|
||||||
- package: github.com/prometheus/client_golang
|
|
||||||
version: v0.8.0-83-ge7e903064f5e9e
|
|
||||||
- package: github.com/shurcooL/sanitized_anchor_name
|
|
||||||
version: 10ef21a441db47d8b13ebcc5fd2310f636973c77
|
|
||||||
- package: github.com/spf13/cobra
|
|
||||||
version: v0.0.1-34-gc439c4fa093711
|
|
||||||
- package: github.com/docker/docker
|
|
||||||
version: docs-v1.12.0-rc4-2016-07-15-9510-ga9fbbdc8dd8794
|
|
||||||
- package: golang.org/x/net
|
|
||||||
version: 0ed95abb35c445290478a5348a7b38bb154135fd
|
|
||||||
- package: github.com/json-iterator/go
|
|
||||||
version: 1.1.4
|
|
||||||
- package: github.com/opencontainers/runc
|
|
||||||
version: v1.0.0-rc5-46-g871ba2e58e2431
|
|
||||||
- package: gopkg.in/inf.v0
|
|
||||||
version: v0.9.0
|
|
||||||
- package: github.com/containerd/containerd
|
|
||||||
version: v1.0.2
|
|
||||||
- package: github.com/ghodss/yaml
|
|
||||||
version: v1.0.0-4-gc7ce16629ff4cd
|
|
||||||
- package: github.com/ibuildthecloud/kvsql
|
|
||||||
version: 6bb3d252056655760ed8ca6557d6d5e607b361d2
|
|
||||||
- package: google.golang.org/genproto
|
|
||||||
version: 09f6ed296fc66555a25fe4ce95173148778dfa85
|
|
||||||
- package: github.com/Microsoft/hcsshim
|
|
||||||
version: v0.6.11
|
|
||||||
- package: google.golang.org/grpc
|
|
||||||
version: v1.13.0
|
|
||||||
- package: github.com/gregjones/httpcache
|
|
||||||
version: 787624de3eb7bd915c329cba748687a3b22666a6
|
|
||||||
- package: github.com/golang/groupcache
|
|
||||||
version: 02826c3e79038b59d737d3b1c0a1d937f71a4433
|
|
||||||
- package: github.com/karrick/godirwalk
|
|
||||||
version: v1.7.5
|
|
||||||
- package: github.com/mattn/go-shellwords
|
|
||||||
version: v1.0.3-20-gf8471b0a71ded0
|
|
||||||
- package: github.com/google/gofuzz
|
|
||||||
version: 44d81051d367757e1c7c6a5a86423ece9afcf63c
|
|
||||||
- package: github.com/modern-go/concurrent
|
- package: github.com/modern-go/concurrent
|
||||||
version: 1.0.3
|
version: 1.0.3
|
||||||
|
- package: github.com/modern-go/reflect2
|
||||||
|
version: 1.0.1
|
||||||
|
- package: github.com/natefinch/lumberjack
|
||||||
|
version: aee4629129445bbdfb69aa565537dcfa16544311
|
||||||
|
- package: github.com/opencontainers/go-digest
|
||||||
|
version: c9281466c8b2f606084ac71339773efd177436e7
|
||||||
|
- package: github.com/opencontainers/image-spec
|
||||||
|
version: v1.0.1
|
||||||
|
- package: github.com/opencontainers/runc
|
||||||
|
version: 96ec2177ae841256168fcf76954f7177af9446eb
|
||||||
|
- package: github.com/opencontainers/runtime-spec
|
||||||
|
version: 5684b8af48c1ac3b1451fa499724e30e3c20a294
|
||||||
|
- package: github.com/opencontainers/runtime-tools
|
||||||
|
version: v0.6.0
|
||||||
|
- package: github.com/opencontainers/selinux
|
||||||
|
version: b6fa367ed7f534f9ba25391cc2d467085dbb445a
|
||||||
|
- package: github.com/pkg/errors
|
||||||
|
version: v0.8.0
|
||||||
|
- package: github.com/rancher/norman
|
||||||
|
version: 29915f8336c0a242560a9fef1d11bbaf04660915
|
||||||
|
repo: https://github.com/ibuildthecloud/norman.git
|
||||||
|
- package: github.com/seccomp/libseccomp-golang
|
||||||
|
version: 32f571b70023028bd57d9288c20efbcb237f3ce0
|
||||||
|
- package: github.com/sirupsen/logrus
|
||||||
|
version: v1.0.3
|
||||||
|
- package: github.com/syndtr/gocapability
|
||||||
|
version: db04d3cc01c8b54962a58ec7e491717d06cfcc16
|
||||||
|
- package: github.com/tchap/go-patricia
|
||||||
|
version: v2.2.6
|
||||||
|
- package: github.com/urfave/cli
|
||||||
|
version: 8e01ec4cd3e2d84ab2fe90d8210528ffbb06d8ff
|
||||||
|
- package: github.com/xeipuuv/gojsonpointer
|
||||||
|
version: 4e3ac2762d5f479393488629ee9370b50873b3a6
|
||||||
|
- package: github.com/xeipuuv/gojsonreference
|
||||||
|
version: bd5ef7bd5415a7ac448318e64f11a24cd21e594b
|
||||||
|
- package: github.com/xeipuuv/gojsonschema
|
||||||
|
version: 1d523034197ff1f222f6429836dd36a2457a1874
|
||||||
|
- package: go.etcd.io/bbolt
|
||||||
|
version: v1.3.1-etcd.8
|
||||||
|
- package: golang.org/x/crypto
|
||||||
|
version: a49355c7e3f8fe157a85be2f77e6e269a0f89602
|
||||||
|
- package: golang.org/x/net
|
||||||
|
version: b3756b4b77d7b13260a0a2ec658753cf48922eac
|
||||||
|
- package: golang.org/x/oauth2
|
||||||
|
version: a6bd8cefa1811bd24b86f8902872e4e8225f74c4
|
||||||
|
- package: golang.org/x/sync
|
||||||
|
version: 450f422ab23cf9881c94e2db30cac0eb1b7cf80c
|
||||||
|
- package: golang.org/x/text
|
||||||
|
version: 19e51611da83d6be54ddafce4a4af510cb3e9ea4
|
||||||
|
- package: golang.org/x/time
|
||||||
|
version: f51c12702a4d776e4c1fa9b0fabab841babae631
|
||||||
|
- package: google.golang.org/genproto
|
||||||
|
version: d80a6e20e776b0b17a324d0ba1ab50a39c8e8944
|
||||||
|
- package: google.golang.org/grpc
|
||||||
|
version: v1.12.0
|
||||||
|
- package: gopkg.in/inf.v0
|
||||||
|
version: 3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4
|
||||||
|
- package: gopkg.in/yaml.v2
|
||||||
|
version: v2.2.1
|
||||||
|
- package: k8s.io/kubernetes
|
||||||
|
version: v1.13.1-k3s2
|
||||||
|
repo: https://github.com/ibuildthecloud/k3s.git
|
||||||
|
transitive: true
|
||||||
|
staging: true
|
||||||
|
- package: github.com/Azure/go-ansiterm
|
||||||
|
version: d6e3b3328b783f23731bc4d058875b0371ff8109
|
||||||
|
- package: github.com/imdario/mergo
|
||||||
|
version: v0.3.5
|
||||||
|
- package: github.com/mxk/go-flowrate
|
||||||
|
version: cca7078d478f8520f85629ad7c68962d31ed7682
|
||||||
|
- package: github.com/russross/blackfriday
|
||||||
|
version: v1.4-2-g300106c228d52c
|
||||||
|
- package: github.com/vishvananda/netns
|
||||||
|
version: be1fbeda19366dea804f00efff2dd73a1642fdcc
|
||||||
|
- package: github.com/cloudflare/cfssl
|
||||||
|
version: 1.3.2-21-g56268a613adfed
|
||||||
- package: github.com/google/cadvisor
|
- package: github.com/google/cadvisor
|
||||||
version: 25bec0e2ace4846e5caaaf69991046c6f44c4bac
|
version: 91dab6eb91496ed68acbef68b02b34b3392ca754
|
||||||
repo: https://github.com/ibuildthecloud/cadvisor.git
|
repo: https://github.com/ibuildthecloud/cadvisor.git
|
||||||
- package: sigs.k8s.io/yaml
|
- package: github.com/miekg/dns
|
||||||
version: v1.1.0
|
version: 5d001d020961ae1c184f9f8152fdc73810481677
|
||||||
|
- package: github.com/mrunalp/fileutils
|
||||||
|
version: 4ee1cc9a80582a0c75febdd5cfa779ee4361cbca
|
||||||
|
- package: github.com/spf13/cobra
|
||||||
|
version: v0.0.1-34-gc439c4fa093711
|
||||||
- package: bitbucket.org/ww/goautoneg
|
- package: bitbucket.org/ww/goautoneg
|
||||||
version: a547fc61f48d567d5b4ec6f8aee5573d8efce11d
|
version: a547fc61f48d567d5b4ec6f8aee5573d8efce11d
|
||||||
repo: https://github.com/rancher/goautoneg.git
|
repo: https://github.com/rancher/goautoneg.git
|
||||||
- package: github.com/beorn7/perks
|
|
||||||
version: 3ac7bf7a47d159a033b107610db8a1b6575507a4
|
|
||||||
- package: github.com/sirupsen/logrus
|
|
||||||
version: v1.0.3-11-g89742aefa4b206
|
|
||||||
- package: gopkg.in/square/go-jose.v2
|
|
||||||
version: v2.1.6-4-g89060dee6a84df
|
|
||||||
- package: k8s.io/utils
|
|
||||||
version: 66066c83e385e385ccc3c964b44fd7dcd413d0ed
|
|
||||||
- package: github.com/daviddengcn/go-colortext
|
|
||||||
version: 511bcaf42ccd42c38aba7427b6673277bf19e2a1
|
|
||||||
- package: github.com/prometheus/procfs
|
|
||||||
version: 65c1f6f8f0fc1e2185eb9863a3bc751496404259
|
|
||||||
- package: golang.org/x/tools
|
|
||||||
version: 2382e3994d48b1d22acc2c86bcad0a2aff028e32
|
|
||||||
- package: github.com/jteeuwen/go-bindata
|
|
||||||
version: v3.0.7-72-ga0ff2567cfb709
|
|
||||||
- package: github.com/modern-go/reflect2
|
|
||||||
version: v1.0.1
|
|
||||||
- package: golang.org/x/time
|
|
||||||
version: f51c12702a4d776e4c1fa9b0fabab841babae631
|
|
||||||
- package: k8s.io/gengo
|
|
||||||
version: 51747d6e00da1fc578d5a333a93bb2abcbce7a95
|
|
||||||
- package: github.com/euank/go-kmsg-parser
|
|
||||||
version: v2.0.0
|
|
||||||
- package: github.com/chai2010/gettext-go
|
|
||||||
version: c6fed771bfd517099caf0f7a961671fa8ed08723
|
|
||||||
- package: github.com/davecgh/go-spew
|
|
||||||
version: v1.1.0-1-g782f4967f2dc45
|
|
||||||
- package: github.com/docker/distribution
|
|
||||||
version: v2.6.0-rc.1-209-gedc3ab29cdff86
|
|
||||||
- package: github.com/docker/go-units
|
|
||||||
version: v0.3.1-11-g9e638d38cf6977
|
|
||||||
- package: github.com/mindprince/gonvml
|
|
||||||
version: fee913ce8fb235edf54739d259ca0ecc226c7b8a
|
|
||||||
- package: github.com/MakeNowJust/heredoc
|
|
||||||
version: bb23615498cded5e105af4ce27de75b089cbe851
|
|
||||||
- package: github.com/syndtr/gocapability
|
|
||||||
version: e7cb7fa329f456b3855136a2642b197bad7366ba
|
|
||||||
- package: k8s.io/klog
|
|
||||||
version: 8139d8cb77af419532b33dfa7dd09fbc5f1d344f
|
|
||||||
- package: github.com/emicklei/go-restful
|
|
||||||
version: 2.2.0-4-gff4f55a206334e
|
|
||||||
- package: github.com/google/btree
|
|
||||||
version: 7d79101e329e5a3adf994758c578dab82b90c017
|
|
||||||
- package: github.com/Azure/go-ansiterm
|
|
||||||
version: d6e3b3328b783f23731bc4d058875b0371ff8109
|
|
||||||
- package: github.com/containerd/console
|
|
||||||
version: 84eeaae905fa414d03e07bcd6c8d3f19e7cf180e
|
|
||||||
- package: github.com/pkg/errors
|
|
||||||
version: v0.8.0
|
|
||||||
- package: github.com/googleapis/gnostic
|
|
||||||
version: 0c5108395e2debce0d731cf0287ddf7242066aba
|
|
||||||
- package: github.com/imdario/mergo
|
|
||||||
version: v0.3.5
|
|
||||||
- package: github.com/robfig/cron
|
|
||||||
version: v1-53-gdf38d32658d878
|
|
||||||
- package: github.com/JeffAshton/win_pdh
|
- package: github.com/JeffAshton/win_pdh
|
||||||
version: 76bb4ee9f0ab50f77826f2a2ee7fb9d3880d6ec2
|
version: 76bb4ee9f0ab50f77826f2a2ee7fb9d3880d6ec2
|
||||||
- package: github.com/armon/circbuf
|
- package: github.com/MakeNowJust/heredoc
|
||||||
version: bbbad097214e2918d8543d5201d12bfd7bca254d
|
version: bb23615498cded5e105af4ce27de75b089cbe851
|
||||||
- package: k8s.io/heapster
|
- package: github.com/container-storage-interface/spec
|
||||||
version: v1.2.0-beta.1
|
|
||||||
- package: github.com/matttproud/golang_protobuf_extensions
|
|
||||||
version: v1.0.1
|
|
||||||
- package: github.com/mrunalp/fileutils
|
|
||||||
version: 4ee1cc9a80582a0c75febdd5cfa779ee4361cbca
|
|
||||||
- package: github.com/opencontainers/runtime-spec
|
|
||||||
version: v1.0.0
|
version: v1.0.0
|
||||||
|
- package: github.com/mindprince/gonvml
|
||||||
|
version: fee913ce8fb235edf54739d259ca0ecc226c7b8a
|
||||||
|
- package: k8s.io/klog
|
||||||
|
version: 8139d8cb77af419532b33dfa7dd09fbc5f1d344f
|
||||||
|
- package: github.com/exponent-io/jsonpath
|
||||||
|
version: d6023ce2651d8eafb5c75bb0c7167536102ec9f5
|
||||||
|
- package: github.com/mattn/go-shellwords
|
||||||
|
version: v1.0.3-20-gf8471b0a71ded0
|
||||||
|
- package: sigs.k8s.io/yaml
|
||||||
|
version: v1.1.0
|
||||||
|
- package: vbom.ml/util
|
||||||
|
version: db5cfe13f5cc80a4990d98e2e1b0707a4d1a5394
|
||||||
- package: github.com/fsnotify/fsnotify
|
- package: github.com/fsnotify/fsnotify
|
||||||
version: v1.3.1-1-gf12c6236fe7b5c
|
version: v1.3.1-1-gf12c6236fe7b5c
|
||||||
- package: github.com/mistifyio/go-zfs
|
- package: github.com/gregjones/httpcache
|
||||||
version: v2.1.1-5-g1b4ae6fb4e77b0
|
version: 787624de3eb7bd915c329cba748687a3b22666a6
|
||||||
- package: github.com/russross/blackfriday
|
- package: github.com/ibuildthecloud/kvsql
|
||||||
version: v1.4-2-g300106c228d52c
|
version: 6bb3d252056655760ed8ca6557d6d5e607b361d2
|
||||||
- package: github.com/inconshreveable/mousetrap
|
|
||||||
version: v1.0
|
|
||||||
- package: github.com/vishvananda/netlink
|
|
||||||
version: b2de5d10e38ecce8607e6b438b6d174f389a004e
|
|
||||||
- package: github.com/mitchellh/go-wordwrap
|
|
||||||
version: ad45545899c7b13c020ea92b2072220eefad42b8
|
|
||||||
- package: github.com/peterbourgon/diskv
|
|
||||||
version: v2.0.1
|
|
||||||
- package: github.com/Microsoft/go-winio
|
|
||||||
version: v0.4.5
|
|
||||||
- package: github.com/cyphar/filepath-securejoin
|
- package: github.com/cyphar/filepath-securejoin
|
||||||
version: v0.2.1-1-gae69057f2299fb
|
version: v0.2.1-1-gae69057f2299fb
|
||||||
- package: github.com/Nvveen/Gotty
|
- package: github.com/jteeuwen/go-bindata
|
||||||
version: cd527374f1e5bff4938207604a14f2e38a9cf512
|
version: v3.0.7-72-ga0ff2567cfb709
|
||||||
- package: github.com/containernetworking/cni
|
- package: github.com/armon/circbuf
|
||||||
version: v0.6.0
|
version: bbbad097214e2918d8543d5201d12bfd7bca254d
|
||||||
- package: github.com/hashicorp/golang-lru
|
|
||||||
version: a0d98a5f288019575c6d1f4bb1573fef2d1fcdc4
|
|
||||||
- package: github.com/jonboulle/clockwork
|
|
||||||
version: 72f9bd7c4e0c2a40055ab3d0f09654f730cce982
|
|
||||||
- package: github.com/seccomp/libseccomp-golang
|
|
||||||
version: 1b506fc7c24eec5a3693cdcbed40d9c226cfc6a1
|
|
||||||
- package: github.com/coreos/pkg
|
- package: github.com/coreos/pkg
|
||||||
version: v4
|
version: v4
|
||||||
- package: github.com/opencontainers/image-spec
|
|
||||||
version: v1.0.0-rc6-12-g372ad780f63454
|
|
||||||
- package: github.com/opencontainers/selinux
|
|
||||||
version: v1.0.0-rc1-5-g4a2974bf1ee960
|
|
||||||
- package: github.com/cloudflare/cfssl
|
|
||||||
version: 1.3.2-21-g56268a613adfed
|
|
||||||
- package: github.com/grpc-ecosystem/go-grpc-prometheus
|
|
||||||
version: v1.1-4-g2500245aa6110c
|
|
||||||
- package: github.com/miekg/dns
|
|
||||||
version: 5d001d020961ae1c184f9f8152fdc73810481677
|
|
||||||
- package: github.com/godbus/dbus
|
|
||||||
version: v3
|
|
||||||
- package: github.com/spf13/pflag
|
|
||||||
version: v1.0.1
|
|
||||||
- package: github.com/docker/go-connections
|
- package: github.com/docker/go-connections
|
||||||
version: v0.3.0
|
version: v0.3.0
|
||||||
- package: golang.org/x/oauth2
|
- package: github.com/peterbourgon/diskv
|
||||||
version: a6bd8cefa1811bd24b86f8902872e4e8225f74c4
|
version: v2.0.1
|
||||||
- package: github.com/gogo/protobuf
|
- package: github.com/prometheus/client_model
|
||||||
version: v0.5
|
version: model-0.0.2-12-gfa8ad6fec33561
|
||||||
- package: github.com/mxk/go-flowrate
|
- package: k8s.io/heapster
|
||||||
version: cca7078d478f8520f85629ad7c68962d31ed7682
|
version: v1.2.0-beta.1
|
||||||
- package: github.com/coreos/go-systemd
|
- package: github.com/vishvananda/netlink
|
||||||
version: v17
|
version: b2de5d10e38ecce8607e6b438b6d174f389a004e
|
||||||
- package: github.com/opencontainers/go-digest
|
- package: github.com/chai2010/gettext-go
|
||||||
version: a6d0ee40d4207ea02364bd3b9e8e77b9159ba1eb
|
version: c6fed771bfd517099caf0f7a961671fa8ed08723
|
||||||
- package: gopkg.in/yaml.v2
|
- package: github.com/google/certificate-transparency-go
|
||||||
version: v2.2.1
|
version: v1.0.21
|
||||||
|
- package: github.com/docker/libnetwork
|
||||||
|
version: v0.8.0-dev.2-1265-ga9cd636e378982
|
||||||
|
- package: github.com/inconshreveable/mousetrap
|
||||||
|
version: v1.0
|
||||||
|
- package: github.com/mistifyio/go-zfs
|
||||||
|
version: v2.1.1-5-g1b4ae6fb4e77b0
|
||||||
|
- package: github.com/mitchellh/go-wordwrap
|
||||||
|
version: ad45545899c7b13c020ea92b2072220eefad42b8
|
||||||
|
- package: github.com/euank/go-kmsg-parser
|
||||||
|
version: v2.0.0
|
||||||
|
- package: github.com/coreos/go-semver
|
||||||
|
version: v0.2.0-9-ge214231b295a8e
|
||||||
|
- package: golang.org/x/sys
|
||||||
|
version: 95c6576299259db960f6c5b9b69ea52422860fce
|
||||||
|
- package: github.com/google/btree
|
||||||
|
version: 7d79101e329e5a3adf994758c578dab82b90c017
|
||||||
|
- package: github.com/sigma/go-inotify
|
||||||
|
version: c87b6cf5033d2c6486046f045eeebdc3d910fd38
|
||||||
|
- package: golang.org/x/tools
|
||||||
|
version: 2382e3994d48b1d22acc2c86bcad0a2aff028e32
|
||||||
|
- package: k8s.io/gengo
|
||||||
|
version: 51747d6e00da1fc578d5a333a93bb2abcbce7a95
|
||||||
|
- package: github.com/Nvveen/Gotty
|
||||||
|
version: cd527374f1e5bff4938207604a14f2e38a9cf512
|
||||||
|
- package: k8s.io/utils
|
||||||
|
version: 66066c83e385e385ccc3c964b44fd7dcd413d0ed
|
||||||
|
- package: github.com/googleapis/gnostic
|
||||||
|
version: 0c5108395e2debce0d731cf0287ddf7242066aba
|
||||||
|
- package: gopkg.in/natefinch/lumberjack.v2
|
||||||
|
version: v1.0-16-g20b71e5b60d756
|
||||||
|
- package: github.com/pborman/uuid
|
||||||
|
version: ca53cad383cad2479bbba7f7a1a05797ec1386e4
|
||||||
|
- package: github.com/prometheus/client_golang
|
||||||
|
version: v0.8.0-83-ge7e903064f5e9e
|
||||||
|
- package: github.com/docker/docker
|
||||||
|
version: docs-v1.12.0-rc4-2016-07-15-9510-ga9fbbdc8dd8794
|
||||||
|
- package: github.com/golang/groupcache
|
||||||
|
version: 02826c3e79038b59d737d3b1c0a1d937f71a4433
|
||||||
|
- package: github.com/robfig/cron
|
||||||
|
version: v1-53-gdf38d32658d878
|
||||||
|
- package: github.com/daviddengcn/go-colortext
|
||||||
|
version: 511bcaf42ccd42c38aba7427b6673277bf19e2a1
|
||||||
|
- package: github.com/ugorji/go
|
||||||
|
version: bdcc60b419d136a85cdf2e7cbcac34b3f1cd6e57
|
||||||
|
- package: github.com/prometheus/procfs
|
||||||
|
version: 65c1f6f8f0fc1e2185eb9863a3bc751496404259
|
||||||
|
- package: github.com/fatih/camelcase
|
||||||
|
version: f6a740d52f961c60348ebb109adde9f4635d7540
|
||||||
|
- package: github.com/renstrom/dedent
|
||||||
|
version: v1.0.0-3-g020d11c3b9c0c7
|
||||||
|
- package: github.com/spf13/pflag
|
||||||
|
version: v1.0.1
|
||||||
- package: github.com/coreos/etcd
|
- package: github.com/coreos/etcd
|
||||||
version: v3.3.10
|
version: v3.3.10
|
||||||
|
- package: github.com/shurcooL/sanitized_anchor_name
|
||||||
|
version: 10ef21a441db47d8b13ebcc5fd2310f636973c77
|
||||||
|
- package: gopkg.in/square/go-jose.v2
|
||||||
|
version: v2.1.6-4-g89060dee6a84df
|
||||||
|
- package: github.com/jonboulle/clockwork
|
||||||
|
version: 72f9bd7c4e0c2a40055ab3d0f09654f730cce982
|
||||||
|
- package: github.com/karrick/godirwalk
|
||||||
|
version: v1.7.5
|
||||||
|
- package: github.com/prometheus/common
|
||||||
|
version: 13ba4ddd0caa9c28ca7b7bffe1dfa9ed8d5ef207
|
||||||
|
- package: github.com/evanphx/json-patch
|
||||||
|
version: v4.0.0-3-g36442dbdb58521
|
||||||
|
- package: github.com/hashicorp/golang-lru
|
||||||
|
version: a0d98a5f288019575c6d1f4bb1573fef2d1fcdc4
|
||||||
|
13
vendor/bitbucket.org/ww/goautoneg/Makefile
generated
vendored
Normal file
13
vendor/bitbucket.org/ww/goautoneg/Makefile
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
include $(GOROOT)/src/Make.inc
|
||||||
|
|
||||||
|
TARG=bitbucket.org/ww/goautoneg
|
||||||
|
GOFILES=autoneg.go
|
||||||
|
|
||||||
|
include $(GOROOT)/src/Make.pkg
|
||||||
|
|
||||||
|
format:
|
||||||
|
gofmt -w *.go
|
||||||
|
|
||||||
|
docs:
|
||||||
|
gomake clean
|
||||||
|
godoc ${TARG} > README.txt
|
67
vendor/bitbucket.org/ww/goautoneg/README.txt
generated
vendored
Normal file
67
vendor/bitbucket.org/ww/goautoneg/README.txt
generated
vendored
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
PACKAGE
|
||||||
|
|
||||||
|
package goautoneg
|
||||||
|
import "bitbucket.org/ww/goautoneg"
|
||||||
|
|
||||||
|
HTTP Content-Type Autonegotiation.
|
||||||
|
|
||||||
|
The functions in this package implement the behaviour specified in
|
||||||
|
http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
|
||||||
|
|
||||||
|
Copyright (c) 2011, Open Knowledge Foundation Ltd.
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in
|
||||||
|
the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
|
||||||
|
Neither the name of the Open Knowledge Foundation Ltd. nor the
|
||||||
|
names of its contributors may be used to endorse or promote
|
||||||
|
products derived from this software without specific prior written
|
||||||
|
permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
|
||||||
|
FUNCTIONS
|
||||||
|
|
||||||
|
func Negotiate(header string, alternatives []string) (content_type string)
|
||||||
|
Negotiate the most appropriate content_type given the accept header
|
||||||
|
and a list of alternatives.
|
||||||
|
|
||||||
|
func ParseAccept(header string) (accept []Accept)
|
||||||
|
Parse an Accept Header string returning a sorted list
|
||||||
|
of clauses
|
||||||
|
|
||||||
|
|
||||||
|
TYPES
|
||||||
|
|
||||||
|
type Accept struct {
|
||||||
|
Type, SubType string
|
||||||
|
Q float32
|
||||||
|
Params map[string]string
|
||||||
|
}
|
||||||
|
Structure to represent a clause in an HTTP Accept Header
|
||||||
|
|
||||||
|
|
||||||
|
SUBDIRECTORIES
|
||||||
|
|
||||||
|
.hg
|
162
vendor/bitbucket.org/ww/goautoneg/autoneg.go
generated
vendored
Normal file
162
vendor/bitbucket.org/ww/goautoneg/autoneg.go
generated
vendored
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
/*
|
||||||
|
HTTP Content-Type Autonegotiation.
|
||||||
|
|
||||||
|
The functions in this package implement the behaviour specified in
|
||||||
|
http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
|
||||||
|
|
||||||
|
Copyright (c) 2011, Open Knowledge Foundation Ltd.
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in
|
||||||
|
the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
|
||||||
|
Neither the name of the Open Knowledge Foundation Ltd. nor the
|
||||||
|
names of its contributors may be used to endorse or promote
|
||||||
|
products derived from this software without specific prior written
|
||||||
|
permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
||||||
|
package goautoneg
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Structure to represent a clause in an HTTP Accept Header
|
||||||
|
type Accept struct {
|
||||||
|
Type, SubType string
|
||||||
|
Q float64
|
||||||
|
Params map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
// For internal use, so that we can use the sort interface
|
||||||
|
type accept_slice []Accept
|
||||||
|
|
||||||
|
func (accept accept_slice) Len() int {
|
||||||
|
slice := []Accept(accept)
|
||||||
|
return len(slice)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (accept accept_slice) Less(i, j int) bool {
|
||||||
|
slice := []Accept(accept)
|
||||||
|
ai, aj := slice[i], slice[j]
|
||||||
|
if ai.Q > aj.Q {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if ai.Type != "*" && aj.Type == "*" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if ai.SubType != "*" && aj.SubType == "*" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (accept accept_slice) Swap(i, j int) {
|
||||||
|
slice := []Accept(accept)
|
||||||
|
slice[i], slice[j] = slice[j], slice[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse an Accept Header string returning a sorted list
|
||||||
|
// of clauses
|
||||||
|
func ParseAccept(header string) (accept []Accept) {
|
||||||
|
parts := strings.Split(header, ",")
|
||||||
|
accept = make([]Accept, 0, len(parts))
|
||||||
|
for _, part := range parts {
|
||||||
|
part := strings.Trim(part, " ")
|
||||||
|
|
||||||
|
a := Accept{}
|
||||||
|
a.Params = make(map[string]string)
|
||||||
|
a.Q = 1.0
|
||||||
|
|
||||||
|
mrp := strings.Split(part, ";")
|
||||||
|
|
||||||
|
media_range := mrp[0]
|
||||||
|
sp := strings.Split(media_range, "/")
|
||||||
|
a.Type = strings.Trim(sp[0], " ")
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case len(sp) == 1 && a.Type == "*":
|
||||||
|
a.SubType = "*"
|
||||||
|
case len(sp) == 2:
|
||||||
|
a.SubType = strings.Trim(sp[1], " ")
|
||||||
|
default:
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(mrp) == 1 {
|
||||||
|
accept = append(accept, a)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, param := range mrp[1:] {
|
||||||
|
sp := strings.SplitN(param, "=", 2)
|
||||||
|
if len(sp) != 2 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
token := strings.Trim(sp[0], " ")
|
||||||
|
if token == "q" {
|
||||||
|
a.Q, _ = strconv.ParseFloat(sp[1], 32)
|
||||||
|
} else {
|
||||||
|
a.Params[token] = strings.Trim(sp[1], " ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
accept = append(accept, a)
|
||||||
|
}
|
||||||
|
|
||||||
|
slice := accept_slice(accept)
|
||||||
|
sort.Sort(slice)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Negotiate the most appropriate content_type given the accept header
|
||||||
|
// and a list of alternatives.
|
||||||
|
func Negotiate(header string, alternatives []string) (content_type string) {
|
||||||
|
asp := make([][]string, 0, len(alternatives))
|
||||||
|
for _, ctype := range alternatives {
|
||||||
|
asp = append(asp, strings.SplitN(ctype, "/", 2))
|
||||||
|
}
|
||||||
|
for _, clause := range ParseAccept(header) {
|
||||||
|
for i, ctsp := range asp {
|
||||||
|
if clause.Type == ctsp[0] && clause.SubType == ctsp[1] {
|
||||||
|
content_type = alternatives[i]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if clause.Type == ctsp[0] && clause.SubType == "*" {
|
||||||
|
content_type = alternatives[i]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if clause.Type == "*" && clause.SubType == "*" {
|
||||||
|
content_type = alternatives[i]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
21
vendor/github.com/Azure/go-ansiterm/LICENSE
generated
vendored
Normal file
21
vendor/github.com/Azure/go-ansiterm/LICENSE
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2015 Microsoft Corporation
|
||||||
|
|
||||||
|
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.
|
12
vendor/github.com/Azure/go-ansiterm/README.md
generated
vendored
Normal file
12
vendor/github.com/Azure/go-ansiterm/README.md
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# go-ansiterm
|
||||||
|
|
||||||
|
This is a cross platform Ansi Terminal Emulation library. It reads a stream of Ansi characters and produces the appropriate function calls. The results of the function calls are platform dependent.
|
||||||
|
|
||||||
|
For example the parser might receive "ESC, [, A" as a stream of three characters. This is the code for Cursor Up (http://www.vt100.net/docs/vt510-rm/CUU). The parser then calls the cursor up function (CUU()) on an event handler. The event handler determines what platform specific work must be done to cause the cursor to move up one position.
|
||||||
|
|
||||||
|
The parser (parser.go) is a partial implementation of this state machine (http://vt100.net/emu/vt500_parser.png). There are also two event handler implementations, one for tests (test_event_handler.go) to validate that the expected events are being produced and called, the other is a Windows implementation (winterm/win_event_handler.go).
|
||||||
|
|
||||||
|
See parser_test.go for examples exercising the state machine and generating appropriate function calls.
|
||||||
|
|
||||||
|
-----
|
||||||
|
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
|
188
vendor/github.com/Azure/go-ansiterm/constants.go
generated
vendored
Normal file
188
vendor/github.com/Azure/go-ansiterm/constants.go
generated
vendored
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
package ansiterm
|
||||||
|
|
||||||
|
const LogEnv = "DEBUG_TERMINAL"
|
||||||
|
|
||||||
|
// ANSI constants
|
||||||
|
// References:
|
||||||
|
// -- http://www.ecma-international.org/publications/standards/Ecma-048.htm
|
||||||
|
// -- http://man7.org/linux/man-pages/man4/console_codes.4.html
|
||||||
|
// -- http://manpages.ubuntu.com/manpages/intrepid/man4/console_codes.4.html
|
||||||
|
// -- http://en.wikipedia.org/wiki/ANSI_escape_code
|
||||||
|
// -- http://vt100.net/emu/dec_ansi_parser
|
||||||
|
// -- http://vt100.net/emu/vt500_parser.svg
|
||||||
|
// -- http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
|
||||||
|
// -- http://www.inwap.com/pdp10/ansicode.txt
|
||||||
|
const (
|
||||||
|
// ECMA-48 Set Graphics Rendition
|
||||||
|
// Note:
|
||||||
|
// -- Constants leading with an underscore (e.g., _ANSI_xxx) are unsupported or reserved
|
||||||
|
// -- Fonts could possibly be supported via SetCurrentConsoleFontEx
|
||||||
|
// -- Windows does not expose the per-window cursor (i.e., caret) blink times
|
||||||
|
ANSI_SGR_RESET = 0
|
||||||
|
ANSI_SGR_BOLD = 1
|
||||||
|
ANSI_SGR_DIM = 2
|
||||||
|
_ANSI_SGR_ITALIC = 3
|
||||||
|
ANSI_SGR_UNDERLINE = 4
|
||||||
|
_ANSI_SGR_BLINKSLOW = 5
|
||||||
|
_ANSI_SGR_BLINKFAST = 6
|
||||||
|
ANSI_SGR_REVERSE = 7
|
||||||
|
_ANSI_SGR_INVISIBLE = 8
|
||||||
|
_ANSI_SGR_LINETHROUGH = 9
|
||||||
|
_ANSI_SGR_FONT_00 = 10
|
||||||
|
_ANSI_SGR_FONT_01 = 11
|
||||||
|
_ANSI_SGR_FONT_02 = 12
|
||||||
|
_ANSI_SGR_FONT_03 = 13
|
||||||
|
_ANSI_SGR_FONT_04 = 14
|
||||||
|
_ANSI_SGR_FONT_05 = 15
|
||||||
|
_ANSI_SGR_FONT_06 = 16
|
||||||
|
_ANSI_SGR_FONT_07 = 17
|
||||||
|
_ANSI_SGR_FONT_08 = 18
|
||||||
|
_ANSI_SGR_FONT_09 = 19
|
||||||
|
_ANSI_SGR_FONT_10 = 20
|
||||||
|
_ANSI_SGR_DOUBLEUNDERLINE = 21
|
||||||
|
ANSI_SGR_BOLD_DIM_OFF = 22
|
||||||
|
_ANSI_SGR_ITALIC_OFF = 23
|
||||||
|
ANSI_SGR_UNDERLINE_OFF = 24
|
||||||
|
_ANSI_SGR_BLINK_OFF = 25
|
||||||
|
_ANSI_SGR_RESERVED_00 = 26
|
||||||
|
ANSI_SGR_REVERSE_OFF = 27
|
||||||
|
_ANSI_SGR_INVISIBLE_OFF = 28
|
||||||
|
_ANSI_SGR_LINETHROUGH_OFF = 29
|
||||||
|
ANSI_SGR_FOREGROUND_BLACK = 30
|
||||||
|
ANSI_SGR_FOREGROUND_RED = 31
|
||||||
|
ANSI_SGR_FOREGROUND_GREEN = 32
|
||||||
|
ANSI_SGR_FOREGROUND_YELLOW = 33
|
||||||
|
ANSI_SGR_FOREGROUND_BLUE = 34
|
||||||
|
ANSI_SGR_FOREGROUND_MAGENTA = 35
|
||||||
|
ANSI_SGR_FOREGROUND_CYAN = 36
|
||||||
|
ANSI_SGR_FOREGROUND_WHITE = 37
|
||||||
|
_ANSI_SGR_RESERVED_01 = 38
|
||||||
|
ANSI_SGR_FOREGROUND_DEFAULT = 39
|
||||||
|
ANSI_SGR_BACKGROUND_BLACK = 40
|
||||||
|
ANSI_SGR_BACKGROUND_RED = 41
|
||||||
|
ANSI_SGR_BACKGROUND_GREEN = 42
|
||||||
|
ANSI_SGR_BACKGROUND_YELLOW = 43
|
||||||
|
ANSI_SGR_BACKGROUND_BLUE = 44
|
||||||
|
ANSI_SGR_BACKGROUND_MAGENTA = 45
|
||||||
|
ANSI_SGR_BACKGROUND_CYAN = 46
|
||||||
|
ANSI_SGR_BACKGROUND_WHITE = 47
|
||||||
|
_ANSI_SGR_RESERVED_02 = 48
|
||||||
|
ANSI_SGR_BACKGROUND_DEFAULT = 49
|
||||||
|
// 50 - 65: Unsupported
|
||||||
|
|
||||||
|
ANSI_MAX_CMD_LENGTH = 4096
|
||||||
|
|
||||||
|
MAX_INPUT_EVENTS = 128
|
||||||
|
DEFAULT_WIDTH = 80
|
||||||
|
DEFAULT_HEIGHT = 24
|
||||||
|
|
||||||
|
ANSI_BEL = 0x07
|
||||||
|
ANSI_BACKSPACE = 0x08
|
||||||
|
ANSI_TAB = 0x09
|
||||||
|
ANSI_LINE_FEED = 0x0A
|
||||||
|
ANSI_VERTICAL_TAB = 0x0B
|
||||||
|
ANSI_FORM_FEED = 0x0C
|
||||||
|
ANSI_CARRIAGE_RETURN = 0x0D
|
||||||
|
ANSI_ESCAPE_PRIMARY = 0x1B
|
||||||
|
ANSI_ESCAPE_SECONDARY = 0x5B
|
||||||
|
ANSI_OSC_STRING_ENTRY = 0x5D
|
||||||
|
ANSI_COMMAND_FIRST = 0x40
|
||||||
|
ANSI_COMMAND_LAST = 0x7E
|
||||||
|
DCS_ENTRY = 0x90
|
||||||
|
CSI_ENTRY = 0x9B
|
||||||
|
OSC_STRING = 0x9D
|
||||||
|
ANSI_PARAMETER_SEP = ";"
|
||||||
|
ANSI_CMD_G0 = '('
|
||||||
|
ANSI_CMD_G1 = ')'
|
||||||
|
ANSI_CMD_G2 = '*'
|
||||||
|
ANSI_CMD_G3 = '+'
|
||||||
|
ANSI_CMD_DECPNM = '>'
|
||||||
|
ANSI_CMD_DECPAM = '='
|
||||||
|
ANSI_CMD_OSC = ']'
|
||||||
|
ANSI_CMD_STR_TERM = '\\'
|
||||||
|
|
||||||
|
KEY_CONTROL_PARAM_2 = ";2"
|
||||||
|
KEY_CONTROL_PARAM_3 = ";3"
|
||||||
|
KEY_CONTROL_PARAM_4 = ";4"
|
||||||
|
KEY_CONTROL_PARAM_5 = ";5"
|
||||||
|
KEY_CONTROL_PARAM_6 = ";6"
|
||||||
|
KEY_CONTROL_PARAM_7 = ";7"
|
||||||
|
KEY_CONTROL_PARAM_8 = ";8"
|
||||||
|
KEY_ESC_CSI = "\x1B["
|
||||||
|
KEY_ESC_N = "\x1BN"
|
||||||
|
KEY_ESC_O = "\x1BO"
|
||||||
|
|
||||||
|
FILL_CHARACTER = ' '
|
||||||
|
)
|
||||||
|
|
||||||
|
func getByteRange(start byte, end byte) []byte {
|
||||||
|
bytes := make([]byte, 0, 32)
|
||||||
|
for i := start; i <= end; i++ {
|
||||||
|
bytes = append(bytes, byte(i))
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytes
|
||||||
|
}
|
||||||
|
|
||||||
|
var toGroundBytes = getToGroundBytes()
|
||||||
|
var executors = getExecuteBytes()
|
||||||
|
|
||||||
|
// SPACE 20+A0 hex Always and everywhere a blank space
|
||||||
|
// Intermediate 20-2F hex !"#$%&'()*+,-./
|
||||||
|
var intermeds = getByteRange(0x20, 0x2F)
|
||||||
|
|
||||||
|
// Parameters 30-3F hex 0123456789:;<=>?
|
||||||
|
// CSI Parameters 30-39, 3B hex 0123456789;
|
||||||
|
var csiParams = getByteRange(0x30, 0x3F)
|
||||||
|
|
||||||
|
var csiCollectables = append(getByteRange(0x30, 0x39), getByteRange(0x3B, 0x3F)...)
|
||||||
|
|
||||||
|
// Uppercase 40-5F hex @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_
|
||||||
|
var upperCase = getByteRange(0x40, 0x5F)
|
||||||
|
|
||||||
|
// Lowercase 60-7E hex `abcdefghijlkmnopqrstuvwxyz{|}~
|
||||||
|
var lowerCase = getByteRange(0x60, 0x7E)
|
||||||
|
|
||||||
|
// Alphabetics 40-7E hex (all of upper and lower case)
|
||||||
|
var alphabetics = append(upperCase, lowerCase...)
|
||||||
|
|
||||||
|
var printables = getByteRange(0x20, 0x7F)
|
||||||
|
|
||||||
|
var escapeIntermediateToGroundBytes = getByteRange(0x30, 0x7E)
|
||||||
|
var escapeToGroundBytes = getEscapeToGroundBytes()
|
||||||
|
|
||||||
|
// See http://www.vt100.net/emu/vt500_parser.png for description of the complex
|
||||||
|
// byte ranges below
|
||||||
|
|
||||||
|
func getEscapeToGroundBytes() []byte {
|
||||||
|
escapeToGroundBytes := getByteRange(0x30, 0x4F)
|
||||||
|
escapeToGroundBytes = append(escapeToGroundBytes, getByteRange(0x51, 0x57)...)
|
||||||
|
escapeToGroundBytes = append(escapeToGroundBytes, 0x59)
|
||||||
|
escapeToGroundBytes = append(escapeToGroundBytes, 0x5A)
|
||||||
|
escapeToGroundBytes = append(escapeToGroundBytes, 0x5C)
|
||||||
|
escapeToGroundBytes = append(escapeToGroundBytes, getByteRange(0x60, 0x7E)...)
|
||||||
|
return escapeToGroundBytes
|
||||||
|
}
|
||||||
|
|
||||||
|
func getExecuteBytes() []byte {
|
||||||
|
executeBytes := getByteRange(0x00, 0x17)
|
||||||
|
executeBytes = append(executeBytes, 0x19)
|
||||||
|
executeBytes = append(executeBytes, getByteRange(0x1C, 0x1F)...)
|
||||||
|
return executeBytes
|
||||||
|
}
|
||||||
|
|
||||||
|
func getToGroundBytes() []byte {
|
||||||
|
groundBytes := []byte{0x18}
|
||||||
|
groundBytes = append(groundBytes, 0x1A)
|
||||||
|
groundBytes = append(groundBytes, getByteRange(0x80, 0x8F)...)
|
||||||
|
groundBytes = append(groundBytes, getByteRange(0x91, 0x97)...)
|
||||||
|
groundBytes = append(groundBytes, 0x99)
|
||||||
|
groundBytes = append(groundBytes, 0x9A)
|
||||||
|
groundBytes = append(groundBytes, 0x9C)
|
||||||
|
return groundBytes
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete 7F hex Always and everywhere ignored
|
||||||
|
// C1 Control 80-9F hex 32 additional control characters
|
||||||
|
// G1 Displayable A1-FE hex 94 additional displayable characters
|
||||||
|
// Special A0+FF hex Same as SPACE and DELETE
|
7
vendor/github.com/Azure/go-ansiterm/context.go
generated
vendored
Normal file
7
vendor/github.com/Azure/go-ansiterm/context.go
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package ansiterm
|
||||||
|
|
||||||
|
type ansiContext struct {
|
||||||
|
currentChar byte
|
||||||
|
paramBuffer []byte
|
||||||
|
interBuffer []byte
|
||||||
|
}
|
49
vendor/github.com/Azure/go-ansiterm/csi_entry_state.go
generated
vendored
Normal file
49
vendor/github.com/Azure/go-ansiterm/csi_entry_state.go
generated
vendored
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
package ansiterm
|
||||||
|
|
||||||
|
type csiEntryState struct {
|
||||||
|
baseState
|
||||||
|
}
|
||||||
|
|
||||||
|
func (csiState csiEntryState) Handle(b byte) (s state, e error) {
|
||||||
|
csiState.parser.logf("CsiEntry::Handle %#x", b)
|
||||||
|
|
||||||
|
nextState, err := csiState.baseState.Handle(b)
|
||||||
|
if nextState != nil || err != nil {
|
||||||
|
return nextState, err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case sliceContains(alphabetics, b):
|
||||||
|
return csiState.parser.ground, nil
|
||||||
|
case sliceContains(csiCollectables, b):
|
||||||
|
return csiState.parser.csiParam, nil
|
||||||
|
case sliceContains(executors, b):
|
||||||
|
return csiState, csiState.parser.execute()
|
||||||
|
}
|
||||||
|
|
||||||
|
return csiState, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (csiState csiEntryState) Transition(s state) error {
|
||||||
|
csiState.parser.logf("CsiEntry::Transition %s --> %s", csiState.Name(), s.Name())
|
||||||
|
csiState.baseState.Transition(s)
|
||||||
|
|
||||||
|
switch s {
|
||||||
|
case csiState.parser.ground:
|
||||||
|
return csiState.parser.csiDispatch()
|
||||||
|
case csiState.parser.csiParam:
|
||||||
|
switch {
|
||||||
|
case sliceContains(csiParams, csiState.parser.context.currentChar):
|
||||||
|
csiState.parser.collectParam()
|
||||||
|
case sliceContains(intermeds, csiState.parser.context.currentChar):
|
||||||
|
csiState.parser.collectInter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (csiState csiEntryState) Enter() error {
|
||||||
|
csiState.parser.clear()
|
||||||
|
return nil
|
||||||
|
}
|
38
vendor/github.com/Azure/go-ansiterm/csi_param_state.go
generated
vendored
Normal file
38
vendor/github.com/Azure/go-ansiterm/csi_param_state.go
generated
vendored
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
package ansiterm
|
||||||
|
|
||||||
|
type csiParamState struct {
|
||||||
|
baseState
|
||||||
|
}
|
||||||
|
|
||||||
|
func (csiState csiParamState) Handle(b byte) (s state, e error) {
|
||||||
|
csiState.parser.logf("CsiParam::Handle %#x", b)
|
||||||
|
|
||||||
|
nextState, err := csiState.baseState.Handle(b)
|
||||||
|
if nextState != nil || err != nil {
|
||||||
|
return nextState, err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case sliceContains(alphabetics, b):
|
||||||
|
return csiState.parser.ground, nil
|
||||||
|
case sliceContains(csiCollectables, b):
|
||||||
|
csiState.parser.collectParam()
|
||||||
|
return csiState, nil
|
||||||
|
case sliceContains(executors, b):
|
||||||
|
return csiState, csiState.parser.execute()
|
||||||
|
}
|
||||||
|
|
||||||
|
return csiState, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (csiState csiParamState) Transition(s state) error {
|
||||||
|
csiState.parser.logf("CsiParam::Transition %s --> %s", csiState.Name(), s.Name())
|
||||||
|
csiState.baseState.Transition(s)
|
||||||
|
|
||||||
|
switch s {
|
||||||
|
case csiState.parser.ground:
|
||||||
|
return csiState.parser.csiDispatch()
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
36
vendor/github.com/Azure/go-ansiterm/escape_intermediate_state.go
generated
vendored
Normal file
36
vendor/github.com/Azure/go-ansiterm/escape_intermediate_state.go
generated
vendored
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
package ansiterm
|
||||||
|
|
||||||
|
type escapeIntermediateState struct {
|
||||||
|
baseState
|
||||||
|
}
|
||||||
|
|
||||||
|
func (escState escapeIntermediateState) Handle(b byte) (s state, e error) {
|
||||||
|
escState.parser.logf("escapeIntermediateState::Handle %#x", b)
|
||||||
|
nextState, err := escState.baseState.Handle(b)
|
||||||
|
if nextState != nil || err != nil {
|
||||||
|
return nextState, err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case sliceContains(intermeds, b):
|
||||||
|
return escState, escState.parser.collectInter()
|
||||||
|
case sliceContains(executors, b):
|
||||||
|
return escState, escState.parser.execute()
|
||||||
|
case sliceContains(escapeIntermediateToGroundBytes, b):
|
||||||
|
return escState.parser.ground, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return escState, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (escState escapeIntermediateState) Transition(s state) error {
|
||||||
|
escState.parser.logf("escapeIntermediateState::Transition %s --> %s", escState.Name(), s.Name())
|
||||||
|
escState.baseState.Transition(s)
|
||||||
|
|
||||||
|
switch s {
|
||||||
|
case escState.parser.ground:
|
||||||
|
return escState.parser.escDispatch()
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
47
vendor/github.com/Azure/go-ansiterm/escape_state.go
generated
vendored
Normal file
47
vendor/github.com/Azure/go-ansiterm/escape_state.go
generated
vendored
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
package ansiterm
|
||||||
|
|
||||||
|
type escapeState struct {
|
||||||
|
baseState
|
||||||
|
}
|
||||||
|
|
||||||
|
func (escState escapeState) Handle(b byte) (s state, e error) {
|
||||||
|
escState.parser.logf("escapeState::Handle %#x", b)
|
||||||
|
nextState, err := escState.baseState.Handle(b)
|
||||||
|
if nextState != nil || err != nil {
|
||||||
|
return nextState, err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case b == ANSI_ESCAPE_SECONDARY:
|
||||||
|
return escState.parser.csiEntry, nil
|
||||||
|
case b == ANSI_OSC_STRING_ENTRY:
|
||||||
|
return escState.parser.oscString, nil
|
||||||
|
case sliceContains(executors, b):
|
||||||
|
return escState, escState.parser.execute()
|
||||||
|
case sliceContains(escapeToGroundBytes, b):
|
||||||
|
return escState.parser.ground, nil
|
||||||
|
case sliceContains(intermeds, b):
|
||||||
|
return escState.parser.escapeIntermediate, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return escState, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (escState escapeState) Transition(s state) error {
|
||||||
|
escState.parser.logf("Escape::Transition %s --> %s", escState.Name(), s.Name())
|
||||||
|
escState.baseState.Transition(s)
|
||||||
|
|
||||||
|
switch s {
|
||||||
|
case escState.parser.ground:
|
||||||
|
return escState.parser.escDispatch()
|
||||||
|
case escState.parser.escapeIntermediate:
|
||||||
|
return escState.parser.collectInter()
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (escState escapeState) Enter() error {
|
||||||
|
escState.parser.clear()
|
||||||
|
return nil
|
||||||
|
}
|
90
vendor/github.com/Azure/go-ansiterm/event_handler.go
generated
vendored
Normal file
90
vendor/github.com/Azure/go-ansiterm/event_handler.go
generated
vendored
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
package ansiterm
|
||||||
|
|
||||||
|
type AnsiEventHandler interface {
|
||||||
|
// Print
|
||||||
|
Print(b byte) error
|
||||||
|
|
||||||
|
// Execute C0 commands
|
||||||
|
Execute(b byte) error
|
||||||
|
|
||||||
|
// CUrsor Up
|
||||||
|
CUU(int) error
|
||||||
|
|
||||||
|
// CUrsor Down
|
||||||
|
CUD(int) error
|
||||||
|
|
||||||
|
// CUrsor Forward
|
||||||
|
CUF(int) error
|
||||||
|
|
||||||
|
// CUrsor Backward
|
||||||
|
CUB(int) error
|
||||||
|
|
||||||
|
// Cursor to Next Line
|
||||||
|
CNL(int) error
|
||||||
|
|
||||||
|
// Cursor to Previous Line
|
||||||
|
CPL(int) error
|
||||||
|
|
||||||
|
// Cursor Horizontal position Absolute
|
||||||
|
CHA(int) error
|
||||||
|
|
||||||
|
// Vertical line Position Absolute
|
||||||
|
VPA(int) error
|
||||||
|
|
||||||
|
// CUrsor Position
|
||||||
|
CUP(int, int) error
|
||||||
|
|
||||||
|
// Horizontal and Vertical Position (depends on PUM)
|
||||||
|
HVP(int, int) error
|
||||||
|
|
||||||
|
// Text Cursor Enable Mode
|
||||||
|
DECTCEM(bool) error
|
||||||
|
|
||||||
|
// Origin Mode
|
||||||
|
DECOM(bool) error
|
||||||
|
|
||||||
|
// 132 Column Mode
|
||||||
|
DECCOLM(bool) error
|
||||||
|
|
||||||
|
// Erase in Display
|
||||||
|
ED(int) error
|
||||||
|
|
||||||
|
// Erase in Line
|
||||||
|
EL(int) error
|
||||||
|
|
||||||
|
// Insert Line
|
||||||
|
IL(int) error
|
||||||
|
|
||||||
|
// Delete Line
|
||||||
|
DL(int) error
|
||||||
|
|
||||||
|
// Insert Character
|
||||||
|
ICH(int) error
|
||||||
|
|
||||||
|
// Delete Character
|
||||||
|
DCH(int) error
|
||||||
|
|
||||||
|
// Set Graphics Rendition
|
||||||
|
SGR([]int) error
|
||||||
|
|
||||||
|
// Pan Down
|
||||||
|
SU(int) error
|
||||||
|
|
||||||
|
// Pan Up
|
||||||
|
SD(int) error
|
||||||
|
|
||||||
|
// Device Attributes
|
||||||
|
DA([]string) error
|
||||||
|
|
||||||
|
// Set Top and Bottom Margins
|
||||||
|
DECSTBM(int, int) error
|
||||||
|
|
||||||
|
// Index
|
||||||
|
IND() error
|
||||||
|
|
||||||
|
// Reverse Index
|
||||||
|
RI() error
|
||||||
|
|
||||||
|
// Flush updates from previous commands
|
||||||
|
Flush() error
|
||||||
|
}
|
24
vendor/github.com/Azure/go-ansiterm/ground_state.go
generated
vendored
Normal file
24
vendor/github.com/Azure/go-ansiterm/ground_state.go
generated
vendored
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package ansiterm
|
||||||
|
|
||||||
|
type groundState struct {
|
||||||
|
baseState
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gs groundState) Handle(b byte) (s state, e error) {
|
||||||
|
gs.parser.context.currentChar = b
|
||||||
|
|
||||||
|
nextState, err := gs.baseState.Handle(b)
|
||||||
|
if nextState != nil || err != nil {
|
||||||
|
return nextState, err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case sliceContains(printables, b):
|
||||||
|
return gs, gs.parser.print()
|
||||||
|
|
||||||
|
case sliceContains(executors, b):
|
||||||
|
return gs, gs.parser.execute()
|
||||||
|
}
|
||||||
|
|
||||||
|
return gs, nil
|
||||||
|
}
|
31
vendor/github.com/Azure/go-ansiterm/osc_string_state.go
generated
vendored
Normal file
31
vendor/github.com/Azure/go-ansiterm/osc_string_state.go
generated
vendored
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
package ansiterm
|
||||||
|
|
||||||
|
type oscStringState struct {
|
||||||
|
baseState
|
||||||
|
}
|
||||||
|
|
||||||
|
func (oscState oscStringState) Handle(b byte) (s state, e error) {
|
||||||
|
oscState.parser.logf("OscString::Handle %#x", b)
|
||||||
|
nextState, err := oscState.baseState.Handle(b)
|
||||||
|
if nextState != nil || err != nil {
|
||||||
|
return nextState, err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case isOscStringTerminator(b):
|
||||||
|
return oscState.parser.ground, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return oscState, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// See below for OSC string terminators for linux
|
||||||
|
// http://man7.org/linux/man-pages/man4/console_codes.4.html
|
||||||
|
func isOscStringTerminator(b byte) bool {
|
||||||
|
|
||||||
|
if b == ANSI_BEL || b == 0x5C {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
151
vendor/github.com/Azure/go-ansiterm/parser.go
generated
vendored
Normal file
151
vendor/github.com/Azure/go-ansiterm/parser.go
generated
vendored
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
package ansiterm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AnsiParser struct {
|
||||||
|
currState state
|
||||||
|
eventHandler AnsiEventHandler
|
||||||
|
context *ansiContext
|
||||||
|
csiEntry state
|
||||||
|
csiParam state
|
||||||
|
dcsEntry state
|
||||||
|
escape state
|
||||||
|
escapeIntermediate state
|
||||||
|
error state
|
||||||
|
ground state
|
||||||
|
oscString state
|
||||||
|
stateMap []state
|
||||||
|
|
||||||
|
logf func(string, ...interface{})
|
||||||
|
}
|
||||||
|
|
||||||
|
type Option func(*AnsiParser)
|
||||||
|
|
||||||
|
func WithLogf(f func(string, ...interface{})) Option {
|
||||||
|
return func(ap *AnsiParser) {
|
||||||
|
ap.logf = f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateParser(initialState string, evtHandler AnsiEventHandler, opts ...Option) *AnsiParser {
|
||||||
|
ap := &AnsiParser{
|
||||||
|
eventHandler: evtHandler,
|
||||||
|
context: &ansiContext{},
|
||||||
|
}
|
||||||
|
for _, o := range opts {
|
||||||
|
o(ap)
|
||||||
|
}
|
||||||
|
|
||||||
|
if isDebugEnv := os.Getenv(LogEnv); isDebugEnv == "1" {
|
||||||
|
logFile, _ := os.Create("ansiParser.log")
|
||||||
|
logger := log.New(logFile, "", log.LstdFlags)
|
||||||
|
if ap.logf != nil {
|
||||||
|
l := ap.logf
|
||||||
|
ap.logf = func(s string, v ...interface{}) {
|
||||||
|
l(s, v...)
|
||||||
|
logger.Printf(s, v...)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ap.logf = logger.Printf
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ap.logf == nil {
|
||||||
|
ap.logf = func(string, ...interface{}) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
ap.csiEntry = csiEntryState{baseState{name: "CsiEntry", parser: ap}}
|
||||||
|
ap.csiParam = csiParamState{baseState{name: "CsiParam", parser: ap}}
|
||||||
|
ap.dcsEntry = dcsEntryState{baseState{name: "DcsEntry", parser: ap}}
|
||||||
|
ap.escape = escapeState{baseState{name: "Escape", parser: ap}}
|
||||||
|
ap.escapeIntermediate = escapeIntermediateState{baseState{name: "EscapeIntermediate", parser: ap}}
|
||||||
|
ap.error = errorState{baseState{name: "Error", parser: ap}}
|
||||||
|
ap.ground = groundState{baseState{name: "Ground", parser: ap}}
|
||||||
|
ap.oscString = oscStringState{baseState{name: "OscString", parser: ap}}
|
||||||
|
|
||||||
|
ap.stateMap = []state{
|
||||||
|
ap.csiEntry,
|
||||||
|
ap.csiParam,
|
||||||
|
ap.dcsEntry,
|
||||||
|
ap.escape,
|
||||||
|
ap.escapeIntermediate,
|
||||||
|
ap.error,
|
||||||
|
ap.ground,
|
||||||
|
ap.oscString,
|
||||||
|
}
|
||||||
|
|
||||||
|
ap.currState = getState(initialState, ap.stateMap)
|
||||||
|
|
||||||
|
ap.logf("CreateParser: parser %p", ap)
|
||||||
|
return ap
|
||||||
|
}
|
||||||
|
|
||||||
|
func getState(name string, states []state) state {
|
||||||
|
for _, el := range states {
|
||||||
|
if el.Name() == name {
|
||||||
|
return el
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ap *AnsiParser) Parse(bytes []byte) (int, error) {
|
||||||
|
for i, b := range bytes {
|
||||||
|
if err := ap.handle(b); err != nil {
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return len(bytes), ap.eventHandler.Flush()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ap *AnsiParser) handle(b byte) error {
|
||||||
|
ap.context.currentChar = b
|
||||||
|
newState, err := ap.currState.Handle(b)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if newState == nil {
|
||||||
|
ap.logf("WARNING: newState is nil")
|
||||||
|
return errors.New("New state of 'nil' is invalid.")
|
||||||
|
}
|
||||||
|
|
||||||
|
if newState != ap.currState {
|
||||||
|
if err := ap.changeState(newState); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ap *AnsiParser) changeState(newState state) error {
|
||||||
|
ap.logf("ChangeState %s --> %s", ap.currState.Name(), newState.Name())
|
||||||
|
|
||||||
|
// Exit old state
|
||||||
|
if err := ap.currState.Exit(); err != nil {
|
||||||
|
ap.logf("Exit state '%s' failed with : '%v'", ap.currState.Name(), err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform transition action
|
||||||
|
if err := ap.currState.Transition(newState); err != nil {
|
||||||
|
ap.logf("Transition from '%s' to '%s' failed with: '%v'", ap.currState.Name(), newState.Name, err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enter new state
|
||||||
|
if err := newState.Enter(); err != nil {
|
||||||
|
ap.logf("Enter state '%s' failed with: '%v'", newState.Name(), err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
ap.currState = newState
|
||||||
|
return nil
|
||||||
|
}
|
99
vendor/github.com/Azure/go-ansiterm/parser_action_helpers.go
generated
vendored
Normal file
99
vendor/github.com/Azure/go-ansiterm/parser_action_helpers.go
generated
vendored
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
package ansiterm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
func parseParams(bytes []byte) ([]string, error) {
|
||||||
|
paramBuff := make([]byte, 0, 0)
|
||||||
|
params := []string{}
|
||||||
|
|
||||||
|
for _, v := range bytes {
|
||||||
|
if v == ';' {
|
||||||
|
if len(paramBuff) > 0 {
|
||||||
|
// Completed parameter, append it to the list
|
||||||
|
s := string(paramBuff)
|
||||||
|
params = append(params, s)
|
||||||
|
paramBuff = make([]byte, 0, 0)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
paramBuff = append(paramBuff, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Last parameter may not be terminated with ';'
|
||||||
|
if len(paramBuff) > 0 {
|
||||||
|
s := string(paramBuff)
|
||||||
|
params = append(params, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
return params, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseCmd(context ansiContext) (string, error) {
|
||||||
|
return string(context.currentChar), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getInt(params []string, dflt int) int {
|
||||||
|
i := getInts(params, 1, dflt)[0]
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
func getInts(params []string, minCount int, dflt int) []int {
|
||||||
|
ints := []int{}
|
||||||
|
|
||||||
|
for _, v := range params {
|
||||||
|
i, _ := strconv.Atoi(v)
|
||||||
|
// Zero is mapped to the default value in VT100.
|
||||||
|
if i == 0 {
|
||||||
|
i = dflt
|
||||||
|
}
|
||||||
|
ints = append(ints, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(ints) < minCount {
|
||||||
|
remaining := minCount - len(ints)
|
||||||
|
for i := 0; i < remaining; i++ {
|
||||||
|
ints = append(ints, dflt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ints
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ap *AnsiParser) modeDispatch(param string, set bool) error {
|
||||||
|
switch param {
|
||||||
|
case "?3":
|
||||||
|
return ap.eventHandler.DECCOLM(set)
|
||||||
|
case "?6":
|
||||||
|
return ap.eventHandler.DECOM(set)
|
||||||
|
case "?25":
|
||||||
|
return ap.eventHandler.DECTCEM(set)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ap *AnsiParser) hDispatch(params []string) error {
|
||||||
|
if len(params) == 1 {
|
||||||
|
return ap.modeDispatch(params[0], true)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ap *AnsiParser) lDispatch(params []string) error {
|
||||||
|
if len(params) == 1 {
|
||||||
|
return ap.modeDispatch(params[0], false)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getEraseParam(params []string) int {
|
||||||
|
param := getInt(params, 0)
|
||||||
|
if param < 0 || 3 < param {
|
||||||
|
param = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return param
|
||||||
|
}
|
119
vendor/github.com/Azure/go-ansiterm/parser_actions.go
generated
vendored
Normal file
119
vendor/github.com/Azure/go-ansiterm/parser_actions.go
generated
vendored
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
package ansiterm
|
||||||
|
|
||||||
|
func (ap *AnsiParser) collectParam() error {
|
||||||
|
currChar := ap.context.currentChar
|
||||||
|
ap.logf("collectParam %#x", currChar)
|
||||||
|
ap.context.paramBuffer = append(ap.context.paramBuffer, currChar)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ap *AnsiParser) collectInter() error {
|
||||||
|
currChar := ap.context.currentChar
|
||||||
|
ap.logf("collectInter %#x", currChar)
|
||||||
|
ap.context.paramBuffer = append(ap.context.interBuffer, currChar)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ap *AnsiParser) escDispatch() error {
|
||||||
|
cmd, _ := parseCmd(*ap.context)
|
||||||
|
intermeds := ap.context.interBuffer
|
||||||
|
ap.logf("escDispatch currentChar: %#x", ap.context.currentChar)
|
||||||
|
ap.logf("escDispatch: %v(%v)", cmd, intermeds)
|
||||||
|
|
||||||
|
switch cmd {
|
||||||
|
case "D": // IND
|
||||||
|
return ap.eventHandler.IND()
|
||||||
|
case "E": // NEL, equivalent to CRLF
|
||||||
|
err := ap.eventHandler.Execute(ANSI_CARRIAGE_RETURN)
|
||||||
|
if err == nil {
|
||||||
|
err = ap.eventHandler.Execute(ANSI_LINE_FEED)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
case "M": // RI
|
||||||
|
return ap.eventHandler.RI()
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ap *AnsiParser) csiDispatch() error {
|
||||||
|
cmd, _ := parseCmd(*ap.context)
|
||||||
|
params, _ := parseParams(ap.context.paramBuffer)
|
||||||
|
ap.logf("Parsed params: %v with length: %d", params, len(params))
|
||||||
|
|
||||||
|
ap.logf("csiDispatch: %v(%v)", cmd, params)
|
||||||
|
|
||||||
|
switch cmd {
|
||||||
|
case "@":
|
||||||
|
return ap.eventHandler.ICH(getInt(params, 1))
|
||||||
|
case "A":
|
||||||
|
return ap.eventHandler.CUU(getInt(params, 1))
|
||||||
|
case "B":
|
||||||
|
return ap.eventHandler.CUD(getInt(params, 1))
|
||||||
|
case "C":
|
||||||
|
return ap.eventHandler.CUF(getInt(params, 1))
|
||||||
|
case "D":
|
||||||
|
return ap.eventHandler.CUB(getInt(params, 1))
|
||||||
|
case "E":
|
||||||
|
return ap.eventHandler.CNL(getInt(params, 1))
|
||||||
|
case "F":
|
||||||
|
return ap.eventHandler.CPL(getInt(params, 1))
|
||||||
|
case "G":
|
||||||
|
return ap.eventHandler.CHA(getInt(params, 1))
|
||||||
|
case "H":
|
||||||
|
ints := getInts(params, 2, 1)
|
||||||
|
x, y := ints[0], ints[1]
|
||||||
|
return ap.eventHandler.CUP(x, y)
|
||||||
|
case "J":
|
||||||
|
param := getEraseParam(params)
|
||||||
|
return ap.eventHandler.ED(param)
|
||||||
|
case "K":
|
||||||
|
param := getEraseParam(params)
|
||||||
|
return ap.eventHandler.EL(param)
|
||||||
|
case "L":
|
||||||
|
return ap.eventHandler.IL(getInt(params, 1))
|
||||||
|
case "M":
|
||||||
|
return ap.eventHandler.DL(getInt(params, 1))
|
||||||
|
case "P":
|
||||||
|
return ap.eventHandler.DCH(getInt(params, 1))
|
||||||
|
case "S":
|
||||||
|
return ap.eventHandler.SU(getInt(params, 1))
|
||||||
|
case "T":
|
||||||
|
return ap.eventHandler.SD(getInt(params, 1))
|
||||||
|
case "c":
|
||||||
|
return ap.eventHandler.DA(params)
|
||||||
|
case "d":
|
||||||
|
return ap.eventHandler.VPA(getInt(params, 1))
|
||||||
|
case "f":
|
||||||
|
ints := getInts(params, 2, 1)
|
||||||
|
x, y := ints[0], ints[1]
|
||||||
|
return ap.eventHandler.HVP(x, y)
|
||||||
|
case "h":
|
||||||
|
return ap.hDispatch(params)
|
||||||
|
case "l":
|
||||||
|
return ap.lDispatch(params)
|
||||||
|
case "m":
|
||||||
|
return ap.eventHandler.SGR(getInts(params, 1, 0))
|
||||||
|
case "r":
|
||||||
|
ints := getInts(params, 2, 1)
|
||||||
|
top, bottom := ints[0], ints[1]
|
||||||
|
return ap.eventHandler.DECSTBM(top, bottom)
|
||||||
|
default:
|
||||||
|
ap.logf("ERROR: Unsupported CSI command: '%s', with full context: %v", cmd, ap.context)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ap *AnsiParser) print() error {
|
||||||
|
return ap.eventHandler.Print(ap.context.currentChar)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ap *AnsiParser) clear() error {
|
||||||
|
ap.context = &ansiContext{}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ap *AnsiParser) execute() error {
|
||||||
|
return ap.eventHandler.Execute(ap.context.currentChar)
|
||||||
|
}
|
71
vendor/github.com/Azure/go-ansiterm/states.go
generated
vendored
Normal file
71
vendor/github.com/Azure/go-ansiterm/states.go
generated
vendored
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
package ansiterm
|
||||||
|
|
||||||
|
type stateID int
|
||||||
|
|
||||||
|
type state interface {
|
||||||
|
Enter() error
|
||||||
|
Exit() error
|
||||||
|
Handle(byte) (state, error)
|
||||||
|
Name() string
|
||||||
|
Transition(state) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type baseState struct {
|
||||||
|
name string
|
||||||
|
parser *AnsiParser
|
||||||
|
}
|
||||||
|
|
||||||
|
func (base baseState) Enter() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (base baseState) Exit() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (base baseState) Handle(b byte) (s state, e error) {
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case b == CSI_ENTRY:
|
||||||
|
return base.parser.csiEntry, nil
|
||||||
|
case b == DCS_ENTRY:
|
||||||
|
return base.parser.dcsEntry, nil
|
||||||
|
case b == ANSI_ESCAPE_PRIMARY:
|
||||||
|
return base.parser.escape, nil
|
||||||
|
case b == OSC_STRING:
|
||||||
|
return base.parser.oscString, nil
|
||||||
|
case sliceContains(toGroundBytes, b):
|
||||||
|
return base.parser.ground, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (base baseState) Name() string {
|
||||||
|
return base.name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (base baseState) Transition(s state) error {
|
||||||
|
if s == base.parser.ground {
|
||||||
|
execBytes := []byte{0x18}
|
||||||
|
execBytes = append(execBytes, 0x1A)
|
||||||
|
execBytes = append(execBytes, getByteRange(0x80, 0x8F)...)
|
||||||
|
execBytes = append(execBytes, getByteRange(0x91, 0x97)...)
|
||||||
|
execBytes = append(execBytes, 0x99)
|
||||||
|
execBytes = append(execBytes, 0x9A)
|
||||||
|
|
||||||
|
if sliceContains(execBytes, base.parser.context.currentChar) {
|
||||||
|
return base.parser.execute()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type dcsEntryState struct {
|
||||||
|
baseState
|
||||||
|
}
|
||||||
|
|
||||||
|
type errorState struct {
|
||||||
|
baseState
|
||||||
|
}
|
21
vendor/github.com/Azure/go-ansiterm/utilities.go
generated
vendored
Normal file
21
vendor/github.com/Azure/go-ansiterm/utilities.go
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package ansiterm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
func sliceContains(bytes []byte, b byte) bool {
|
||||||
|
for _, v := range bytes {
|
||||||
|
if v == b {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertBytesToInteger(bytes []byte) int {
|
||||||
|
s := string(bytes)
|
||||||
|
i, _ := strconv.Atoi(s)
|
||||||
|
return i
|
||||||
|
}
|
182
vendor/github.com/Azure/go-ansiterm/winterm/ansi.go
generated
vendored
Normal file
182
vendor/github.com/Azure/go-ansiterm/winterm/ansi.go
generated
vendored
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
// +build windows
|
||||||
|
|
||||||
|
package winterm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/Azure/go-ansiterm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Windows keyboard constants
|
||||||
|
// See https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx.
|
||||||
|
const (
|
||||||
|
VK_PRIOR = 0x21 // PAGE UP key
|
||||||
|
VK_NEXT = 0x22 // PAGE DOWN key
|
||||||
|
VK_END = 0x23 // END key
|
||||||
|
VK_HOME = 0x24 // HOME key
|
||||||
|
VK_LEFT = 0x25 // LEFT ARROW key
|
||||||
|
VK_UP = 0x26 // UP ARROW key
|
||||||
|
VK_RIGHT = 0x27 // RIGHT ARROW key
|
||||||
|
VK_DOWN = 0x28 // DOWN ARROW key
|
||||||
|
VK_SELECT = 0x29 // SELECT key
|
||||||
|
VK_PRINT = 0x2A // PRINT key
|
||||||
|
VK_EXECUTE = 0x2B // EXECUTE key
|
||||||
|
VK_SNAPSHOT = 0x2C // PRINT SCREEN key
|
||||||
|
VK_INSERT = 0x2D // INS key
|
||||||
|
VK_DELETE = 0x2E // DEL key
|
||||||
|
VK_HELP = 0x2F // HELP key
|
||||||
|
VK_F1 = 0x70 // F1 key
|
||||||
|
VK_F2 = 0x71 // F2 key
|
||||||
|
VK_F3 = 0x72 // F3 key
|
||||||
|
VK_F4 = 0x73 // F4 key
|
||||||
|
VK_F5 = 0x74 // F5 key
|
||||||
|
VK_F6 = 0x75 // F6 key
|
||||||
|
VK_F7 = 0x76 // F7 key
|
||||||
|
VK_F8 = 0x77 // F8 key
|
||||||
|
VK_F9 = 0x78 // F9 key
|
||||||
|
VK_F10 = 0x79 // F10 key
|
||||||
|
VK_F11 = 0x7A // F11 key
|
||||||
|
VK_F12 = 0x7B // F12 key
|
||||||
|
|
||||||
|
RIGHT_ALT_PRESSED = 0x0001
|
||||||
|
LEFT_ALT_PRESSED = 0x0002
|
||||||
|
RIGHT_CTRL_PRESSED = 0x0004
|
||||||
|
LEFT_CTRL_PRESSED = 0x0008
|
||||||
|
SHIFT_PRESSED = 0x0010
|
||||||
|
NUMLOCK_ON = 0x0020
|
||||||
|
SCROLLLOCK_ON = 0x0040
|
||||||
|
CAPSLOCK_ON = 0x0080
|
||||||
|
ENHANCED_KEY = 0x0100
|
||||||
|
)
|
||||||
|
|
||||||
|
type ansiCommand struct {
|
||||||
|
CommandBytes []byte
|
||||||
|
Command string
|
||||||
|
Parameters []string
|
||||||
|
IsSpecial bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func newAnsiCommand(command []byte) *ansiCommand {
|
||||||
|
|
||||||
|
if isCharacterSelectionCmdChar(command[1]) {
|
||||||
|
// Is Character Set Selection commands
|
||||||
|
return &ansiCommand{
|
||||||
|
CommandBytes: command,
|
||||||
|
Command: string(command),
|
||||||
|
IsSpecial: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// last char is command character
|
||||||
|
lastCharIndex := len(command) - 1
|
||||||
|
|
||||||
|
ac := &ansiCommand{
|
||||||
|
CommandBytes: command,
|
||||||
|
Command: string(command[lastCharIndex]),
|
||||||
|
IsSpecial: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
// more than a single escape
|
||||||
|
if lastCharIndex != 0 {
|
||||||
|
start := 1
|
||||||
|
// skip if double char escape sequence
|
||||||
|
if command[0] == ansiterm.ANSI_ESCAPE_PRIMARY && command[1] == ansiterm.ANSI_ESCAPE_SECONDARY {
|
||||||
|
start++
|
||||||
|
}
|
||||||
|
// convert this to GetNextParam method
|
||||||
|
ac.Parameters = strings.Split(string(command[start:lastCharIndex]), ansiterm.ANSI_PARAMETER_SEP)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ac
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *ansiCommand) paramAsSHORT(index int, defaultValue int16) int16 {
|
||||||
|
if index < 0 || index >= len(ac.Parameters) {
|
||||||
|
return defaultValue
|
||||||
|
}
|
||||||
|
|
||||||
|
param, err := strconv.ParseInt(ac.Parameters[index], 10, 16)
|
||||||
|
if err != nil {
|
||||||
|
return defaultValue
|
||||||
|
}
|
||||||
|
|
||||||
|
return int16(param)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *ansiCommand) String() string {
|
||||||
|
return fmt.Sprintf("0x%v \"%v\" (\"%v\")",
|
||||||
|
bytesToHex(ac.CommandBytes),
|
||||||
|
ac.Command,
|
||||||
|
strings.Join(ac.Parameters, "\",\""))
|
||||||
|
}
|
||||||
|
|
||||||
|
// isAnsiCommandChar returns true if the passed byte falls within the range of ANSI commands.
|
||||||
|
// See http://manpages.ubuntu.com/manpages/intrepid/man4/console_codes.4.html.
|
||||||
|
func isAnsiCommandChar(b byte) bool {
|
||||||
|
switch {
|
||||||
|
case ansiterm.ANSI_COMMAND_FIRST <= b && b <= ansiterm.ANSI_COMMAND_LAST && b != ansiterm.ANSI_ESCAPE_SECONDARY:
|
||||||
|
return true
|
||||||
|
case b == ansiterm.ANSI_CMD_G1 || b == ansiterm.ANSI_CMD_OSC || b == ansiterm.ANSI_CMD_DECPAM || b == ansiterm.ANSI_CMD_DECPNM:
|
||||||
|
// non-CSI escape sequence terminator
|
||||||
|
return true
|
||||||
|
case b == ansiterm.ANSI_CMD_STR_TERM || b == ansiterm.ANSI_BEL:
|
||||||
|
// String escape sequence terminator
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func isXtermOscSequence(command []byte, current byte) bool {
|
||||||
|
return (len(command) >= 2 && command[0] == ansiterm.ANSI_ESCAPE_PRIMARY && command[1] == ansiterm.ANSI_CMD_OSC && current != ansiterm.ANSI_BEL)
|
||||||
|
}
|
||||||
|
|
||||||
|
func isCharacterSelectionCmdChar(b byte) bool {
|
||||||
|
return (b == ansiterm.ANSI_CMD_G0 || b == ansiterm.ANSI_CMD_G1 || b == ansiterm.ANSI_CMD_G2 || b == ansiterm.ANSI_CMD_G3)
|
||||||
|
}
|
||||||
|
|
||||||
|
// bytesToHex converts a slice of bytes to a human-readable string.
|
||||||
|
func bytesToHex(b []byte) string {
|
||||||
|
hex := make([]string, len(b))
|
||||||
|
for i, ch := range b {
|
||||||
|
hex[i] = fmt.Sprintf("%X", ch)
|
||||||
|
}
|
||||||
|
return strings.Join(hex, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ensureInRange adjusts the passed value, if necessary, to ensure it is within
|
||||||
|
// the passed min / max range.
|
||||||
|
func ensureInRange(n int16, min int16, max int16) int16 {
|
||||||
|
if n < min {
|
||||||
|
return min
|
||||||
|
} else if n > max {
|
||||||
|
return max
|
||||||
|
} else {
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetStdFile(nFile int) (*os.File, uintptr) {
|
||||||
|
var file *os.File
|
||||||
|
switch nFile {
|
||||||
|
case syscall.STD_INPUT_HANDLE:
|
||||||
|
file = os.Stdin
|
||||||
|
case syscall.STD_OUTPUT_HANDLE:
|
||||||
|
file = os.Stdout
|
||||||
|
case syscall.STD_ERROR_HANDLE:
|
||||||
|
file = os.Stderr
|
||||||
|
default:
|
||||||
|
panic(fmt.Errorf("Invalid standard handle identifier: %v", nFile))
|
||||||
|
}
|
||||||
|
|
||||||
|
fd, err := syscall.GetStdHandle(nFile)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Errorf("Invalid standard handle identifier: %v -- %v", nFile, err))
|
||||||
|
}
|
||||||
|
|
||||||
|
return file, uintptr(fd)
|
||||||
|
}
|
327
vendor/github.com/Azure/go-ansiterm/winterm/api.go
generated
vendored
Normal file
327
vendor/github.com/Azure/go-ansiterm/winterm/api.go
generated
vendored
Normal file
@ -0,0 +1,327 @@
|
|||||||
|
// +build windows
|
||||||
|
|
||||||
|
package winterm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
//===========================================================================================================
|
||||||
|
// IMPORTANT NOTE:
|
||||||
|
//
|
||||||
|
// The methods below make extensive use of the "unsafe" package to obtain the required pointers.
|
||||||
|
// Beginning in Go 1.3, the garbage collector may release local variables (e.g., incoming arguments, stack
|
||||||
|
// variables) the pointers reference *before* the API completes.
|
||||||
|
//
|
||||||
|
// As a result, in those cases, the code must hint that the variables remain in active by invoking the
|
||||||
|
// dummy method "use" (see below). Newer versions of Go are planned to change the mechanism to no longer
|
||||||
|
// require unsafe pointers.
|
||||||
|
//
|
||||||
|
// If you add or modify methods, ENSURE protection of local variables through the "use" builtin to inform
|
||||||
|
// the garbage collector the variables remain in use if:
|
||||||
|
//
|
||||||
|
// -- The value is not a pointer (e.g., int32, struct)
|
||||||
|
// -- The value is not referenced by the method after passing the pointer to Windows
|
||||||
|
//
|
||||||
|
// See http://golang.org/doc/go1.3.
|
||||||
|
//===========================================================================================================
|
||||||
|
|
||||||
|
var (
|
||||||
|
kernel32DLL = syscall.NewLazyDLL("kernel32.dll")
|
||||||
|
|
||||||
|
getConsoleCursorInfoProc = kernel32DLL.NewProc("GetConsoleCursorInfo")
|
||||||
|
setConsoleCursorInfoProc = kernel32DLL.NewProc("SetConsoleCursorInfo")
|
||||||
|
setConsoleCursorPositionProc = kernel32DLL.NewProc("SetConsoleCursorPosition")
|
||||||
|
setConsoleModeProc = kernel32DLL.NewProc("SetConsoleMode")
|
||||||
|
getConsoleScreenBufferInfoProc = kernel32DLL.NewProc("GetConsoleScreenBufferInfo")
|
||||||
|
setConsoleScreenBufferSizeProc = kernel32DLL.NewProc("SetConsoleScreenBufferSize")
|
||||||
|
scrollConsoleScreenBufferProc = kernel32DLL.NewProc("ScrollConsoleScreenBufferA")
|
||||||
|
setConsoleTextAttributeProc = kernel32DLL.NewProc("SetConsoleTextAttribute")
|
||||||
|
setConsoleWindowInfoProc = kernel32DLL.NewProc("SetConsoleWindowInfo")
|
||||||
|
writeConsoleOutputProc = kernel32DLL.NewProc("WriteConsoleOutputW")
|
||||||
|
readConsoleInputProc = kernel32DLL.NewProc("ReadConsoleInputW")
|
||||||
|
waitForSingleObjectProc = kernel32DLL.NewProc("WaitForSingleObject")
|
||||||
|
)
|
||||||
|
|
||||||
|
// Windows Console constants
|
||||||
|
const (
|
||||||
|
// Console modes
|
||||||
|
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx.
|
||||||
|
ENABLE_PROCESSED_INPUT = 0x0001
|
||||||
|
ENABLE_LINE_INPUT = 0x0002
|
||||||
|
ENABLE_ECHO_INPUT = 0x0004
|
||||||
|
ENABLE_WINDOW_INPUT = 0x0008
|
||||||
|
ENABLE_MOUSE_INPUT = 0x0010
|
||||||
|
ENABLE_INSERT_MODE = 0x0020
|
||||||
|
ENABLE_QUICK_EDIT_MODE = 0x0040
|
||||||
|
ENABLE_EXTENDED_FLAGS = 0x0080
|
||||||
|
ENABLE_AUTO_POSITION = 0x0100
|
||||||
|
ENABLE_VIRTUAL_TERMINAL_INPUT = 0x0200
|
||||||
|
|
||||||
|
ENABLE_PROCESSED_OUTPUT = 0x0001
|
||||||
|
ENABLE_WRAP_AT_EOL_OUTPUT = 0x0002
|
||||||
|
ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004
|
||||||
|
DISABLE_NEWLINE_AUTO_RETURN = 0x0008
|
||||||
|
ENABLE_LVB_GRID_WORLDWIDE = 0x0010
|
||||||
|
|
||||||
|
// Character attributes
|
||||||
|
// Note:
|
||||||
|
// -- The attributes are combined to produce various colors (e.g., Blue + Green will create Cyan).
|
||||||
|
// Clearing all foreground or background colors results in black; setting all creates white.
|
||||||
|
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms682088(v=vs.85).aspx#_win32_character_attributes.
|
||||||
|
FOREGROUND_BLUE uint16 = 0x0001
|
||||||
|
FOREGROUND_GREEN uint16 = 0x0002
|
||||||
|
FOREGROUND_RED uint16 = 0x0004
|
||||||
|
FOREGROUND_INTENSITY uint16 = 0x0008
|
||||||
|
FOREGROUND_MASK uint16 = 0x000F
|
||||||
|
|
||||||
|
BACKGROUND_BLUE uint16 = 0x0010
|
||||||
|
BACKGROUND_GREEN uint16 = 0x0020
|
||||||
|
BACKGROUND_RED uint16 = 0x0040
|
||||||
|
BACKGROUND_INTENSITY uint16 = 0x0080
|
||||||
|
BACKGROUND_MASK uint16 = 0x00F0
|
||||||
|
|
||||||
|
COMMON_LVB_MASK uint16 = 0xFF00
|
||||||
|
COMMON_LVB_REVERSE_VIDEO uint16 = 0x4000
|
||||||
|
COMMON_LVB_UNDERSCORE uint16 = 0x8000
|
||||||
|
|
||||||
|
// Input event types
|
||||||
|
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683499(v=vs.85).aspx.
|
||||||
|
KEY_EVENT = 0x0001
|
||||||
|
MOUSE_EVENT = 0x0002
|
||||||
|
WINDOW_BUFFER_SIZE_EVENT = 0x0004
|
||||||
|
MENU_EVENT = 0x0008
|
||||||
|
FOCUS_EVENT = 0x0010
|
||||||
|
|
||||||
|
// WaitForSingleObject return codes
|
||||||
|
WAIT_ABANDONED = 0x00000080
|
||||||
|
WAIT_FAILED = 0xFFFFFFFF
|
||||||
|
WAIT_SIGNALED = 0x0000000
|
||||||
|
WAIT_TIMEOUT = 0x00000102
|
||||||
|
|
||||||
|
// WaitForSingleObject wait duration
|
||||||
|
WAIT_INFINITE = 0xFFFFFFFF
|
||||||
|
WAIT_ONE_SECOND = 1000
|
||||||
|
WAIT_HALF_SECOND = 500
|
||||||
|
WAIT_QUARTER_SECOND = 250
|
||||||
|
)
|
||||||
|
|
||||||
|
// Windows API Console types
|
||||||
|
// -- See https://msdn.microsoft.com/en-us/library/windows/desktop/ms682101(v=vs.85).aspx for Console specific types (e.g., COORD)
|
||||||
|
// -- See https://msdn.microsoft.com/en-us/library/aa296569(v=vs.60).aspx for comments on alignment
|
||||||
|
type (
|
||||||
|
CHAR_INFO struct {
|
||||||
|
UnicodeChar uint16
|
||||||
|
Attributes uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
CONSOLE_CURSOR_INFO struct {
|
||||||
|
Size uint32
|
||||||
|
Visible int32
|
||||||
|
}
|
||||||
|
|
||||||
|
CONSOLE_SCREEN_BUFFER_INFO struct {
|
||||||
|
Size COORD
|
||||||
|
CursorPosition COORD
|
||||||
|
Attributes uint16
|
||||||
|
Window SMALL_RECT
|
||||||
|
MaximumWindowSize COORD
|
||||||
|
}
|
||||||
|
|
||||||
|
COORD struct {
|
||||||
|
X int16
|
||||||
|
Y int16
|
||||||
|
}
|
||||||
|
|
||||||
|
SMALL_RECT struct {
|
||||||
|
Left int16
|
||||||
|
Top int16
|
||||||
|
Right int16
|
||||||
|
Bottom int16
|
||||||
|
}
|
||||||
|
|
||||||
|
// INPUT_RECORD is a C/C++ union of which KEY_EVENT_RECORD is one case, it is also the largest
|
||||||
|
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683499(v=vs.85).aspx.
|
||||||
|
INPUT_RECORD struct {
|
||||||
|
EventType uint16
|
||||||
|
KeyEvent KEY_EVENT_RECORD
|
||||||
|
}
|
||||||
|
|
||||||
|
KEY_EVENT_RECORD struct {
|
||||||
|
KeyDown int32
|
||||||
|
RepeatCount uint16
|
||||||
|
VirtualKeyCode uint16
|
||||||
|
VirtualScanCode uint16
|
||||||
|
UnicodeChar uint16
|
||||||
|
ControlKeyState uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
WINDOW_BUFFER_SIZE struct {
|
||||||
|
Size COORD
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// boolToBOOL converts a Go bool into a Windows int32.
|
||||||
|
func boolToBOOL(f bool) int32 {
|
||||||
|
if f {
|
||||||
|
return int32(1)
|
||||||
|
} else {
|
||||||
|
return int32(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetConsoleCursorInfo retrieves information about the size and visiblity of the console cursor.
|
||||||
|
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683163(v=vs.85).aspx.
|
||||||
|
func GetConsoleCursorInfo(handle uintptr, cursorInfo *CONSOLE_CURSOR_INFO) error {
|
||||||
|
r1, r2, err := getConsoleCursorInfoProc.Call(handle, uintptr(unsafe.Pointer(cursorInfo)), 0)
|
||||||
|
return checkError(r1, r2, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetConsoleCursorInfo sets the size and visiblity of the console cursor.
|
||||||
|
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686019(v=vs.85).aspx.
|
||||||
|
func SetConsoleCursorInfo(handle uintptr, cursorInfo *CONSOLE_CURSOR_INFO) error {
|
||||||
|
r1, r2, err := setConsoleCursorInfoProc.Call(handle, uintptr(unsafe.Pointer(cursorInfo)), 0)
|
||||||
|
return checkError(r1, r2, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetConsoleCursorPosition location of the console cursor.
|
||||||
|
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686025(v=vs.85).aspx.
|
||||||
|
func SetConsoleCursorPosition(handle uintptr, coord COORD) error {
|
||||||
|
r1, r2, err := setConsoleCursorPositionProc.Call(handle, coordToPointer(coord))
|
||||||
|
use(coord)
|
||||||
|
return checkError(r1, r2, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetConsoleMode gets the console mode for given file descriptor
|
||||||
|
// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms683167(v=vs.85).aspx.
|
||||||
|
func GetConsoleMode(handle uintptr) (mode uint32, err error) {
|
||||||
|
err = syscall.GetConsoleMode(syscall.Handle(handle), &mode)
|
||||||
|
return mode, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetConsoleMode sets the console mode for given file descriptor
|
||||||
|
// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx.
|
||||||
|
func SetConsoleMode(handle uintptr, mode uint32) error {
|
||||||
|
r1, r2, err := setConsoleModeProc.Call(handle, uintptr(mode), 0)
|
||||||
|
use(mode)
|
||||||
|
return checkError(r1, r2, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetConsoleScreenBufferInfo retrieves information about the specified console screen buffer.
|
||||||
|
// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms683171(v=vs.85).aspx.
|
||||||
|
func GetConsoleScreenBufferInfo(handle uintptr) (*CONSOLE_SCREEN_BUFFER_INFO, error) {
|
||||||
|
info := CONSOLE_SCREEN_BUFFER_INFO{}
|
||||||
|
err := checkError(getConsoleScreenBufferInfoProc.Call(handle, uintptr(unsafe.Pointer(&info)), 0))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &info, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ScrollConsoleScreenBuffer(handle uintptr, scrollRect SMALL_RECT, clipRect SMALL_RECT, destOrigin COORD, char CHAR_INFO) error {
|
||||||
|
r1, r2, err := scrollConsoleScreenBufferProc.Call(handle, uintptr(unsafe.Pointer(&scrollRect)), uintptr(unsafe.Pointer(&clipRect)), coordToPointer(destOrigin), uintptr(unsafe.Pointer(&char)))
|
||||||
|
use(scrollRect)
|
||||||
|
use(clipRect)
|
||||||
|
use(destOrigin)
|
||||||
|
use(char)
|
||||||
|
return checkError(r1, r2, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetConsoleScreenBufferSize sets the size of the console screen buffer.
|
||||||
|
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686044(v=vs.85).aspx.
|
||||||
|
func SetConsoleScreenBufferSize(handle uintptr, coord COORD) error {
|
||||||
|
r1, r2, err := setConsoleScreenBufferSizeProc.Call(handle, coordToPointer(coord))
|
||||||
|
use(coord)
|
||||||
|
return checkError(r1, r2, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetConsoleTextAttribute sets the attributes of characters written to the
|
||||||
|
// console screen buffer by the WriteFile or WriteConsole function.
|
||||||
|
// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms686047(v=vs.85).aspx.
|
||||||
|
func SetConsoleTextAttribute(handle uintptr, attribute uint16) error {
|
||||||
|
r1, r2, err := setConsoleTextAttributeProc.Call(handle, uintptr(attribute), 0)
|
||||||
|
use(attribute)
|
||||||
|
return checkError(r1, r2, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetConsoleWindowInfo sets the size and position of the console screen buffer's window.
|
||||||
|
// Note that the size and location must be within and no larger than the backing console screen buffer.
|
||||||
|
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686125(v=vs.85).aspx.
|
||||||
|
func SetConsoleWindowInfo(handle uintptr, isAbsolute bool, rect SMALL_RECT) error {
|
||||||
|
r1, r2, err := setConsoleWindowInfoProc.Call(handle, uintptr(boolToBOOL(isAbsolute)), uintptr(unsafe.Pointer(&rect)))
|
||||||
|
use(isAbsolute)
|
||||||
|
use(rect)
|
||||||
|
return checkError(r1, r2, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteConsoleOutput writes the CHAR_INFOs from the provided buffer to the active console buffer.
|
||||||
|
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms687404(v=vs.85).aspx.
|
||||||
|
func WriteConsoleOutput(handle uintptr, buffer []CHAR_INFO, bufferSize COORD, bufferCoord COORD, writeRegion *SMALL_RECT) error {
|
||||||
|
r1, r2, err := writeConsoleOutputProc.Call(handle, uintptr(unsafe.Pointer(&buffer[0])), coordToPointer(bufferSize), coordToPointer(bufferCoord), uintptr(unsafe.Pointer(writeRegion)))
|
||||||
|
use(buffer)
|
||||||
|
use(bufferSize)
|
||||||
|
use(bufferCoord)
|
||||||
|
return checkError(r1, r2, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadConsoleInput reads (and removes) data from the console input buffer.
|
||||||
|
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms684961(v=vs.85).aspx.
|
||||||
|
func ReadConsoleInput(handle uintptr, buffer []INPUT_RECORD, count *uint32) error {
|
||||||
|
r1, r2, err := readConsoleInputProc.Call(handle, uintptr(unsafe.Pointer(&buffer[0])), uintptr(len(buffer)), uintptr(unsafe.Pointer(count)))
|
||||||
|
use(buffer)
|
||||||
|
return checkError(r1, r2, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WaitForSingleObject waits for the passed handle to be signaled.
|
||||||
|
// It returns true if the handle was signaled; false otherwise.
|
||||||
|
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms687032(v=vs.85).aspx.
|
||||||
|
func WaitForSingleObject(handle uintptr, msWait uint32) (bool, error) {
|
||||||
|
r1, _, err := waitForSingleObjectProc.Call(handle, uintptr(uint32(msWait)))
|
||||||
|
switch r1 {
|
||||||
|
case WAIT_ABANDONED, WAIT_TIMEOUT:
|
||||||
|
return false, nil
|
||||||
|
case WAIT_SIGNALED:
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
use(msWait)
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// String helpers
|
||||||
|
func (info CONSOLE_SCREEN_BUFFER_INFO) String() string {
|
||||||
|
return fmt.Sprintf("Size(%v) Cursor(%v) Window(%v) Max(%v)", info.Size, info.CursorPosition, info.Window, info.MaximumWindowSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (coord COORD) String() string {
|
||||||
|
return fmt.Sprintf("%v,%v", coord.X, coord.Y)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rect SMALL_RECT) String() string {
|
||||||
|
return fmt.Sprintf("(%v,%v),(%v,%v)", rect.Left, rect.Top, rect.Right, rect.Bottom)
|
||||||
|
}
|
||||||
|
|
||||||
|
// checkError evaluates the results of a Windows API call and returns the error if it failed.
|
||||||
|
func checkError(r1, r2 uintptr, err error) error {
|
||||||
|
// Windows APIs return non-zero to indicate success
|
||||||
|
if r1 != 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the error if provided, otherwise default to EINVAL
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return syscall.EINVAL
|
||||||
|
}
|
||||||
|
|
||||||
|
// coordToPointer converts a COORD into a uintptr (by fooling the type system).
|
||||||
|
func coordToPointer(c COORD) uintptr {
|
||||||
|
// Note: This code assumes the two SHORTs are correctly laid out; the "cast" to uint32 is just to get a pointer to pass.
|
||||||
|
return uintptr(*((*uint32)(unsafe.Pointer(&c))))
|
||||||
|
}
|
||||||
|
|
||||||
|
// use is a no-op, but the compiler cannot see that it is.
|
||||||
|
// Calling use(p) ensures that p is kept live until that point.
|
||||||
|
func use(p interface{}) {}
|
100
vendor/github.com/Azure/go-ansiterm/winterm/attr_translation.go
generated
vendored
Normal file
100
vendor/github.com/Azure/go-ansiterm/winterm/attr_translation.go
generated
vendored
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
// +build windows
|
||||||
|
|
||||||
|
package winterm
|
||||||
|
|
||||||
|
import "github.com/Azure/go-ansiterm"
|
||||||
|
|
||||||
|
const (
|
||||||
|
FOREGROUND_COLOR_MASK = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
|
||||||
|
BACKGROUND_COLOR_MASK = BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE
|
||||||
|
)
|
||||||
|
|
||||||
|
// collectAnsiIntoWindowsAttributes modifies the passed Windows text mode flags to reflect the
|
||||||
|
// request represented by the passed ANSI mode.
|
||||||
|
func collectAnsiIntoWindowsAttributes(windowsMode uint16, inverted bool, baseMode uint16, ansiMode int16) (uint16, bool) {
|
||||||
|
switch ansiMode {
|
||||||
|
|
||||||
|
// Mode styles
|
||||||
|
case ansiterm.ANSI_SGR_BOLD:
|
||||||
|
windowsMode = windowsMode | FOREGROUND_INTENSITY
|
||||||
|
|
||||||
|
case ansiterm.ANSI_SGR_DIM, ansiterm.ANSI_SGR_BOLD_DIM_OFF:
|
||||||
|
windowsMode &^= FOREGROUND_INTENSITY
|
||||||
|
|
||||||
|
case ansiterm.ANSI_SGR_UNDERLINE:
|
||||||
|
windowsMode = windowsMode | COMMON_LVB_UNDERSCORE
|
||||||
|
|
||||||
|
case ansiterm.ANSI_SGR_REVERSE:
|
||||||
|
inverted = true
|
||||||
|
|
||||||
|
case ansiterm.ANSI_SGR_REVERSE_OFF:
|
||||||
|
inverted = false
|
||||||
|
|
||||||
|
case ansiterm.ANSI_SGR_UNDERLINE_OFF:
|
||||||
|
windowsMode &^= COMMON_LVB_UNDERSCORE
|
||||||
|
|
||||||
|
// Foreground colors
|
||||||
|
case ansiterm.ANSI_SGR_FOREGROUND_DEFAULT:
|
||||||
|
windowsMode = (windowsMode &^ FOREGROUND_MASK) | (baseMode & FOREGROUND_MASK)
|
||||||
|
|
||||||
|
case ansiterm.ANSI_SGR_FOREGROUND_BLACK:
|
||||||
|
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK)
|
||||||
|
|
||||||
|
case ansiterm.ANSI_SGR_FOREGROUND_RED:
|
||||||
|
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED
|
||||||
|
|
||||||
|
case ansiterm.ANSI_SGR_FOREGROUND_GREEN:
|
||||||
|
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_GREEN
|
||||||
|
|
||||||
|
case ansiterm.ANSI_SGR_FOREGROUND_YELLOW:
|
||||||
|
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED | FOREGROUND_GREEN
|
||||||
|
|
||||||
|
case ansiterm.ANSI_SGR_FOREGROUND_BLUE:
|
||||||
|
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_BLUE
|
||||||
|
|
||||||
|
case ansiterm.ANSI_SGR_FOREGROUND_MAGENTA:
|
||||||
|
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED | FOREGROUND_BLUE
|
||||||
|
|
||||||
|
case ansiterm.ANSI_SGR_FOREGROUND_CYAN:
|
||||||
|
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_GREEN | FOREGROUND_BLUE
|
||||||
|
|
||||||
|
case ansiterm.ANSI_SGR_FOREGROUND_WHITE:
|
||||||
|
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
|
||||||
|
|
||||||
|
// Background colors
|
||||||
|
case ansiterm.ANSI_SGR_BACKGROUND_DEFAULT:
|
||||||
|
// Black with no intensity
|
||||||
|
windowsMode = (windowsMode &^ BACKGROUND_MASK) | (baseMode & BACKGROUND_MASK)
|
||||||
|
|
||||||
|
case ansiterm.ANSI_SGR_BACKGROUND_BLACK:
|
||||||
|
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK)
|
||||||
|
|
||||||
|
case ansiterm.ANSI_SGR_BACKGROUND_RED:
|
||||||
|
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED
|
||||||
|
|
||||||
|
case ansiterm.ANSI_SGR_BACKGROUND_GREEN:
|
||||||
|
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_GREEN
|
||||||
|
|
||||||
|
case ansiterm.ANSI_SGR_BACKGROUND_YELLOW:
|
||||||
|
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED | BACKGROUND_GREEN
|
||||||
|
|
||||||
|
case ansiterm.ANSI_SGR_BACKGROUND_BLUE:
|
||||||
|
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_BLUE
|
||||||
|
|
||||||
|
case ansiterm.ANSI_SGR_BACKGROUND_MAGENTA:
|
||||||
|
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED | BACKGROUND_BLUE
|
||||||
|
|
||||||
|
case ansiterm.ANSI_SGR_BACKGROUND_CYAN:
|
||||||
|
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_GREEN | BACKGROUND_BLUE
|
||||||
|
|
||||||
|
case ansiterm.ANSI_SGR_BACKGROUND_WHITE:
|
||||||
|
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE
|
||||||
|
}
|
||||||
|
|
||||||
|
return windowsMode, inverted
|
||||||
|
}
|
||||||
|
|
||||||
|
// invertAttributes inverts the foreground and background colors of a Windows attributes value
|
||||||
|
func invertAttributes(windowsMode uint16) uint16 {
|
||||||
|
return (COMMON_LVB_MASK & windowsMode) | ((FOREGROUND_MASK & windowsMode) << 4) | ((BACKGROUND_MASK & windowsMode) >> 4)
|
||||||
|
}
|
101
vendor/github.com/Azure/go-ansiterm/winterm/cursor_helpers.go
generated
vendored
Normal file
101
vendor/github.com/Azure/go-ansiterm/winterm/cursor_helpers.go
generated
vendored
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
// +build windows
|
||||||
|
|
||||||
|
package winterm
|
||||||
|
|
||||||
|
const (
|
||||||
|
horizontal = iota
|
||||||
|
vertical
|
||||||
|
)
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) getCursorWindow(info *CONSOLE_SCREEN_BUFFER_INFO) SMALL_RECT {
|
||||||
|
if h.originMode {
|
||||||
|
sr := h.effectiveSr(info.Window)
|
||||||
|
return SMALL_RECT{
|
||||||
|
Top: sr.top,
|
||||||
|
Bottom: sr.bottom,
|
||||||
|
Left: 0,
|
||||||
|
Right: info.Size.X - 1,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return SMALL_RECT{
|
||||||
|
Top: info.Window.Top,
|
||||||
|
Bottom: info.Window.Bottom,
|
||||||
|
Left: 0,
|
||||||
|
Right: info.Size.X - 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// setCursorPosition sets the cursor to the specified position, bounded to the screen size
|
||||||
|
func (h *windowsAnsiEventHandler) setCursorPosition(position COORD, window SMALL_RECT) error {
|
||||||
|
position.X = ensureInRange(position.X, window.Left, window.Right)
|
||||||
|
position.Y = ensureInRange(position.Y, window.Top, window.Bottom)
|
||||||
|
err := SetConsoleCursorPosition(h.fd, position)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.logf("Cursor position set: (%d, %d)", position.X, position.Y)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) moveCursorVertical(param int) error {
|
||||||
|
return h.moveCursor(vertical, param)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) moveCursorHorizontal(param int) error {
|
||||||
|
return h.moveCursor(horizontal, param)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) moveCursor(moveMode int, param int) error {
|
||||||
|
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
position := info.CursorPosition
|
||||||
|
switch moveMode {
|
||||||
|
case horizontal:
|
||||||
|
position.X += int16(param)
|
||||||
|
case vertical:
|
||||||
|
position.Y += int16(param)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = h.setCursorPosition(position, h.getCursorWindow(info)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) moveCursorLine(param int) error {
|
||||||
|
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
position := info.CursorPosition
|
||||||
|
position.X = 0
|
||||||
|
position.Y += int16(param)
|
||||||
|
|
||||||
|
if err = h.setCursorPosition(position, h.getCursorWindow(info)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) moveCursorColumn(param int) error {
|
||||||
|
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
position := info.CursorPosition
|
||||||
|
position.X = int16(param) - 1
|
||||||
|
|
||||||
|
if err = h.setCursorPosition(position, h.getCursorWindow(info)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
84
vendor/github.com/Azure/go-ansiterm/winterm/erase_helpers.go
generated
vendored
Normal file
84
vendor/github.com/Azure/go-ansiterm/winterm/erase_helpers.go
generated
vendored
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
// +build windows
|
||||||
|
|
||||||
|
package winterm
|
||||||
|
|
||||||
|
import "github.com/Azure/go-ansiterm"
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) clearRange(attributes uint16, fromCoord COORD, toCoord COORD) error {
|
||||||
|
// Ignore an invalid (negative area) request
|
||||||
|
if toCoord.Y < fromCoord.Y {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
|
||||||
|
var coordStart = COORD{}
|
||||||
|
var coordEnd = COORD{}
|
||||||
|
|
||||||
|
xCurrent, yCurrent := fromCoord.X, fromCoord.Y
|
||||||
|
xEnd, yEnd := toCoord.X, toCoord.Y
|
||||||
|
|
||||||
|
// Clear any partial initial line
|
||||||
|
if xCurrent > 0 {
|
||||||
|
coordStart.X, coordStart.Y = xCurrent, yCurrent
|
||||||
|
coordEnd.X, coordEnd.Y = xEnd, yCurrent
|
||||||
|
|
||||||
|
err = h.clearRect(attributes, coordStart, coordEnd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
xCurrent = 0
|
||||||
|
yCurrent += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear intervening rectangular section
|
||||||
|
if yCurrent < yEnd {
|
||||||
|
coordStart.X, coordStart.Y = xCurrent, yCurrent
|
||||||
|
coordEnd.X, coordEnd.Y = xEnd, yEnd-1
|
||||||
|
|
||||||
|
err = h.clearRect(attributes, coordStart, coordEnd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
xCurrent = 0
|
||||||
|
yCurrent = yEnd
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear remaining partial ending line
|
||||||
|
coordStart.X, coordStart.Y = xCurrent, yCurrent
|
||||||
|
coordEnd.X, coordEnd.Y = xEnd, yEnd
|
||||||
|
|
||||||
|
err = h.clearRect(attributes, coordStart, coordEnd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) clearRect(attributes uint16, fromCoord COORD, toCoord COORD) error {
|
||||||
|
region := SMALL_RECT{Top: fromCoord.Y, Left: fromCoord.X, Bottom: toCoord.Y, Right: toCoord.X}
|
||||||
|
width := toCoord.X - fromCoord.X + 1
|
||||||
|
height := toCoord.Y - fromCoord.Y + 1
|
||||||
|
size := uint32(width) * uint32(height)
|
||||||
|
|
||||||
|
if size <= 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer := make([]CHAR_INFO, size)
|
||||||
|
|
||||||
|
char := CHAR_INFO{ansiterm.FILL_CHARACTER, attributes}
|
||||||
|
for i := 0; i < int(size); i++ {
|
||||||
|
buffer[i] = char
|
||||||
|
}
|
||||||
|
|
||||||
|
err := WriteConsoleOutput(h.fd, buffer, COORD{X: width, Y: height}, COORD{X: 0, Y: 0}, ®ion)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
118
vendor/github.com/Azure/go-ansiterm/winterm/scroll_helper.go
generated
vendored
Normal file
118
vendor/github.com/Azure/go-ansiterm/winterm/scroll_helper.go
generated
vendored
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
// +build windows
|
||||||
|
|
||||||
|
package winterm
|
||||||
|
|
||||||
|
// effectiveSr gets the current effective scroll region in buffer coordinates
|
||||||
|
func (h *windowsAnsiEventHandler) effectiveSr(window SMALL_RECT) scrollRegion {
|
||||||
|
top := addInRange(window.Top, h.sr.top, window.Top, window.Bottom)
|
||||||
|
bottom := addInRange(window.Top, h.sr.bottom, window.Top, window.Bottom)
|
||||||
|
if top >= bottom {
|
||||||
|
top = window.Top
|
||||||
|
bottom = window.Bottom
|
||||||
|
}
|
||||||
|
return scrollRegion{top: top, bottom: bottom}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) scrollUp(param int) error {
|
||||||
|
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
sr := h.effectiveSr(info.Window)
|
||||||
|
return h.scroll(param, sr, info)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) scrollDown(param int) error {
|
||||||
|
return h.scrollUp(-param)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) deleteLines(param int) error {
|
||||||
|
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
start := info.CursorPosition.Y
|
||||||
|
sr := h.effectiveSr(info.Window)
|
||||||
|
// Lines cannot be inserted or deleted outside the scrolling region.
|
||||||
|
if start >= sr.top && start <= sr.bottom {
|
||||||
|
sr.top = start
|
||||||
|
return h.scroll(param, sr, info)
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) insertLines(param int) error {
|
||||||
|
return h.deleteLines(-param)
|
||||||
|
}
|
||||||
|
|
||||||
|
// scroll scrolls the provided scroll region by param lines. The scroll region is in buffer coordinates.
|
||||||
|
func (h *windowsAnsiEventHandler) scroll(param int, sr scrollRegion, info *CONSOLE_SCREEN_BUFFER_INFO) error {
|
||||||
|
h.logf("scroll: scrollTop: %d, scrollBottom: %d", sr.top, sr.bottom)
|
||||||
|
h.logf("scroll: windowTop: %d, windowBottom: %d", info.Window.Top, info.Window.Bottom)
|
||||||
|
|
||||||
|
// Copy from and clip to the scroll region (full buffer width)
|
||||||
|
scrollRect := SMALL_RECT{
|
||||||
|
Top: sr.top,
|
||||||
|
Bottom: sr.bottom,
|
||||||
|
Left: 0,
|
||||||
|
Right: info.Size.X - 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Origin to which area should be copied
|
||||||
|
destOrigin := COORD{
|
||||||
|
X: 0,
|
||||||
|
Y: sr.top - int16(param),
|
||||||
|
}
|
||||||
|
|
||||||
|
char := CHAR_INFO{
|
||||||
|
UnicodeChar: ' ',
|
||||||
|
Attributes: h.attributes,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := ScrollConsoleScreenBuffer(h.fd, scrollRect, scrollRect, destOrigin, char); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) deleteCharacters(param int) error {
|
||||||
|
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return h.scrollLine(param, info.CursorPosition, info)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) insertCharacters(param int) error {
|
||||||
|
return h.deleteCharacters(-param)
|
||||||
|
}
|
||||||
|
|
||||||
|
// scrollLine scrolls a line horizontally starting at the provided position by a number of columns.
|
||||||
|
func (h *windowsAnsiEventHandler) scrollLine(columns int, position COORD, info *CONSOLE_SCREEN_BUFFER_INFO) error {
|
||||||
|
// Copy from and clip to the scroll region (full buffer width)
|
||||||
|
scrollRect := SMALL_RECT{
|
||||||
|
Top: position.Y,
|
||||||
|
Bottom: position.Y,
|
||||||
|
Left: position.X,
|
||||||
|
Right: info.Size.X - 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Origin to which area should be copied
|
||||||
|
destOrigin := COORD{
|
||||||
|
X: position.X - int16(columns),
|
||||||
|
Y: position.Y,
|
||||||
|
}
|
||||||
|
|
||||||
|
char := CHAR_INFO{
|
||||||
|
UnicodeChar: ' ',
|
||||||
|
Attributes: h.attributes,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := ScrollConsoleScreenBuffer(h.fd, scrollRect, scrollRect, destOrigin, char); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
9
vendor/github.com/Azure/go-ansiterm/winterm/utilities.go
generated
vendored
Normal file
9
vendor/github.com/Azure/go-ansiterm/winterm/utilities.go
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
// +build windows
|
||||||
|
|
||||||
|
package winterm
|
||||||
|
|
||||||
|
// AddInRange increments a value by the passed quantity while ensuring the values
|
||||||
|
// always remain within the supplied min / max range.
|
||||||
|
func addInRange(n int16, increment int16, min int16, max int16) int16 {
|
||||||
|
return ensureInRange(n+increment, min, max)
|
||||||
|
}
|
743
vendor/github.com/Azure/go-ansiterm/winterm/win_event_handler.go
generated
vendored
Normal file
743
vendor/github.com/Azure/go-ansiterm/winterm/win_event_handler.go
generated
vendored
Normal file
@ -0,0 +1,743 @@
|
|||||||
|
// +build windows
|
||||||
|
|
||||||
|
package winterm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/Azure/go-ansiterm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type windowsAnsiEventHandler struct {
|
||||||
|
fd uintptr
|
||||||
|
file *os.File
|
||||||
|
infoReset *CONSOLE_SCREEN_BUFFER_INFO
|
||||||
|
sr scrollRegion
|
||||||
|
buffer bytes.Buffer
|
||||||
|
attributes uint16
|
||||||
|
inverted bool
|
||||||
|
wrapNext bool
|
||||||
|
drewMarginByte bool
|
||||||
|
originMode bool
|
||||||
|
marginByte byte
|
||||||
|
curInfo *CONSOLE_SCREEN_BUFFER_INFO
|
||||||
|
curPos COORD
|
||||||
|
logf func(string, ...interface{})
|
||||||
|
}
|
||||||
|
|
||||||
|
type Option func(*windowsAnsiEventHandler)
|
||||||
|
|
||||||
|
func WithLogf(f func(string, ...interface{})) Option {
|
||||||
|
return func(w *windowsAnsiEventHandler) {
|
||||||
|
w.logf = f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateWinEventHandler(fd uintptr, file *os.File, opts ...Option) ansiterm.AnsiEventHandler {
|
||||||
|
infoReset, err := GetConsoleScreenBufferInfo(fd)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
h := &windowsAnsiEventHandler{
|
||||||
|
fd: fd,
|
||||||
|
file: file,
|
||||||
|
infoReset: infoReset,
|
||||||
|
attributes: infoReset.Attributes,
|
||||||
|
}
|
||||||
|
for _, o := range opts {
|
||||||
|
o(h)
|
||||||
|
}
|
||||||
|
|
||||||
|
if isDebugEnv := os.Getenv(ansiterm.LogEnv); isDebugEnv == "1" {
|
||||||
|
logFile, _ := os.Create("winEventHandler.log")
|
||||||
|
logger := log.New(logFile, "", log.LstdFlags)
|
||||||
|
if h.logf != nil {
|
||||||
|
l := h.logf
|
||||||
|
h.logf = func(s string, v ...interface{}) {
|
||||||
|
l(s, v...)
|
||||||
|
logger.Printf(s, v...)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
h.logf = logger.Printf
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if h.logf == nil {
|
||||||
|
h.logf = func(string, ...interface{}) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
|
||||||
|
type scrollRegion struct {
|
||||||
|
top int16
|
||||||
|
bottom int16
|
||||||
|
}
|
||||||
|
|
||||||
|
// simulateLF simulates a LF or CR+LF by scrolling if necessary to handle the
|
||||||
|
// current cursor position and scroll region settings, in which case it returns
|
||||||
|
// true. If no special handling is necessary, then it does nothing and returns
|
||||||
|
// false.
|
||||||
|
//
|
||||||
|
// In the false case, the caller should ensure that a carriage return
|
||||||
|
// and line feed are inserted or that the text is otherwise wrapped.
|
||||||
|
func (h *windowsAnsiEventHandler) simulateLF(includeCR bool) (bool, error) {
|
||||||
|
if h.wrapNext {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
h.clearWrap()
|
||||||
|
}
|
||||||
|
pos, info, err := h.getCurrentInfo()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
sr := h.effectiveSr(info.Window)
|
||||||
|
if pos.Y == sr.bottom {
|
||||||
|
// Scrolling is necessary. Let Windows automatically scroll if the scrolling region
|
||||||
|
// is the full window.
|
||||||
|
if sr.top == info.Window.Top && sr.bottom == info.Window.Bottom {
|
||||||
|
if includeCR {
|
||||||
|
pos.X = 0
|
||||||
|
h.updatePos(pos)
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// A custom scroll region is active. Scroll the window manually to simulate
|
||||||
|
// the LF.
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
h.logf("Simulating LF inside scroll region")
|
||||||
|
if err := h.scrollUp(1); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if includeCR {
|
||||||
|
pos.X = 0
|
||||||
|
if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
|
||||||
|
} else if pos.Y < info.Window.Bottom {
|
||||||
|
// Let Windows handle the LF.
|
||||||
|
pos.Y++
|
||||||
|
if includeCR {
|
||||||
|
pos.X = 0
|
||||||
|
}
|
||||||
|
h.updatePos(pos)
|
||||||
|
return false, nil
|
||||||
|
} else {
|
||||||
|
// The cursor is at the bottom of the screen but outside the scroll
|
||||||
|
// region. Skip the LF.
|
||||||
|
h.logf("Simulating LF outside scroll region")
|
||||||
|
if includeCR {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
pos.X = 0
|
||||||
|
if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// executeLF executes a LF without a CR.
|
||||||
|
func (h *windowsAnsiEventHandler) executeLF() error {
|
||||||
|
handled, err := h.simulateLF(false)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !handled {
|
||||||
|
// Windows LF will reset the cursor column position. Write the LF
|
||||||
|
// and restore the cursor position.
|
||||||
|
pos, _, err := h.getCurrentInfo()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.buffer.WriteByte(ansiterm.ANSI_LINE_FEED)
|
||||||
|
if pos.X != 0 {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.logf("Resetting cursor position for LF without CR")
|
||||||
|
if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) Print(b byte) error {
|
||||||
|
if h.wrapNext {
|
||||||
|
h.buffer.WriteByte(h.marginByte)
|
||||||
|
h.clearWrap()
|
||||||
|
if _, err := h.simulateLF(true); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pos, info, err := h.getCurrentInfo()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if pos.X == info.Size.X-1 {
|
||||||
|
h.wrapNext = true
|
||||||
|
h.marginByte = b
|
||||||
|
} else {
|
||||||
|
pos.X++
|
||||||
|
h.updatePos(pos)
|
||||||
|
h.buffer.WriteByte(b)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) Execute(b byte) error {
|
||||||
|
switch b {
|
||||||
|
case ansiterm.ANSI_TAB:
|
||||||
|
h.logf("Execute(TAB)")
|
||||||
|
// Move to the next tab stop, but preserve auto-wrap if already set.
|
||||||
|
if !h.wrapNext {
|
||||||
|
pos, info, err := h.getCurrentInfo()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
pos.X = (pos.X + 8) - pos.X%8
|
||||||
|
if pos.X >= info.Size.X {
|
||||||
|
pos.X = info.Size.X - 1
|
||||||
|
}
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
|
||||||
|
case ansiterm.ANSI_BEL:
|
||||||
|
h.buffer.WriteByte(ansiterm.ANSI_BEL)
|
||||||
|
return nil
|
||||||
|
|
||||||
|
case ansiterm.ANSI_BACKSPACE:
|
||||||
|
if h.wrapNext {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.clearWrap()
|
||||||
|
}
|
||||||
|
pos, _, err := h.getCurrentInfo()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if pos.X > 0 {
|
||||||
|
pos.X--
|
||||||
|
h.updatePos(pos)
|
||||||
|
h.buffer.WriteByte(ansiterm.ANSI_BACKSPACE)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
|
||||||
|
case ansiterm.ANSI_VERTICAL_TAB, ansiterm.ANSI_FORM_FEED:
|
||||||
|
// Treat as true LF.
|
||||||
|
return h.executeLF()
|
||||||
|
|
||||||
|
case ansiterm.ANSI_LINE_FEED:
|
||||||
|
// Simulate a CR and LF for now since there is no way in go-ansiterm
|
||||||
|
// to tell if the LF should include CR (and more things break when it's
|
||||||
|
// missing than when it's incorrectly added).
|
||||||
|
handled, err := h.simulateLF(true)
|
||||||
|
if handled || err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return h.buffer.WriteByte(ansiterm.ANSI_LINE_FEED)
|
||||||
|
|
||||||
|
case ansiterm.ANSI_CARRIAGE_RETURN:
|
||||||
|
if h.wrapNext {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.clearWrap()
|
||||||
|
}
|
||||||
|
pos, _, err := h.getCurrentInfo()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if pos.X != 0 {
|
||||||
|
pos.X = 0
|
||||||
|
h.updatePos(pos)
|
||||||
|
h.buffer.WriteByte(ansiterm.ANSI_CARRIAGE_RETURN)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) CUU(param int) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.logf("CUU: [%v]", []string{strconv.Itoa(param)})
|
||||||
|
h.clearWrap()
|
||||||
|
return h.moveCursorVertical(-param)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) CUD(param int) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.logf("CUD: [%v]", []string{strconv.Itoa(param)})
|
||||||
|
h.clearWrap()
|
||||||
|
return h.moveCursorVertical(param)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) CUF(param int) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.logf("CUF: [%v]", []string{strconv.Itoa(param)})
|
||||||
|
h.clearWrap()
|
||||||
|
return h.moveCursorHorizontal(param)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) CUB(param int) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.logf("CUB: [%v]", []string{strconv.Itoa(param)})
|
||||||
|
h.clearWrap()
|
||||||
|
return h.moveCursorHorizontal(-param)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) CNL(param int) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.logf("CNL: [%v]", []string{strconv.Itoa(param)})
|
||||||
|
h.clearWrap()
|
||||||
|
return h.moveCursorLine(param)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) CPL(param int) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.logf("CPL: [%v]", []string{strconv.Itoa(param)})
|
||||||
|
h.clearWrap()
|
||||||
|
return h.moveCursorLine(-param)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) CHA(param int) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.logf("CHA: [%v]", []string{strconv.Itoa(param)})
|
||||||
|
h.clearWrap()
|
||||||
|
return h.moveCursorColumn(param)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) VPA(param int) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.logf("VPA: [[%d]]", param)
|
||||||
|
h.clearWrap()
|
||||||
|
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
window := h.getCursorWindow(info)
|
||||||
|
position := info.CursorPosition
|
||||||
|
position.Y = window.Top + int16(param) - 1
|
||||||
|
return h.setCursorPosition(position, window)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) CUP(row int, col int) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.logf("CUP: [[%d %d]]", row, col)
|
||||||
|
h.clearWrap()
|
||||||
|
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
window := h.getCursorWindow(info)
|
||||||
|
position := COORD{window.Left + int16(col) - 1, window.Top + int16(row) - 1}
|
||||||
|
return h.setCursorPosition(position, window)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) HVP(row int, col int) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.logf("HVP: [[%d %d]]", row, col)
|
||||||
|
h.clearWrap()
|
||||||
|
return h.CUP(row, col)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) DECTCEM(visible bool) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.logf("DECTCEM: [%v]", []string{strconv.FormatBool(visible)})
|
||||||
|
h.clearWrap()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) DECOM(enable bool) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.logf("DECOM: [%v]", []string{strconv.FormatBool(enable)})
|
||||||
|
h.clearWrap()
|
||||||
|
h.originMode = enable
|
||||||
|
return h.CUP(1, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) DECCOLM(use132 bool) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.logf("DECCOLM: [%v]", []string{strconv.FormatBool(use132)})
|
||||||
|
h.clearWrap()
|
||||||
|
if err := h.ED(2); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
targetWidth := int16(80)
|
||||||
|
if use132 {
|
||||||
|
targetWidth = 132
|
||||||
|
}
|
||||||
|
if info.Size.X < targetWidth {
|
||||||
|
if err := SetConsoleScreenBufferSize(h.fd, COORD{targetWidth, info.Size.Y}); err != nil {
|
||||||
|
h.logf("set buffer failed: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
window := info.Window
|
||||||
|
window.Left = 0
|
||||||
|
window.Right = targetWidth - 1
|
||||||
|
if err := SetConsoleWindowInfo(h.fd, true, window); err != nil {
|
||||||
|
h.logf("set window failed: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if info.Size.X > targetWidth {
|
||||||
|
if err := SetConsoleScreenBufferSize(h.fd, COORD{targetWidth, info.Size.Y}); err != nil {
|
||||||
|
h.logf("set buffer failed: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SetConsoleCursorPosition(h.fd, COORD{0, 0})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) ED(param int) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.logf("ED: [%v]", []string{strconv.Itoa(param)})
|
||||||
|
h.clearWrap()
|
||||||
|
|
||||||
|
// [J -- Erases from the cursor to the end of the screen, including the cursor position.
|
||||||
|
// [1J -- Erases from the beginning of the screen to the cursor, including the cursor position.
|
||||||
|
// [2J -- Erases the complete display. The cursor does not move.
|
||||||
|
// Notes:
|
||||||
|
// -- Clearing the entire buffer, versus just the Window, works best for Windows Consoles
|
||||||
|
|
||||||
|
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var start COORD
|
||||||
|
var end COORD
|
||||||
|
|
||||||
|
switch param {
|
||||||
|
case 0:
|
||||||
|
start = info.CursorPosition
|
||||||
|
end = COORD{info.Size.X - 1, info.Size.Y - 1}
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
start = COORD{0, 0}
|
||||||
|
end = info.CursorPosition
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
start = COORD{0, 0}
|
||||||
|
end = COORD{info.Size.X - 1, info.Size.Y - 1}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = h.clearRange(h.attributes, start, end)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the whole buffer was cleared, move the window to the top while preserving
|
||||||
|
// the window-relative cursor position.
|
||||||
|
if param == 2 {
|
||||||
|
pos := info.CursorPosition
|
||||||
|
window := info.Window
|
||||||
|
pos.Y -= window.Top
|
||||||
|
window.Bottom -= window.Top
|
||||||
|
window.Top = 0
|
||||||
|
if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := SetConsoleWindowInfo(h.fd, true, window); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) EL(param int) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.logf("EL: [%v]", strconv.Itoa(param))
|
||||||
|
h.clearWrap()
|
||||||
|
|
||||||
|
// [K -- Erases from the cursor to the end of the line, including the cursor position.
|
||||||
|
// [1K -- Erases from the beginning of the line to the cursor, including the cursor position.
|
||||||
|
// [2K -- Erases the complete line.
|
||||||
|
|
||||||
|
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var start COORD
|
||||||
|
var end COORD
|
||||||
|
|
||||||
|
switch param {
|
||||||
|
case 0:
|
||||||
|
start = info.CursorPosition
|
||||||
|
end = COORD{info.Size.X, info.CursorPosition.Y}
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
start = COORD{0, info.CursorPosition.Y}
|
||||||
|
end = info.CursorPosition
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
start = COORD{0, info.CursorPosition.Y}
|
||||||
|
end = COORD{info.Size.X, info.CursorPosition.Y}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = h.clearRange(h.attributes, start, end)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) IL(param int) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.logf("IL: [%v]", strconv.Itoa(param))
|
||||||
|
h.clearWrap()
|
||||||
|
return h.insertLines(param)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) DL(param int) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.logf("DL: [%v]", strconv.Itoa(param))
|
||||||
|
h.clearWrap()
|
||||||
|
return h.deleteLines(param)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) ICH(param int) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.logf("ICH: [%v]", strconv.Itoa(param))
|
||||||
|
h.clearWrap()
|
||||||
|
return h.insertCharacters(param)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) DCH(param int) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.logf("DCH: [%v]", strconv.Itoa(param))
|
||||||
|
h.clearWrap()
|
||||||
|
return h.deleteCharacters(param)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) SGR(params []int) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
strings := []string{}
|
||||||
|
for _, v := range params {
|
||||||
|
strings = append(strings, strconv.Itoa(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
h.logf("SGR: [%v]", strings)
|
||||||
|
|
||||||
|
if len(params) <= 0 {
|
||||||
|
h.attributes = h.infoReset.Attributes
|
||||||
|
h.inverted = false
|
||||||
|
} else {
|
||||||
|
for _, attr := range params {
|
||||||
|
|
||||||
|
if attr == ansiterm.ANSI_SGR_RESET {
|
||||||
|
h.attributes = h.infoReset.Attributes
|
||||||
|
h.inverted = false
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
h.attributes, h.inverted = collectAnsiIntoWindowsAttributes(h.attributes, h.inverted, h.infoReset.Attributes, int16(attr))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
attributes := h.attributes
|
||||||
|
if h.inverted {
|
||||||
|
attributes = invertAttributes(attributes)
|
||||||
|
}
|
||||||
|
err := SetConsoleTextAttribute(h.fd, attributes)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) SU(param int) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.logf("SU: [%v]", []string{strconv.Itoa(param)})
|
||||||
|
h.clearWrap()
|
||||||
|
return h.scrollUp(param)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) SD(param int) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.logf("SD: [%v]", []string{strconv.Itoa(param)})
|
||||||
|
h.clearWrap()
|
||||||
|
return h.scrollDown(param)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) DA(params []string) error {
|
||||||
|
h.logf("DA: [%v]", params)
|
||||||
|
// DA cannot be implemented because it must send data on the VT100 input stream,
|
||||||
|
// which is not available to go-ansiterm.
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) DECSTBM(top int, bottom int) error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.logf("DECSTBM: [%d, %d]", top, bottom)
|
||||||
|
|
||||||
|
// Windows is 0 indexed, Linux is 1 indexed
|
||||||
|
h.sr.top = int16(top - 1)
|
||||||
|
h.sr.bottom = int16(bottom - 1)
|
||||||
|
|
||||||
|
// This command also moves the cursor to the origin.
|
||||||
|
h.clearWrap()
|
||||||
|
return h.CUP(1, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) RI() error {
|
||||||
|
if err := h.Flush(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.logf("RI: []")
|
||||||
|
h.clearWrap()
|
||||||
|
|
||||||
|
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
sr := h.effectiveSr(info.Window)
|
||||||
|
if info.CursorPosition.Y == sr.top {
|
||||||
|
return h.scrollDown(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return h.moveCursorVertical(-1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) IND() error {
|
||||||
|
h.logf("IND: []")
|
||||||
|
return h.executeLF()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) Flush() error {
|
||||||
|
h.curInfo = nil
|
||||||
|
if h.buffer.Len() > 0 {
|
||||||
|
h.logf("Flush: [%s]", h.buffer.Bytes())
|
||||||
|
if _, err := h.buffer.WriteTo(h.file); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if h.wrapNext && !h.drewMarginByte {
|
||||||
|
h.logf("Flush: drawing margin byte '%c'", h.marginByte)
|
||||||
|
|
||||||
|
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
charInfo := []CHAR_INFO{{UnicodeChar: uint16(h.marginByte), Attributes: info.Attributes}}
|
||||||
|
size := COORD{1, 1}
|
||||||
|
position := COORD{0, 0}
|
||||||
|
region := SMALL_RECT{Left: info.CursorPosition.X, Top: info.CursorPosition.Y, Right: info.CursorPosition.X, Bottom: info.CursorPosition.Y}
|
||||||
|
if err := WriteConsoleOutput(h.fd, charInfo, size, position, ®ion); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.drewMarginByte = true
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// cacheConsoleInfo ensures that the current console screen information has been queried
|
||||||
|
// since the last call to Flush(). It must be called before accessing h.curInfo or h.curPos.
|
||||||
|
func (h *windowsAnsiEventHandler) getCurrentInfo() (COORD, *CONSOLE_SCREEN_BUFFER_INFO, error) {
|
||||||
|
if h.curInfo == nil {
|
||||||
|
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||||
|
if err != nil {
|
||||||
|
return COORD{}, nil, err
|
||||||
|
}
|
||||||
|
h.curInfo = info
|
||||||
|
h.curPos = info.CursorPosition
|
||||||
|
}
|
||||||
|
return h.curPos, h.curInfo, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *windowsAnsiEventHandler) updatePos(pos COORD) {
|
||||||
|
if h.curInfo == nil {
|
||||||
|
panic("failed to call getCurrentInfo before calling updatePos")
|
||||||
|
}
|
||||||
|
h.curPos = pos
|
||||||
|
}
|
||||||
|
|
||||||
|
// clearWrap clears the state where the cursor is in the margin
|
||||||
|
// waiting for the next character before wrapping the line. This must
|
||||||
|
// be done before most operations that act on the cursor.
|
||||||
|
func (h *windowsAnsiEventHandler) clearWrap() {
|
||||||
|
h.wrapNext = false
|
||||||
|
h.drewMarginByte = false
|
||||||
|
}
|
5
vendor/github.com/BurntSushi/toml/.gitignore
generated
vendored
Normal file
5
vendor/github.com/BurntSushi/toml/.gitignore
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
TAGS
|
||||||
|
tags
|
||||||
|
.*.swp
|
||||||
|
tomlcheck/tomlcheck
|
||||||
|
toml.test
|
15
vendor/github.com/BurntSushi/toml/.travis.yml
generated
vendored
Normal file
15
vendor/github.com/BurntSushi/toml/.travis.yml
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
language: go
|
||||||
|
go:
|
||||||
|
- 1.1
|
||||||
|
- 1.2
|
||||||
|
- 1.3
|
||||||
|
- 1.4
|
||||||
|
- 1.5
|
||||||
|
- 1.6
|
||||||
|
- tip
|
||||||
|
install:
|
||||||
|
- go install ./...
|
||||||
|
- go get github.com/BurntSushi/toml-test
|
||||||
|
script:
|
||||||
|
- export PATH="$PATH:$HOME/gopath/bin"
|
||||||
|
- make test
|
3
vendor/github.com/BurntSushi/toml/COMPATIBLE
generated
vendored
Normal file
3
vendor/github.com/BurntSushi/toml/COMPATIBLE
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
Compatible with TOML version
|
||||||
|
[v0.4.0](https://github.com/toml-lang/toml/blob/v0.4.0/versions/en/toml-v0.4.0.md)
|
||||||
|
|
21
vendor/github.com/BurntSushi/toml/COPYING
generated
vendored
Normal file
21
vendor/github.com/BurntSushi/toml/COPYING
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2013 TOML authors
|
||||||
|
|
||||||
|
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.
|
19
vendor/github.com/BurntSushi/toml/Makefile
generated
vendored
Normal file
19
vendor/github.com/BurntSushi/toml/Makefile
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
install:
|
||||||
|
go install ./...
|
||||||
|
|
||||||
|
test: install
|
||||||
|
go test -v
|
||||||
|
toml-test toml-test-decoder
|
||||||
|
toml-test -encoder toml-test-encoder
|
||||||
|
|
||||||
|
fmt:
|
||||||
|
gofmt -w *.go */*.go
|
||||||
|
colcheck *.go */*.go
|
||||||
|
|
||||||
|
tags:
|
||||||
|
find ./ -name '*.go' -print0 | xargs -0 gotags > TAGS
|
||||||
|
|
||||||
|
push:
|
||||||
|
git push origin master
|
||||||
|
git push github master
|
||||||
|
|
218
vendor/github.com/BurntSushi/toml/README.md
generated
vendored
Normal file
218
vendor/github.com/BurntSushi/toml/README.md
generated
vendored
Normal file
@ -0,0 +1,218 @@
|
|||||||
|
## TOML parser and encoder for Go with reflection
|
||||||
|
|
||||||
|
TOML stands for Tom's Obvious, Minimal Language. This Go package provides a
|
||||||
|
reflection interface similar to Go's standard library `json` and `xml`
|
||||||
|
packages. This package also supports the `encoding.TextUnmarshaler` and
|
||||||
|
`encoding.TextMarshaler` interfaces so that you can define custom data
|
||||||
|
representations. (There is an example of this below.)
|
||||||
|
|
||||||
|
Spec: https://github.com/toml-lang/toml
|
||||||
|
|
||||||
|
Compatible with TOML version
|
||||||
|
[v0.4.0](https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.4.0.md)
|
||||||
|
|
||||||
|
Documentation: https://godoc.org/github.com/BurntSushi/toml
|
||||||
|
|
||||||
|
Installation:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go get github.com/BurntSushi/toml
|
||||||
|
```
|
||||||
|
|
||||||
|
Try the toml validator:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go get github.com/BurntSushi/toml/cmd/tomlv
|
||||||
|
tomlv some-toml-file.toml
|
||||||
|
```
|
||||||
|
|
||||||
|
[![Build Status](https://travis-ci.org/BurntSushi/toml.svg?branch=master)](https://travis-ci.org/BurntSushi/toml) [![GoDoc](https://godoc.org/github.com/BurntSushi/toml?status.svg)](https://godoc.org/github.com/BurntSushi/toml)
|
||||||
|
|
||||||
|
### Testing
|
||||||
|
|
||||||
|
This package passes all tests in
|
||||||
|
[toml-test](https://github.com/BurntSushi/toml-test) for both the decoder
|
||||||
|
and the encoder.
|
||||||
|
|
||||||
|
### Examples
|
||||||
|
|
||||||
|
This package works similarly to how the Go standard library handles `XML`
|
||||||
|
and `JSON`. Namely, data is loaded into Go values via reflection.
|
||||||
|
|
||||||
|
For the simplest example, consider some TOML file as just a list of keys
|
||||||
|
and values:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
Age = 25
|
||||||
|
Cats = [ "Cauchy", "Plato" ]
|
||||||
|
Pi = 3.14
|
||||||
|
Perfection = [ 6, 28, 496, 8128 ]
|
||||||
|
DOB = 1987-07-05T05:45:00Z
|
||||||
|
```
|
||||||
|
|
||||||
|
Which could be defined in Go as:
|
||||||
|
|
||||||
|
```go
|
||||||
|
type Config struct {
|
||||||
|
Age int
|
||||||
|
Cats []string
|
||||||
|
Pi float64
|
||||||
|
Perfection []int
|
||||||
|
DOB time.Time // requires `import time`
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
And then decoded with:
|
||||||
|
|
||||||
|
```go
|
||||||
|
var conf Config
|
||||||
|
if _, err := toml.Decode(tomlData, &conf); err != nil {
|
||||||
|
// handle error
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also use struct tags if your struct field name doesn't map to a TOML
|
||||||
|
key value directly:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
some_key_NAME = "wat"
|
||||||
|
```
|
||||||
|
|
||||||
|
```go
|
||||||
|
type TOML struct {
|
||||||
|
ObscureKey string `toml:"some_key_NAME"`
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Using the `encoding.TextUnmarshaler` interface
|
||||||
|
|
||||||
|
Here's an example that automatically parses duration strings into
|
||||||
|
`time.Duration` values:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[[song]]
|
||||||
|
name = "Thunder Road"
|
||||||
|
duration = "4m49s"
|
||||||
|
|
||||||
|
[[song]]
|
||||||
|
name = "Stairway to Heaven"
|
||||||
|
duration = "8m03s"
|
||||||
|
```
|
||||||
|
|
||||||
|
Which can be decoded with:
|
||||||
|
|
||||||
|
```go
|
||||||
|
type song struct {
|
||||||
|
Name string
|
||||||
|
Duration duration
|
||||||
|
}
|
||||||
|
type songs struct {
|
||||||
|
Song []song
|
||||||
|
}
|
||||||
|
var favorites songs
|
||||||
|
if _, err := toml.Decode(blob, &favorites); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, s := range favorites.Song {
|
||||||
|
fmt.Printf("%s (%s)\n", s.Name, s.Duration)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
And you'll also need a `duration` type that satisfies the
|
||||||
|
`encoding.TextUnmarshaler` interface:
|
||||||
|
|
||||||
|
```go
|
||||||
|
type duration struct {
|
||||||
|
time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *duration) UnmarshalText(text []byte) error {
|
||||||
|
var err error
|
||||||
|
d.Duration, err = time.ParseDuration(string(text))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### More complex usage
|
||||||
|
|
||||||
|
Here's an example of how to load the example from the official spec page:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
# This is a TOML document. Boom.
|
||||||
|
|
||||||
|
title = "TOML Example"
|
||||||
|
|
||||||
|
[owner]
|
||||||
|
name = "Tom Preston-Werner"
|
||||||
|
organization = "GitHub"
|
||||||
|
bio = "GitHub Cofounder & CEO\nLikes tater tots and beer."
|
||||||
|
dob = 1979-05-27T07:32:00Z # First class dates? Why not?
|
||||||
|
|
||||||
|
[database]
|
||||||
|
server = "192.168.1.1"
|
||||||
|
ports = [ 8001, 8001, 8002 ]
|
||||||
|
connection_max = 5000
|
||||||
|
enabled = true
|
||||||
|
|
||||||
|
[servers]
|
||||||
|
|
||||||
|
# You can indent as you please. Tabs or spaces. TOML don't care.
|
||||||
|
[servers.alpha]
|
||||||
|
ip = "10.0.0.1"
|
||||||
|
dc = "eqdc10"
|
||||||
|
|
||||||
|
[servers.beta]
|
||||||
|
ip = "10.0.0.2"
|
||||||
|
dc = "eqdc10"
|
||||||
|
|
||||||
|
[clients]
|
||||||
|
data = [ ["gamma", "delta"], [1, 2] ] # just an update to make sure parsers support it
|
||||||
|
|
||||||
|
# Line breaks are OK when inside arrays
|
||||||
|
hosts = [
|
||||||
|
"alpha",
|
||||||
|
"omega"
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
And the corresponding Go types are:
|
||||||
|
|
||||||
|
```go
|
||||||
|
type tomlConfig struct {
|
||||||
|
Title string
|
||||||
|
Owner ownerInfo
|
||||||
|
DB database `toml:"database"`
|
||||||
|
Servers map[string]server
|
||||||
|
Clients clients
|
||||||
|
}
|
||||||
|
|
||||||
|
type ownerInfo struct {
|
||||||
|
Name string
|
||||||
|
Org string `toml:"organization"`
|
||||||
|
Bio string
|
||||||
|
DOB time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
type database struct {
|
||||||
|
Server string
|
||||||
|
Ports []int
|
||||||
|
ConnMax int `toml:"connection_max"`
|
||||||
|
Enabled bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type server struct {
|
||||||
|
IP string
|
||||||
|
DC string
|
||||||
|
}
|
||||||
|
|
||||||
|
type clients struct {
|
||||||
|
Data [][]interface{}
|
||||||
|
Hosts []string
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that a case insensitive match will be tried if an exact match can't be
|
||||||
|
found.
|
||||||
|
|
||||||
|
A working example of the above can be found in `_examples/example.{go,toml}`.
|
509
vendor/github.com/BurntSushi/toml/decode.go
generated
vendored
Normal file
509
vendor/github.com/BurntSushi/toml/decode.go
generated
vendored
Normal file
@ -0,0 +1,509 @@
|
|||||||
|
package toml
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"math"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func e(format string, args ...interface{}) error {
|
||||||
|
return fmt.Errorf("toml: "+format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmarshaler is the interface implemented by objects that can unmarshal a
|
||||||
|
// TOML description of themselves.
|
||||||
|
type Unmarshaler interface {
|
||||||
|
UnmarshalTOML(interface{}) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmarshal decodes the contents of `p` in TOML format into a pointer `v`.
|
||||||
|
func Unmarshal(p []byte, v interface{}) error {
|
||||||
|
_, err := Decode(string(p), v)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Primitive is a TOML value that hasn't been decoded into a Go value.
|
||||||
|
// When using the various `Decode*` functions, the type `Primitive` may
|
||||||
|
// be given to any value, and its decoding will be delayed.
|
||||||
|
//
|
||||||
|
// A `Primitive` value can be decoded using the `PrimitiveDecode` function.
|
||||||
|
//
|
||||||
|
// The underlying representation of a `Primitive` value is subject to change.
|
||||||
|
// Do not rely on it.
|
||||||
|
//
|
||||||
|
// N.B. Primitive values are still parsed, so using them will only avoid
|
||||||
|
// the overhead of reflection. They can be useful when you don't know the
|
||||||
|
// exact type of TOML data until run time.
|
||||||
|
type Primitive struct {
|
||||||
|
undecoded interface{}
|
||||||
|
context Key
|
||||||
|
}
|
||||||
|
|
||||||
|
// DEPRECATED!
|
||||||
|
//
|
||||||
|
// Use MetaData.PrimitiveDecode instead.
|
||||||
|
func PrimitiveDecode(primValue Primitive, v interface{}) error {
|
||||||
|
md := MetaData{decoded: make(map[string]bool)}
|
||||||
|
return md.unify(primValue.undecoded, rvalue(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
// PrimitiveDecode is just like the other `Decode*` functions, except it
|
||||||
|
// decodes a TOML value that has already been parsed. Valid primitive values
|
||||||
|
// can *only* be obtained from values filled by the decoder functions,
|
||||||
|
// including this method. (i.e., `v` may contain more `Primitive`
|
||||||
|
// values.)
|
||||||
|
//
|
||||||
|
// Meta data for primitive values is included in the meta data returned by
|
||||||
|
// the `Decode*` functions with one exception: keys returned by the Undecoded
|
||||||
|
// method will only reflect keys that were decoded. Namely, any keys hidden
|
||||||
|
// behind a Primitive will be considered undecoded. Executing this method will
|
||||||
|
// update the undecoded keys in the meta data. (See the example.)
|
||||||
|
func (md *MetaData) PrimitiveDecode(primValue Primitive, v interface{}) error {
|
||||||
|
md.context = primValue.context
|
||||||
|
defer func() { md.context = nil }()
|
||||||
|
return md.unify(primValue.undecoded, rvalue(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode will decode the contents of `data` in TOML format into a pointer
|
||||||
|
// `v`.
|
||||||
|
//
|
||||||
|
// TOML hashes correspond to Go structs or maps. (Dealer's choice. They can be
|
||||||
|
// used interchangeably.)
|
||||||
|
//
|
||||||
|
// TOML arrays of tables correspond to either a slice of structs or a slice
|
||||||
|
// of maps.
|
||||||
|
//
|
||||||
|
// TOML datetimes correspond to Go `time.Time` values.
|
||||||
|
//
|
||||||
|
// All other TOML types (float, string, int, bool and array) correspond
|
||||||
|
// to the obvious Go types.
|
||||||
|
//
|
||||||
|
// An exception to the above rules is if a type implements the
|
||||||
|
// encoding.TextUnmarshaler interface. In this case, any primitive TOML value
|
||||||
|
// (floats, strings, integers, booleans and datetimes) will be converted to
|
||||||
|
// a byte string and given to the value's UnmarshalText method. See the
|
||||||
|
// Unmarshaler example for a demonstration with time duration strings.
|
||||||
|
//
|
||||||
|
// Key mapping
|
||||||
|
//
|
||||||
|
// TOML keys can map to either keys in a Go map or field names in a Go
|
||||||
|
// struct. The special `toml` struct tag may be used to map TOML keys to
|
||||||
|
// struct fields that don't match the key name exactly. (See the example.)
|
||||||
|
// A case insensitive match to struct names will be tried if an exact match
|
||||||
|
// can't be found.
|
||||||
|
//
|
||||||
|
// The mapping between TOML values and Go values is loose. That is, there
|
||||||
|
// may exist TOML values that cannot be placed into your representation, and
|
||||||
|
// there may be parts of your representation that do not correspond to
|
||||||
|
// TOML values. This loose mapping can be made stricter by using the IsDefined
|
||||||
|
// and/or Undecoded methods on the MetaData returned.
|
||||||
|
//
|
||||||
|
// This decoder will not handle cyclic types. If a cyclic type is passed,
|
||||||
|
// `Decode` will not terminate.
|
||||||
|
func Decode(data string, v interface{}) (MetaData, error) {
|
||||||
|
rv := reflect.ValueOf(v)
|
||||||
|
if rv.Kind() != reflect.Ptr {
|
||||||
|
return MetaData{}, e("Decode of non-pointer %s", reflect.TypeOf(v))
|
||||||
|
}
|
||||||
|
if rv.IsNil() {
|
||||||
|
return MetaData{}, e("Decode of nil %s", reflect.TypeOf(v))
|
||||||
|
}
|
||||||
|
p, err := parse(data)
|
||||||
|
if err != nil {
|
||||||
|
return MetaData{}, err
|
||||||
|
}
|
||||||
|
md := MetaData{
|
||||||
|
p.mapping, p.types, p.ordered,
|
||||||
|
make(map[string]bool, len(p.ordered)), nil,
|
||||||
|
}
|
||||||
|
return md, md.unify(p.mapping, indirect(rv))
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecodeFile is just like Decode, except it will automatically read the
|
||||||
|
// contents of the file at `fpath` and decode it for you.
|
||||||
|
func DecodeFile(fpath string, v interface{}) (MetaData, error) {
|
||||||
|
bs, err := ioutil.ReadFile(fpath)
|
||||||
|
if err != nil {
|
||||||
|
return MetaData{}, err
|
||||||
|
}
|
||||||
|
return Decode(string(bs), v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecodeReader is just like Decode, except it will consume all bytes
|
||||||
|
// from the reader and decode it for you.
|
||||||
|
func DecodeReader(r io.Reader, v interface{}) (MetaData, error) {
|
||||||
|
bs, err := ioutil.ReadAll(r)
|
||||||
|
if err != nil {
|
||||||
|
return MetaData{}, err
|
||||||
|
}
|
||||||
|
return Decode(string(bs), v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// unify performs a sort of type unification based on the structure of `rv`,
|
||||||
|
// which is the client representation.
|
||||||
|
//
|
||||||
|
// Any type mismatch produces an error. Finding a type that we don't know
|
||||||
|
// how to handle produces an unsupported type error.
|
||||||
|
func (md *MetaData) unify(data interface{}, rv reflect.Value) error {
|
||||||
|
|
||||||
|
// Special case. Look for a `Primitive` value.
|
||||||
|
if rv.Type() == reflect.TypeOf((*Primitive)(nil)).Elem() {
|
||||||
|
// Save the undecoded data and the key context into the primitive
|
||||||
|
// value.
|
||||||
|
context := make(Key, len(md.context))
|
||||||
|
copy(context, md.context)
|
||||||
|
rv.Set(reflect.ValueOf(Primitive{
|
||||||
|
undecoded: data,
|
||||||
|
context: context,
|
||||||
|
}))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Special case. Unmarshaler Interface support.
|
||||||
|
if rv.CanAddr() {
|
||||||
|
if v, ok := rv.Addr().Interface().(Unmarshaler); ok {
|
||||||
|
return v.UnmarshalTOML(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Special case. Handle time.Time values specifically.
|
||||||
|
// TODO: Remove this code when we decide to drop support for Go 1.1.
|
||||||
|
// This isn't necessary in Go 1.2 because time.Time satisfies the encoding
|
||||||
|
// interfaces.
|
||||||
|
if rv.Type().AssignableTo(rvalue(time.Time{}).Type()) {
|
||||||
|
return md.unifyDatetime(data, rv)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Special case. Look for a value satisfying the TextUnmarshaler interface.
|
||||||
|
if v, ok := rv.Interface().(TextUnmarshaler); ok {
|
||||||
|
return md.unifyText(data, v)
|
||||||
|
}
|
||||||
|
// BUG(burntsushi)
|
||||||
|
// The behavior here is incorrect whenever a Go type satisfies the
|
||||||
|
// encoding.TextUnmarshaler interface but also corresponds to a TOML
|
||||||
|
// hash or array. In particular, the unmarshaler should only be applied
|
||||||
|
// to primitive TOML values. But at this point, it will be applied to
|
||||||
|
// all kinds of values and produce an incorrect error whenever those values
|
||||||
|
// are hashes or arrays (including arrays of tables).
|
||||||
|
|
||||||
|
k := rv.Kind()
|
||||||
|
|
||||||
|
// laziness
|
||||||
|
if k >= reflect.Int && k <= reflect.Uint64 {
|
||||||
|
return md.unifyInt(data, rv)
|
||||||
|
}
|
||||||
|
switch k {
|
||||||
|
case reflect.Ptr:
|
||||||
|
elem := reflect.New(rv.Type().Elem())
|
||||||
|
err := md.unify(data, reflect.Indirect(elem))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
rv.Set(elem)
|
||||||
|
return nil
|
||||||
|
case reflect.Struct:
|
||||||
|
return md.unifyStruct(data, rv)
|
||||||
|
case reflect.Map:
|
||||||
|
return md.unifyMap(data, rv)
|
||||||
|
case reflect.Array:
|
||||||
|
return md.unifyArray(data, rv)
|
||||||
|
case reflect.Slice:
|
||||||
|
return md.unifySlice(data, rv)
|
||||||
|
case reflect.String:
|
||||||
|
return md.unifyString(data, rv)
|
||||||
|
case reflect.Bool:
|
||||||
|
return md.unifyBool(data, rv)
|
||||||
|
case reflect.Interface:
|
||||||
|
// we only support empty interfaces.
|
||||||
|
if rv.NumMethod() > 0 {
|
||||||
|
return e("unsupported type %s", rv.Type())
|
||||||
|
}
|
||||||
|
return md.unifyAnything(data, rv)
|
||||||
|
case reflect.Float32:
|
||||||
|
fallthrough
|
||||||
|
case reflect.Float64:
|
||||||
|
return md.unifyFloat64(data, rv)
|
||||||
|
}
|
||||||
|
return e("unsupported type %s", rv.Kind())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (md *MetaData) unifyStruct(mapping interface{}, rv reflect.Value) error {
|
||||||
|
tmap, ok := mapping.(map[string]interface{})
|
||||||
|
if !ok {
|
||||||
|
if mapping == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return e("type mismatch for %s: expected table but found %T",
|
||||||
|
rv.Type().String(), mapping)
|
||||||
|
}
|
||||||
|
|
||||||
|
for key, datum := range tmap {
|
||||||
|
var f *field
|
||||||
|
fields := cachedTypeFields(rv.Type())
|
||||||
|
for i := range fields {
|
||||||
|
ff := &fields[i]
|
||||||
|
if ff.name == key {
|
||||||
|
f = ff
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if f == nil && strings.EqualFold(ff.name, key) {
|
||||||
|
f = ff
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if f != nil {
|
||||||
|
subv := rv
|
||||||
|
for _, i := range f.index {
|
||||||
|
subv = indirect(subv.Field(i))
|
||||||
|
}
|
||||||
|
if isUnifiable(subv) {
|
||||||
|
md.decoded[md.context.add(key).String()] = true
|
||||||
|
md.context = append(md.context, key)
|
||||||
|
if err := md.unify(datum, subv); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
md.context = md.context[0 : len(md.context)-1]
|
||||||
|
} else if f.name != "" {
|
||||||
|
// Bad user! No soup for you!
|
||||||
|
return e("cannot write unexported field %s.%s",
|
||||||
|
rv.Type().String(), f.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (md *MetaData) unifyMap(mapping interface{}, rv reflect.Value) error {
|
||||||
|
tmap, ok := mapping.(map[string]interface{})
|
||||||
|
if !ok {
|
||||||
|
if tmap == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return badtype("map", mapping)
|
||||||
|
}
|
||||||
|
if rv.IsNil() {
|
||||||
|
rv.Set(reflect.MakeMap(rv.Type()))
|
||||||
|
}
|
||||||
|
for k, v := range tmap {
|
||||||
|
md.decoded[md.context.add(k).String()] = true
|
||||||
|
md.context = append(md.context, k)
|
||||||
|
|
||||||
|
rvkey := indirect(reflect.New(rv.Type().Key()))
|
||||||
|
rvval := reflect.Indirect(reflect.New(rv.Type().Elem()))
|
||||||
|
if err := md.unify(v, rvval); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
md.context = md.context[0 : len(md.context)-1]
|
||||||
|
|
||||||
|
rvkey.SetString(k)
|
||||||
|
rv.SetMapIndex(rvkey, rvval)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (md *MetaData) unifyArray(data interface{}, rv reflect.Value) error {
|
||||||
|
datav := reflect.ValueOf(data)
|
||||||
|
if datav.Kind() != reflect.Slice {
|
||||||
|
if !datav.IsValid() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return badtype("slice", data)
|
||||||
|
}
|
||||||
|
sliceLen := datav.Len()
|
||||||
|
if sliceLen != rv.Len() {
|
||||||
|
return e("expected array length %d; got TOML array of length %d",
|
||||||
|
rv.Len(), sliceLen)
|
||||||
|
}
|
||||||
|
return md.unifySliceArray(datav, rv)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (md *MetaData) unifySlice(data interface{}, rv reflect.Value) error {
|
||||||
|
datav := reflect.ValueOf(data)
|
||||||
|
if datav.Kind() != reflect.Slice {
|
||||||
|
if !datav.IsValid() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return badtype("slice", data)
|
||||||
|
}
|
||||||
|
n := datav.Len()
|
||||||
|
if rv.IsNil() || rv.Cap() < n {
|
||||||
|
rv.Set(reflect.MakeSlice(rv.Type(), n, n))
|
||||||
|
}
|
||||||
|
rv.SetLen(n)
|
||||||
|
return md.unifySliceArray(datav, rv)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (md *MetaData) unifySliceArray(data, rv reflect.Value) error {
|
||||||
|
sliceLen := data.Len()
|
||||||
|
for i := 0; i < sliceLen; i++ {
|
||||||
|
v := data.Index(i).Interface()
|
||||||
|
sliceval := indirect(rv.Index(i))
|
||||||
|
if err := md.unify(v, sliceval); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (md *MetaData) unifyDatetime(data interface{}, rv reflect.Value) error {
|
||||||
|
if _, ok := data.(time.Time); ok {
|
||||||
|
rv.Set(reflect.ValueOf(data))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return badtype("time.Time", data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (md *MetaData) unifyString(data interface{}, rv reflect.Value) error {
|
||||||
|
if s, ok := data.(string); ok {
|
||||||
|
rv.SetString(s)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return badtype("string", data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (md *MetaData) unifyFloat64(data interface{}, rv reflect.Value) error {
|
||||||
|
if num, ok := data.(float64); ok {
|
||||||
|
switch rv.Kind() {
|
||||||
|
case reflect.Float32:
|
||||||
|
fallthrough
|
||||||
|
case reflect.Float64:
|
||||||
|
rv.SetFloat(num)
|
||||||
|
default:
|
||||||
|
panic("bug")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return badtype("float", data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (md *MetaData) unifyInt(data interface{}, rv reflect.Value) error {
|
||||||
|
if num, ok := data.(int64); ok {
|
||||||
|
if rv.Kind() >= reflect.Int && rv.Kind() <= reflect.Int64 {
|
||||||
|
switch rv.Kind() {
|
||||||
|
case reflect.Int, reflect.Int64:
|
||||||
|
// No bounds checking necessary.
|
||||||
|
case reflect.Int8:
|
||||||
|
if num < math.MinInt8 || num > math.MaxInt8 {
|
||||||
|
return e("value %d is out of range for int8", num)
|
||||||
|
}
|
||||||
|
case reflect.Int16:
|
||||||
|
if num < math.MinInt16 || num > math.MaxInt16 {
|
||||||
|
return e("value %d is out of range for int16", num)
|
||||||
|
}
|
||||||
|
case reflect.Int32:
|
||||||
|
if num < math.MinInt32 || num > math.MaxInt32 {
|
||||||
|
return e("value %d is out of range for int32", num)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rv.SetInt(num)
|
||||||
|
} else if rv.Kind() >= reflect.Uint && rv.Kind() <= reflect.Uint64 {
|
||||||
|
unum := uint64(num)
|
||||||
|
switch rv.Kind() {
|
||||||
|
case reflect.Uint, reflect.Uint64:
|
||||||
|
// No bounds checking necessary.
|
||||||
|
case reflect.Uint8:
|
||||||
|
if num < 0 || unum > math.MaxUint8 {
|
||||||
|
return e("value %d is out of range for uint8", num)
|
||||||
|
}
|
||||||
|
case reflect.Uint16:
|
||||||
|
if num < 0 || unum > math.MaxUint16 {
|
||||||
|
return e("value %d is out of range for uint16", num)
|
||||||
|
}
|
||||||
|
case reflect.Uint32:
|
||||||
|
if num < 0 || unum > math.MaxUint32 {
|
||||||
|
return e("value %d is out of range for uint32", num)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rv.SetUint(unum)
|
||||||
|
} else {
|
||||||
|
panic("unreachable")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return badtype("integer", data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (md *MetaData) unifyBool(data interface{}, rv reflect.Value) error {
|
||||||
|
if b, ok := data.(bool); ok {
|
||||||
|
rv.SetBool(b)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return badtype("boolean", data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (md *MetaData) unifyAnything(data interface{}, rv reflect.Value) error {
|
||||||
|
rv.Set(reflect.ValueOf(data))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (md *MetaData) unifyText(data interface{}, v TextUnmarshaler) error {
|
||||||
|
var s string
|
||||||
|
switch sdata := data.(type) {
|
||||||
|
case TextMarshaler:
|
||||||
|
text, err := sdata.MarshalText()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
s = string(text)
|
||||||
|
case fmt.Stringer:
|
||||||
|
s = sdata.String()
|
||||||
|
case string:
|
||||||
|
s = sdata
|
||||||
|
case bool:
|
||||||
|
s = fmt.Sprintf("%v", sdata)
|
||||||
|
case int64:
|
||||||
|
s = fmt.Sprintf("%d", sdata)
|
||||||
|
case float64:
|
||||||
|
s = fmt.Sprintf("%f", sdata)
|
||||||
|
default:
|
||||||
|
return badtype("primitive (string-like)", data)
|
||||||
|
}
|
||||||
|
if err := v.UnmarshalText([]byte(s)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// rvalue returns a reflect.Value of `v`. All pointers are resolved.
|
||||||
|
func rvalue(v interface{}) reflect.Value {
|
||||||
|
return indirect(reflect.ValueOf(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
// indirect returns the value pointed to by a pointer.
|
||||||
|
// Pointers are followed until the value is not a pointer.
|
||||||
|
// New values are allocated for each nil pointer.
|
||||||
|
//
|
||||||
|
// An exception to this rule is if the value satisfies an interface of
|
||||||
|
// interest to us (like encoding.TextUnmarshaler).
|
||||||
|
func indirect(v reflect.Value) reflect.Value {
|
||||||
|
if v.Kind() != reflect.Ptr {
|
||||||
|
if v.CanSet() {
|
||||||
|
pv := v.Addr()
|
||||||
|
if _, ok := pv.Interface().(TextUnmarshaler); ok {
|
||||||
|
return pv
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
if v.IsNil() {
|
||||||
|
v.Set(reflect.New(v.Type().Elem()))
|
||||||
|
}
|
||||||
|
return indirect(reflect.Indirect(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
func isUnifiable(rv reflect.Value) bool {
|
||||||
|
if rv.CanSet() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if _, ok := rv.Interface().(TextUnmarshaler); ok {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func badtype(expected string, data interface{}) error {
|
||||||
|
return e("cannot load TOML value of type %T into a Go %s", data, expected)
|
||||||
|
}
|
121
vendor/github.com/BurntSushi/toml/decode_meta.go
generated
vendored
Normal file
121
vendor/github.com/BurntSushi/toml/decode_meta.go
generated
vendored
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
package toml
|
||||||
|
|
||||||
|
import "strings"
|
||||||
|
|
||||||
|
// MetaData allows access to meta information about TOML data that may not
|
||||||
|
// be inferrable via reflection. In particular, whether a key has been defined
|
||||||
|
// and the TOML type of a key.
|
||||||
|
type MetaData struct {
|
||||||
|
mapping map[string]interface{}
|
||||||
|
types map[string]tomlType
|
||||||
|
keys []Key
|
||||||
|
decoded map[string]bool
|
||||||
|
context Key // Used only during decoding.
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsDefined returns true if the key given exists in the TOML data. The key
|
||||||
|
// should be specified hierarchially. e.g.,
|
||||||
|
//
|
||||||
|
// // access the TOML key 'a.b.c'
|
||||||
|
// IsDefined("a", "b", "c")
|
||||||
|
//
|
||||||
|
// IsDefined will return false if an empty key given. Keys are case sensitive.
|
||||||
|
func (md *MetaData) IsDefined(key ...string) bool {
|
||||||
|
if len(key) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
var hash map[string]interface{}
|
||||||
|
var ok bool
|
||||||
|
var hashOrVal interface{} = md.mapping
|
||||||
|
for _, k := range key {
|
||||||
|
if hash, ok = hashOrVal.(map[string]interface{}); !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if hashOrVal, ok = hash[k]; !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type returns a string representation of the type of the key specified.
|
||||||
|
//
|
||||||
|
// Type will return the empty string if given an empty key or a key that
|
||||||
|
// does not exist. Keys are case sensitive.
|
||||||
|
func (md *MetaData) Type(key ...string) string {
|
||||||
|
fullkey := strings.Join(key, ".")
|
||||||
|
if typ, ok := md.types[fullkey]; ok {
|
||||||
|
return typ.typeString()
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// Key is the type of any TOML key, including key groups. Use (MetaData).Keys
|
||||||
|
// to get values of this type.
|
||||||
|
type Key []string
|
||||||
|
|
||||||
|
func (k Key) String() string {
|
||||||
|
return strings.Join(k, ".")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k Key) maybeQuotedAll() string {
|
||||||
|
var ss []string
|
||||||
|
for i := range k {
|
||||||
|
ss = append(ss, k.maybeQuoted(i))
|
||||||
|
}
|
||||||
|
return strings.Join(ss, ".")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k Key) maybeQuoted(i int) string {
|
||||||
|
quote := false
|
||||||
|
for _, c := range k[i] {
|
||||||
|
if !isBareKeyChar(c) {
|
||||||
|
quote = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if quote {
|
||||||
|
return "\"" + strings.Replace(k[i], "\"", "\\\"", -1) + "\""
|
||||||
|
}
|
||||||
|
return k[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k Key) add(piece string) Key {
|
||||||
|
newKey := make(Key, len(k)+1)
|
||||||
|
copy(newKey, k)
|
||||||
|
newKey[len(k)] = piece
|
||||||
|
return newKey
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keys returns a slice of every key in the TOML data, including key groups.
|
||||||
|
// Each key is itself a slice, where the first element is the top of the
|
||||||
|
// hierarchy and the last is the most specific.
|
||||||
|
//
|
||||||
|
// The list will have the same order as the keys appeared in the TOML data.
|
||||||
|
//
|
||||||
|
// All keys returned are non-empty.
|
||||||
|
func (md *MetaData) Keys() []Key {
|
||||||
|
return md.keys
|
||||||
|
}
|
||||||
|
|
||||||
|
// Undecoded returns all keys that have not been decoded in the order in which
|
||||||
|
// they appear in the original TOML document.
|
||||||
|
//
|
||||||
|
// This includes keys that haven't been decoded because of a Primitive value.
|
||||||
|
// Once the Primitive value is decoded, the keys will be considered decoded.
|
||||||
|
//
|
||||||
|
// Also note that decoding into an empty interface will result in no decoding,
|
||||||
|
// and so no keys will be considered decoded.
|
||||||
|
//
|
||||||
|
// In this sense, the Undecoded keys correspond to keys in the TOML document
|
||||||
|
// that do not have a concrete type in your representation.
|
||||||
|
func (md *MetaData) Undecoded() []Key {
|
||||||
|
undecoded := make([]Key, 0, len(md.keys))
|
||||||
|
for _, key := range md.keys {
|
||||||
|
if !md.decoded[key.String()] {
|
||||||
|
undecoded = append(undecoded, key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return undecoded
|
||||||
|
}
|
27
vendor/github.com/BurntSushi/toml/doc.go
generated
vendored
Normal file
27
vendor/github.com/BurntSushi/toml/doc.go
generated
vendored
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
Package toml provides facilities for decoding and encoding TOML configuration
|
||||||
|
files via reflection. There is also support for delaying decoding with
|
||||||
|
the Primitive type, and querying the set of keys in a TOML document with the
|
||||||
|
MetaData type.
|
||||||
|
|
||||||
|
The specification implemented: https://github.com/toml-lang/toml
|
||||||
|
|
||||||
|
The sub-command github.com/BurntSushi/toml/cmd/tomlv can be used to verify
|
||||||
|
whether a file is a valid TOML document. It can also be used to print the
|
||||||
|
type of each key in a TOML document.
|
||||||
|
|
||||||
|
Testing
|
||||||
|
|
||||||
|
There are two important types of tests used for this package. The first is
|
||||||
|
contained inside '*_test.go' files and uses the standard Go unit testing
|
||||||
|
framework. These tests are primarily devoted to holistically testing the
|
||||||
|
decoder and encoder.
|
||||||
|
|
||||||
|
The second type of testing is used to verify the implementation's adherence
|
||||||
|
to the TOML specification. These tests have been factored into their own
|
||||||
|
project: https://github.com/BurntSushi/toml-test
|
||||||
|
|
||||||
|
The reason the tests are in a separate project is so that they can be used by
|
||||||
|
any implementation of TOML. Namely, it is language agnostic.
|
||||||
|
*/
|
||||||
|
package toml
|
568
vendor/github.com/BurntSushi/toml/encode.go
generated
vendored
Normal file
568
vendor/github.com/BurntSushi/toml/encode.go
generated
vendored
Normal file
@ -0,0 +1,568 @@
|
|||||||
|
package toml
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"reflect"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type tomlEncodeError struct{ error }
|
||||||
|
|
||||||
|
var (
|
||||||
|
errArrayMixedElementTypes = errors.New(
|
||||||
|
"toml: cannot encode array with mixed element types")
|
||||||
|
errArrayNilElement = errors.New(
|
||||||
|
"toml: cannot encode array with nil element")
|
||||||
|
errNonString = errors.New(
|
||||||
|
"toml: cannot encode a map with non-string key type")
|
||||||
|
errAnonNonStruct = errors.New(
|
||||||
|
"toml: cannot encode an anonymous field that is not a struct")
|
||||||
|
errArrayNoTable = errors.New(
|
||||||
|
"toml: TOML array element cannot contain a table")
|
||||||
|
errNoKey = errors.New(
|
||||||
|
"toml: top-level values must be Go maps or structs")
|
||||||
|
errAnything = errors.New("") // used in testing
|
||||||
|
)
|
||||||
|
|
||||||
|
var quotedReplacer = strings.NewReplacer(
|
||||||
|
"\t", "\\t",
|
||||||
|
"\n", "\\n",
|
||||||
|
"\r", "\\r",
|
||||||
|
"\"", "\\\"",
|
||||||
|
"\\", "\\\\",
|
||||||
|
)
|
||||||
|
|
||||||
|
// Encoder controls the encoding of Go values to a TOML document to some
|
||||||
|
// io.Writer.
|
||||||
|
//
|
||||||
|
// The indentation level can be controlled with the Indent field.
|
||||||
|
type Encoder struct {
|
||||||
|
// A single indentation level. By default it is two spaces.
|
||||||
|
Indent string
|
||||||
|
|
||||||
|
// hasWritten is whether we have written any output to w yet.
|
||||||
|
hasWritten bool
|
||||||
|
w *bufio.Writer
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewEncoder returns a TOML encoder that encodes Go values to the io.Writer
|
||||||
|
// given. By default, a single indentation level is 2 spaces.
|
||||||
|
func NewEncoder(w io.Writer) *Encoder {
|
||||||
|
return &Encoder{
|
||||||
|
w: bufio.NewWriter(w),
|
||||||
|
Indent: " ",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encode writes a TOML representation of the Go value to the underlying
|
||||||
|
// io.Writer. If the value given cannot be encoded to a valid TOML document,
|
||||||
|
// then an error is returned.
|
||||||
|
//
|
||||||
|
// The mapping between Go values and TOML values should be precisely the same
|
||||||
|
// as for the Decode* functions. Similarly, the TextMarshaler interface is
|
||||||
|
// supported by encoding the resulting bytes as strings. (If you want to write
|
||||||
|
// arbitrary binary data then you will need to use something like base64 since
|
||||||
|
// TOML does not have any binary types.)
|
||||||
|
//
|
||||||
|
// When encoding TOML hashes (i.e., Go maps or structs), keys without any
|
||||||
|
// sub-hashes are encoded first.
|
||||||
|
//
|
||||||
|
// If a Go map is encoded, then its keys are sorted alphabetically for
|
||||||
|
// deterministic output. More control over this behavior may be provided if
|
||||||
|
// there is demand for it.
|
||||||
|
//
|
||||||
|
// Encoding Go values without a corresponding TOML representation---like map
|
||||||
|
// types with non-string keys---will cause an error to be returned. Similarly
|
||||||
|
// for mixed arrays/slices, arrays/slices with nil elements, embedded
|
||||||
|
// non-struct types and nested slices containing maps or structs.
|
||||||
|
// (e.g., [][]map[string]string is not allowed but []map[string]string is OK
|
||||||
|
// and so is []map[string][]string.)
|
||||||
|
func (enc *Encoder) Encode(v interface{}) error {
|
||||||
|
rv := eindirect(reflect.ValueOf(v))
|
||||||
|
if err := enc.safeEncode(Key([]string{}), rv); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return enc.w.Flush()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (enc *Encoder) safeEncode(key Key, rv reflect.Value) (err error) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
if terr, ok := r.(tomlEncodeError); ok {
|
||||||
|
err = terr.error
|
||||||
|
return
|
||||||
|
}
|
||||||
|
panic(r)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
enc.encode(key, rv)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (enc *Encoder) encode(key Key, rv reflect.Value) {
|
||||||
|
// Special case. Time needs to be in ISO8601 format.
|
||||||
|
// Special case. If we can marshal the type to text, then we used that.
|
||||||
|
// Basically, this prevents the encoder for handling these types as
|
||||||
|
// generic structs (or whatever the underlying type of a TextMarshaler is).
|
||||||
|
switch rv.Interface().(type) {
|
||||||
|
case time.Time, TextMarshaler:
|
||||||
|
enc.keyEqElement(key, rv)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
k := rv.Kind()
|
||||||
|
switch k {
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32,
|
||||||
|
reflect.Int64,
|
||||||
|
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32,
|
||||||
|
reflect.Uint64,
|
||||||
|
reflect.Float32, reflect.Float64, reflect.String, reflect.Bool:
|
||||||
|
enc.keyEqElement(key, rv)
|
||||||
|
case reflect.Array, reflect.Slice:
|
||||||
|
if typeEqual(tomlArrayHash, tomlTypeOfGo(rv)) {
|
||||||
|
enc.eArrayOfTables(key, rv)
|
||||||
|
} else {
|
||||||
|
enc.keyEqElement(key, rv)
|
||||||
|
}
|
||||||
|
case reflect.Interface:
|
||||||
|
if rv.IsNil() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
enc.encode(key, rv.Elem())
|
||||||
|
case reflect.Map:
|
||||||
|
if rv.IsNil() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
enc.eTable(key, rv)
|
||||||
|
case reflect.Ptr:
|
||||||
|
if rv.IsNil() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
enc.encode(key, rv.Elem())
|
||||||
|
case reflect.Struct:
|
||||||
|
enc.eTable(key, rv)
|
||||||
|
default:
|
||||||
|
panic(e("unsupported type for key '%s': %s", key, k))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// eElement encodes any value that can be an array element (primitives and
|
||||||
|
// arrays).
|
||||||
|
func (enc *Encoder) eElement(rv reflect.Value) {
|
||||||
|
switch v := rv.Interface().(type) {
|
||||||
|
case time.Time:
|
||||||
|
// Special case time.Time as a primitive. Has to come before
|
||||||
|
// TextMarshaler below because time.Time implements
|
||||||
|
// encoding.TextMarshaler, but we need to always use UTC.
|
||||||
|
enc.wf(v.UTC().Format("2006-01-02T15:04:05Z"))
|
||||||
|
return
|
||||||
|
case TextMarshaler:
|
||||||
|
// Special case. Use text marshaler if it's available for this value.
|
||||||
|
if s, err := v.MarshalText(); err != nil {
|
||||||
|
encPanic(err)
|
||||||
|
} else {
|
||||||
|
enc.writeQuoted(string(s))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch rv.Kind() {
|
||||||
|
case reflect.Bool:
|
||||||
|
enc.wf(strconv.FormatBool(rv.Bool()))
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32,
|
||||||
|
reflect.Int64:
|
||||||
|
enc.wf(strconv.FormatInt(rv.Int(), 10))
|
||||||
|
case reflect.Uint, reflect.Uint8, reflect.Uint16,
|
||||||
|
reflect.Uint32, reflect.Uint64:
|
||||||
|
enc.wf(strconv.FormatUint(rv.Uint(), 10))
|
||||||
|
case reflect.Float32:
|
||||||
|
enc.wf(floatAddDecimal(strconv.FormatFloat(rv.Float(), 'f', -1, 32)))
|
||||||
|
case reflect.Float64:
|
||||||
|
enc.wf(floatAddDecimal(strconv.FormatFloat(rv.Float(), 'f', -1, 64)))
|
||||||
|
case reflect.Array, reflect.Slice:
|
||||||
|
enc.eArrayOrSliceElement(rv)
|
||||||
|
case reflect.Interface:
|
||||||
|
enc.eElement(rv.Elem())
|
||||||
|
case reflect.String:
|
||||||
|
enc.writeQuoted(rv.String())
|
||||||
|
default:
|
||||||
|
panic(e("unexpected primitive type: %s", rv.Kind()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// By the TOML spec, all floats must have a decimal with at least one
|
||||||
|
// number on either side.
|
||||||
|
func floatAddDecimal(fstr string) string {
|
||||||
|
if !strings.Contains(fstr, ".") {
|
||||||
|
return fstr + ".0"
|
||||||
|
}
|
||||||
|
return fstr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (enc *Encoder) writeQuoted(s string) {
|
||||||
|
enc.wf("\"%s\"", quotedReplacer.Replace(s))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (enc *Encoder) eArrayOrSliceElement(rv reflect.Value) {
|
||||||
|
length := rv.Len()
|
||||||
|
enc.wf("[")
|
||||||
|
for i := 0; i < length; i++ {
|
||||||
|
elem := rv.Index(i)
|
||||||
|
enc.eElement(elem)
|
||||||
|
if i != length-1 {
|
||||||
|
enc.wf(", ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
enc.wf("]")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (enc *Encoder) eArrayOfTables(key Key, rv reflect.Value) {
|
||||||
|
if len(key) == 0 {
|
||||||
|
encPanic(errNoKey)
|
||||||
|
}
|
||||||
|
for i := 0; i < rv.Len(); i++ {
|
||||||
|
trv := rv.Index(i)
|
||||||
|
if isNil(trv) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
panicIfInvalidKey(key)
|
||||||
|
enc.newline()
|
||||||
|
enc.wf("%s[[%s]]", enc.indentStr(key), key.maybeQuotedAll())
|
||||||
|
enc.newline()
|
||||||
|
enc.eMapOrStruct(key, trv)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (enc *Encoder) eTable(key Key, rv reflect.Value) {
|
||||||
|
panicIfInvalidKey(key)
|
||||||
|
if len(key) == 1 {
|
||||||
|
// Output an extra newline between top-level tables.
|
||||||
|
// (The newline isn't written if nothing else has been written though.)
|
||||||
|
enc.newline()
|
||||||
|
}
|
||||||
|
if len(key) > 0 {
|
||||||
|
enc.wf("%s[%s]", enc.indentStr(key), key.maybeQuotedAll())
|
||||||
|
enc.newline()
|
||||||
|
}
|
||||||
|
enc.eMapOrStruct(key, rv)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (enc *Encoder) eMapOrStruct(key Key, rv reflect.Value) {
|
||||||
|
switch rv := eindirect(rv); rv.Kind() {
|
||||||
|
case reflect.Map:
|
||||||
|
enc.eMap(key, rv)
|
||||||
|
case reflect.Struct:
|
||||||
|
enc.eStruct(key, rv)
|
||||||
|
default:
|
||||||
|
panic("eTable: unhandled reflect.Value Kind: " + rv.Kind().String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (enc *Encoder) eMap(key Key, rv reflect.Value) {
|
||||||
|
rt := rv.Type()
|
||||||
|
if rt.Key().Kind() != reflect.String {
|
||||||
|
encPanic(errNonString)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort keys so that we have deterministic output. And write keys directly
|
||||||
|
// underneath this key first, before writing sub-structs or sub-maps.
|
||||||
|
var mapKeysDirect, mapKeysSub []string
|
||||||
|
for _, mapKey := range rv.MapKeys() {
|
||||||
|
k := mapKey.String()
|
||||||
|
if typeIsHash(tomlTypeOfGo(rv.MapIndex(mapKey))) {
|
||||||
|
mapKeysSub = append(mapKeysSub, k)
|
||||||
|
} else {
|
||||||
|
mapKeysDirect = append(mapKeysDirect, k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var writeMapKeys = func(mapKeys []string) {
|
||||||
|
sort.Strings(mapKeys)
|
||||||
|
for _, mapKey := range mapKeys {
|
||||||
|
mrv := rv.MapIndex(reflect.ValueOf(mapKey))
|
||||||
|
if isNil(mrv) {
|
||||||
|
// Don't write anything for nil fields.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
enc.encode(key.add(mapKey), mrv)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writeMapKeys(mapKeysDirect)
|
||||||
|
writeMapKeys(mapKeysSub)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (enc *Encoder) eStruct(key Key, rv reflect.Value) {
|
||||||
|
// Write keys for fields directly under this key first, because if we write
|
||||||
|
// a field that creates a new table, then all keys under it will be in that
|
||||||
|
// table (not the one we're writing here).
|
||||||
|
rt := rv.Type()
|
||||||
|
var fieldsDirect, fieldsSub [][]int
|
||||||
|
var addFields func(rt reflect.Type, rv reflect.Value, start []int)
|
||||||
|
addFields = func(rt reflect.Type, rv reflect.Value, start []int) {
|
||||||
|
for i := 0; i < rt.NumField(); i++ {
|
||||||
|
f := rt.Field(i)
|
||||||
|
// skip unexported fields
|
||||||
|
if f.PkgPath != "" && !f.Anonymous {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
frv := rv.Field(i)
|
||||||
|
if f.Anonymous {
|
||||||
|
t := f.Type
|
||||||
|
switch t.Kind() {
|
||||||
|
case reflect.Struct:
|
||||||
|
// Treat anonymous struct fields with
|
||||||
|
// tag names as though they are not
|
||||||
|
// anonymous, like encoding/json does.
|
||||||
|
if getOptions(f.Tag).name == "" {
|
||||||
|
addFields(t, frv, f.Index)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
case reflect.Ptr:
|
||||||
|
if t.Elem().Kind() == reflect.Struct &&
|
||||||
|
getOptions(f.Tag).name == "" {
|
||||||
|
if !frv.IsNil() {
|
||||||
|
addFields(t.Elem(), frv.Elem(), f.Index)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// Fall through to the normal field encoding logic below
|
||||||
|
// for non-struct anonymous fields.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if typeIsHash(tomlTypeOfGo(frv)) {
|
||||||
|
fieldsSub = append(fieldsSub, append(start, f.Index...))
|
||||||
|
} else {
|
||||||
|
fieldsDirect = append(fieldsDirect, append(start, f.Index...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
addFields(rt, rv, nil)
|
||||||
|
|
||||||
|
var writeFields = func(fields [][]int) {
|
||||||
|
for _, fieldIndex := range fields {
|
||||||
|
sft := rt.FieldByIndex(fieldIndex)
|
||||||
|
sf := rv.FieldByIndex(fieldIndex)
|
||||||
|
if isNil(sf) {
|
||||||
|
// Don't write anything for nil fields.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
opts := getOptions(sft.Tag)
|
||||||
|
if opts.skip {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
keyName := sft.Name
|
||||||
|
if opts.name != "" {
|
||||||
|
keyName = opts.name
|
||||||
|
}
|
||||||
|
if opts.omitempty && isEmpty(sf) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if opts.omitzero && isZero(sf) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
enc.encode(key.add(keyName), sf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writeFields(fieldsDirect)
|
||||||
|
writeFields(fieldsSub)
|
||||||
|
}
|
||||||
|
|
||||||
|
// tomlTypeName returns the TOML type name of the Go value's type. It is
|
||||||
|
// used to determine whether the types of array elements are mixed (which is
|
||||||
|
// forbidden). If the Go value is nil, then it is illegal for it to be an array
|
||||||
|
// element, and valueIsNil is returned as true.
|
||||||
|
|
||||||
|
// Returns the TOML type of a Go value. The type may be `nil`, which means
|
||||||
|
// no concrete TOML type could be found.
|
||||||
|
func tomlTypeOfGo(rv reflect.Value) tomlType {
|
||||||
|
if isNil(rv) || !rv.IsValid() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
switch rv.Kind() {
|
||||||
|
case reflect.Bool:
|
||||||
|
return tomlBool
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32,
|
||||||
|
reflect.Int64,
|
||||||
|
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32,
|
||||||
|
reflect.Uint64:
|
||||||
|
return tomlInteger
|
||||||
|
case reflect.Float32, reflect.Float64:
|
||||||
|
return tomlFloat
|
||||||
|
case reflect.Array, reflect.Slice:
|
||||||
|
if typeEqual(tomlHash, tomlArrayType(rv)) {
|
||||||
|
return tomlArrayHash
|
||||||
|
}
|
||||||
|
return tomlArray
|
||||||
|
case reflect.Ptr, reflect.Interface:
|
||||||
|
return tomlTypeOfGo(rv.Elem())
|
||||||
|
case reflect.String:
|
||||||
|
return tomlString
|
||||||
|
case reflect.Map:
|
||||||
|
return tomlHash
|
||||||
|
case reflect.Struct:
|
||||||
|
switch rv.Interface().(type) {
|
||||||
|
case time.Time:
|
||||||
|
return tomlDatetime
|
||||||
|
case TextMarshaler:
|
||||||
|
return tomlString
|
||||||
|
default:
|
||||||
|
return tomlHash
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
panic("unexpected reflect.Kind: " + rv.Kind().String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// tomlArrayType returns the element type of a TOML array. The type returned
|
||||||
|
// may be nil if it cannot be determined (e.g., a nil slice or a zero length
|
||||||
|
// slize). This function may also panic if it finds a type that cannot be
|
||||||
|
// expressed in TOML (such as nil elements, heterogeneous arrays or directly
|
||||||
|
// nested arrays of tables).
|
||||||
|
func tomlArrayType(rv reflect.Value) tomlType {
|
||||||
|
if isNil(rv) || !rv.IsValid() || rv.Len() == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
firstType := tomlTypeOfGo(rv.Index(0))
|
||||||
|
if firstType == nil {
|
||||||
|
encPanic(errArrayNilElement)
|
||||||
|
}
|
||||||
|
|
||||||
|
rvlen := rv.Len()
|
||||||
|
for i := 1; i < rvlen; i++ {
|
||||||
|
elem := rv.Index(i)
|
||||||
|
switch elemType := tomlTypeOfGo(elem); {
|
||||||
|
case elemType == nil:
|
||||||
|
encPanic(errArrayNilElement)
|
||||||
|
case !typeEqual(firstType, elemType):
|
||||||
|
encPanic(errArrayMixedElementTypes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If we have a nested array, then we must make sure that the nested
|
||||||
|
// array contains ONLY primitives.
|
||||||
|
// This checks arbitrarily nested arrays.
|
||||||
|
if typeEqual(firstType, tomlArray) || typeEqual(firstType, tomlArrayHash) {
|
||||||
|
nest := tomlArrayType(eindirect(rv.Index(0)))
|
||||||
|
if typeEqual(nest, tomlHash) || typeEqual(nest, tomlArrayHash) {
|
||||||
|
encPanic(errArrayNoTable)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return firstType
|
||||||
|
}
|
||||||
|
|
||||||
|
type tagOptions struct {
|
||||||
|
skip bool // "-"
|
||||||
|
name string
|
||||||
|
omitempty bool
|
||||||
|
omitzero bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func getOptions(tag reflect.StructTag) tagOptions {
|
||||||
|
t := tag.Get("toml")
|
||||||
|
if t == "-" {
|
||||||
|
return tagOptions{skip: true}
|
||||||
|
}
|
||||||
|
var opts tagOptions
|
||||||
|
parts := strings.Split(t, ",")
|
||||||
|
opts.name = parts[0]
|
||||||
|
for _, s := range parts[1:] {
|
||||||
|
switch s {
|
||||||
|
case "omitempty":
|
||||||
|
opts.omitempty = true
|
||||||
|
case "omitzero":
|
||||||
|
opts.omitzero = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return opts
|
||||||
|
}
|
||||||
|
|
||||||
|
func isZero(rv reflect.Value) bool {
|
||||||
|
switch rv.Kind() {
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
|
return rv.Int() == 0
|
||||||
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||||
|
return rv.Uint() == 0
|
||||||
|
case reflect.Float32, reflect.Float64:
|
||||||
|
return rv.Float() == 0.0
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func isEmpty(rv reflect.Value) bool {
|
||||||
|
switch rv.Kind() {
|
||||||
|
case reflect.Array, reflect.Slice, reflect.Map, reflect.String:
|
||||||
|
return rv.Len() == 0
|
||||||
|
case reflect.Bool:
|
||||||
|
return !rv.Bool()
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (enc *Encoder) newline() {
|
||||||
|
if enc.hasWritten {
|
||||||
|
enc.wf("\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (enc *Encoder) keyEqElement(key Key, val reflect.Value) {
|
||||||
|
if len(key) == 0 {
|
||||||
|
encPanic(errNoKey)
|
||||||
|
}
|
||||||
|
panicIfInvalidKey(key)
|
||||||
|
enc.wf("%s%s = ", enc.indentStr(key), key.maybeQuoted(len(key)-1))
|
||||||
|
enc.eElement(val)
|
||||||
|
enc.newline()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (enc *Encoder) wf(format string, v ...interface{}) {
|
||||||
|
if _, err := fmt.Fprintf(enc.w, format, v...); err != nil {
|
||||||
|
encPanic(err)
|
||||||
|
}
|
||||||
|
enc.hasWritten = true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (enc *Encoder) indentStr(key Key) string {
|
||||||
|
return strings.Repeat(enc.Indent, len(key)-1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func encPanic(err error) {
|
||||||
|
panic(tomlEncodeError{err})
|
||||||
|
}
|
||||||
|
|
||||||
|
func eindirect(v reflect.Value) reflect.Value {
|
||||||
|
switch v.Kind() {
|
||||||
|
case reflect.Ptr, reflect.Interface:
|
||||||
|
return eindirect(v.Elem())
|
||||||
|
default:
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func isNil(rv reflect.Value) bool {
|
||||||
|
switch rv.Kind() {
|
||||||
|
case reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
|
||||||
|
return rv.IsNil()
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func panicIfInvalidKey(key Key) {
|
||||||
|
for _, k := range key {
|
||||||
|
if len(k) == 0 {
|
||||||
|
encPanic(e("Key '%s' is not a valid table name. Key names "+
|
||||||
|
"cannot be empty.", key.maybeQuotedAll()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func isValidKeyName(s string) bool {
|
||||||
|
return len(s) != 0
|
||||||
|
}
|
19
vendor/github.com/BurntSushi/toml/encoding_types.go
generated
vendored
Normal file
19
vendor/github.com/BurntSushi/toml/encoding_types.go
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
// +build go1.2
|
||||||
|
|
||||||
|
package toml
|
||||||
|
|
||||||
|
// In order to support Go 1.1, we define our own TextMarshaler and
|
||||||
|
// TextUnmarshaler types. For Go 1.2+, we just alias them with the
|
||||||
|
// standard library interfaces.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TextMarshaler is a synonym for encoding.TextMarshaler. It is defined here
|
||||||
|
// so that Go 1.1 can be supported.
|
||||||
|
type TextMarshaler encoding.TextMarshaler
|
||||||
|
|
||||||
|
// TextUnmarshaler is a synonym for encoding.TextUnmarshaler. It is defined
|
||||||
|
// here so that Go 1.1 can be supported.
|
||||||
|
type TextUnmarshaler encoding.TextUnmarshaler
|
18
vendor/github.com/BurntSushi/toml/encoding_types_1.1.go
generated
vendored
Normal file
18
vendor/github.com/BurntSushi/toml/encoding_types_1.1.go
generated
vendored
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
// +build !go1.2
|
||||||
|
|
||||||
|
package toml
|
||||||
|
|
||||||
|
// These interfaces were introduced in Go 1.2, so we add them manually when
|
||||||
|
// compiling for Go 1.1.
|
||||||
|
|
||||||
|
// TextMarshaler is a synonym for encoding.TextMarshaler. It is defined here
|
||||||
|
// so that Go 1.1 can be supported.
|
||||||
|
type TextMarshaler interface {
|
||||||
|
MarshalText() (text []byte, err error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TextUnmarshaler is a synonym for encoding.TextUnmarshaler. It is defined
|
||||||
|
// here so that Go 1.1 can be supported.
|
||||||
|
type TextUnmarshaler interface {
|
||||||
|
UnmarshalText(text []byte) error
|
||||||
|
}
|
953
vendor/github.com/BurntSushi/toml/lex.go
generated
vendored
Normal file
953
vendor/github.com/BurntSushi/toml/lex.go
generated
vendored
Normal file
@ -0,0 +1,953 @@
|
|||||||
|
package toml
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"unicode"
|
||||||
|
"unicode/utf8"
|
||||||
|
)
|
||||||
|
|
||||||
|
type itemType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
itemError itemType = iota
|
||||||
|
itemNIL // used in the parser to indicate no type
|
||||||
|
itemEOF
|
||||||
|
itemText
|
||||||
|
itemString
|
||||||
|
itemRawString
|
||||||
|
itemMultilineString
|
||||||
|
itemRawMultilineString
|
||||||
|
itemBool
|
||||||
|
itemInteger
|
||||||
|
itemFloat
|
||||||
|
itemDatetime
|
||||||
|
itemArray // the start of an array
|
||||||
|
itemArrayEnd
|
||||||
|
itemTableStart
|
||||||
|
itemTableEnd
|
||||||
|
itemArrayTableStart
|
||||||
|
itemArrayTableEnd
|
||||||
|
itemKeyStart
|
||||||
|
itemCommentStart
|
||||||
|
itemInlineTableStart
|
||||||
|
itemInlineTableEnd
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
eof = 0
|
||||||
|
comma = ','
|
||||||
|
tableStart = '['
|
||||||
|
tableEnd = ']'
|
||||||
|
arrayTableStart = '['
|
||||||
|
arrayTableEnd = ']'
|
||||||
|
tableSep = '.'
|
||||||
|
keySep = '='
|
||||||
|
arrayStart = '['
|
||||||
|
arrayEnd = ']'
|
||||||
|
commentStart = '#'
|
||||||
|
stringStart = '"'
|
||||||
|
stringEnd = '"'
|
||||||
|
rawStringStart = '\''
|
||||||
|
rawStringEnd = '\''
|
||||||
|
inlineTableStart = '{'
|
||||||
|
inlineTableEnd = '}'
|
||||||
|
)
|
||||||
|
|
||||||
|
type stateFn func(lx *lexer) stateFn
|
||||||
|
|
||||||
|
type lexer struct {
|
||||||
|
input string
|
||||||
|
start int
|
||||||
|
pos int
|
||||||
|
line int
|
||||||
|
state stateFn
|
||||||
|
items chan item
|
||||||
|
|
||||||
|
// Allow for backing up up to three runes.
|
||||||
|
// This is necessary because TOML contains 3-rune tokens (""" and ''').
|
||||||
|
prevWidths [3]int
|
||||||
|
nprev int // how many of prevWidths are in use
|
||||||
|
// If we emit an eof, we can still back up, but it is not OK to call
|
||||||
|
// next again.
|
||||||
|
atEOF bool
|
||||||
|
|
||||||
|
// A stack of state functions used to maintain context.
|
||||||
|
// The idea is to reuse parts of the state machine in various places.
|
||||||
|
// For example, values can appear at the top level or within arbitrarily
|
||||||
|
// nested arrays. The last state on the stack is used after a value has
|
||||||
|
// been lexed. Similarly for comments.
|
||||||
|
stack []stateFn
|
||||||
|
}
|
||||||
|
|
||||||
|
type item struct {
|
||||||
|
typ itemType
|
||||||
|
val string
|
||||||
|
line int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lx *lexer) nextItem() item {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case item := <-lx.items:
|
||||||
|
return item
|
||||||
|
default:
|
||||||
|
lx.state = lx.state(lx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func lex(input string) *lexer {
|
||||||
|
lx := &lexer{
|
||||||
|
input: input,
|
||||||
|
state: lexTop,
|
||||||
|
line: 1,
|
||||||
|
items: make(chan item, 10),
|
||||||
|
stack: make([]stateFn, 0, 10),
|
||||||
|
}
|
||||||
|
return lx
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lx *lexer) push(state stateFn) {
|
||||||
|
lx.stack = append(lx.stack, state)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lx *lexer) pop() stateFn {
|
||||||
|
if len(lx.stack) == 0 {
|
||||||
|
return lx.errorf("BUG in lexer: no states to pop")
|
||||||
|
}
|
||||||
|
last := lx.stack[len(lx.stack)-1]
|
||||||
|
lx.stack = lx.stack[0 : len(lx.stack)-1]
|
||||||
|
return last
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lx *lexer) current() string {
|
||||||
|
return lx.input[lx.start:lx.pos]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lx *lexer) emit(typ itemType) {
|
||||||
|
lx.items <- item{typ, lx.current(), lx.line}
|
||||||
|
lx.start = lx.pos
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lx *lexer) emitTrim(typ itemType) {
|
||||||
|
lx.items <- item{typ, strings.TrimSpace(lx.current()), lx.line}
|
||||||
|
lx.start = lx.pos
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lx *lexer) next() (r rune) {
|
||||||
|
if lx.atEOF {
|
||||||
|
panic("next called after EOF")
|
||||||
|
}
|
||||||
|
if lx.pos >= len(lx.input) {
|
||||||
|
lx.atEOF = true
|
||||||
|
return eof
|
||||||
|
}
|
||||||
|
|
||||||
|
if lx.input[lx.pos] == '\n' {
|
||||||
|
lx.line++
|
||||||
|
}
|
||||||
|
lx.prevWidths[2] = lx.prevWidths[1]
|
||||||
|
lx.prevWidths[1] = lx.prevWidths[0]
|
||||||
|
if lx.nprev < 3 {
|
||||||
|
lx.nprev++
|
||||||
|
}
|
||||||
|
r, w := utf8.DecodeRuneInString(lx.input[lx.pos:])
|
||||||
|
lx.prevWidths[0] = w
|
||||||
|
lx.pos += w
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
// ignore skips over the pending input before this point.
|
||||||
|
func (lx *lexer) ignore() {
|
||||||
|
lx.start = lx.pos
|
||||||
|
}
|
||||||
|
|
||||||
|
// backup steps back one rune. Can be called only twice between calls to next.
|
||||||
|
func (lx *lexer) backup() {
|
||||||
|
if lx.atEOF {
|
||||||
|
lx.atEOF = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if lx.nprev < 1 {
|
||||||
|
panic("backed up too far")
|
||||||
|
}
|
||||||
|
w := lx.prevWidths[0]
|
||||||
|
lx.prevWidths[0] = lx.prevWidths[1]
|
||||||
|
lx.prevWidths[1] = lx.prevWidths[2]
|
||||||
|
lx.nprev--
|
||||||
|
lx.pos -= w
|
||||||
|
if lx.pos < len(lx.input) && lx.input[lx.pos] == '\n' {
|
||||||
|
lx.line--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// accept consumes the next rune if it's equal to `valid`.
|
||||||
|
func (lx *lexer) accept(valid rune) bool {
|
||||||
|
if lx.next() == valid {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
lx.backup()
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// peek returns but does not consume the next rune in the input.
|
||||||
|
func (lx *lexer) peek() rune {
|
||||||
|
r := lx.next()
|
||||||
|
lx.backup()
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
// skip ignores all input that matches the given predicate.
|
||||||
|
func (lx *lexer) skip(pred func(rune) bool) {
|
||||||
|
for {
|
||||||
|
r := lx.next()
|
||||||
|
if pred(r) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
lx.backup()
|
||||||
|
lx.ignore()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// errorf stops all lexing by emitting an error and returning `nil`.
|
||||||
|
// Note that any value that is a character is escaped if it's a special
|
||||||
|
// character (newlines, tabs, etc.).
|
||||||
|
func (lx *lexer) errorf(format string, values ...interface{}) stateFn {
|
||||||
|
lx.items <- item{
|
||||||
|
itemError,
|
||||||
|
fmt.Sprintf(format, values...),
|
||||||
|
lx.line,
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// lexTop consumes elements at the top level of TOML data.
|
||||||
|
func lexTop(lx *lexer) stateFn {
|
||||||
|
r := lx.next()
|
||||||
|
if isWhitespace(r) || isNL(r) {
|
||||||
|
return lexSkip(lx, lexTop)
|
||||||
|
}
|
||||||
|
switch r {
|
||||||
|
case commentStart:
|
||||||
|
lx.push(lexTop)
|
||||||
|
return lexCommentStart
|
||||||
|
case tableStart:
|
||||||
|
return lexTableStart
|
||||||
|
case eof:
|
||||||
|
if lx.pos > lx.start {
|
||||||
|
return lx.errorf("unexpected EOF")
|
||||||
|
}
|
||||||
|
lx.emit(itemEOF)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// At this point, the only valid item can be a key, so we back up
|
||||||
|
// and let the key lexer do the rest.
|
||||||
|
lx.backup()
|
||||||
|
lx.push(lexTopEnd)
|
||||||
|
return lexKeyStart
|
||||||
|
}
|
||||||
|
|
||||||
|
// lexTopEnd is entered whenever a top-level item has been consumed. (A value
|
||||||
|
// or a table.) It must see only whitespace, and will turn back to lexTop
|
||||||
|
// upon a newline. If it sees EOF, it will quit the lexer successfully.
|
||||||
|
func lexTopEnd(lx *lexer) stateFn {
|
||||||
|
r := lx.next()
|
||||||
|
switch {
|
||||||
|
case r == commentStart:
|
||||||
|
// a comment will read to a newline for us.
|
||||||
|
lx.push(lexTop)
|
||||||
|
return lexCommentStart
|
||||||
|
case isWhitespace(r):
|
||||||
|
return lexTopEnd
|
||||||
|
case isNL(r):
|
||||||
|
lx.ignore()
|
||||||
|
return lexTop
|
||||||
|
case r == eof:
|
||||||
|
lx.emit(itemEOF)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return lx.errorf("expected a top-level item to end with a newline, "+
|
||||||
|
"comment, or EOF, but got %q instead", r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// lexTable lexes the beginning of a table. Namely, it makes sure that
|
||||||
|
// it starts with a character other than '.' and ']'.
|
||||||
|
// It assumes that '[' has already been consumed.
|
||||||
|
// It also handles the case that this is an item in an array of tables.
|
||||||
|
// e.g., '[[name]]'.
|
||||||
|
func lexTableStart(lx *lexer) stateFn {
|
||||||
|
if lx.peek() == arrayTableStart {
|
||||||
|
lx.next()
|
||||||
|
lx.emit(itemArrayTableStart)
|
||||||
|
lx.push(lexArrayTableEnd)
|
||||||
|
} else {
|
||||||
|
lx.emit(itemTableStart)
|
||||||
|
lx.push(lexTableEnd)
|
||||||
|
}
|
||||||
|
return lexTableNameStart
|
||||||
|
}
|
||||||
|
|
||||||
|
func lexTableEnd(lx *lexer) stateFn {
|
||||||
|
lx.emit(itemTableEnd)
|
||||||
|
return lexTopEnd
|
||||||
|
}
|
||||||
|
|
||||||
|
func lexArrayTableEnd(lx *lexer) stateFn {
|
||||||
|
if r := lx.next(); r != arrayTableEnd {
|
||||||
|
return lx.errorf("expected end of table array name delimiter %q, "+
|
||||||
|
"but got %q instead", arrayTableEnd, r)
|
||||||
|
}
|
||||||
|
lx.emit(itemArrayTableEnd)
|
||||||
|
return lexTopEnd
|
||||||
|
}
|
||||||
|
|
||||||
|
func lexTableNameStart(lx *lexer) stateFn {
|
||||||
|
lx.skip(isWhitespace)
|
||||||
|
switch r := lx.peek(); {
|
||||||
|
case r == tableEnd || r == eof:
|
||||||
|
return lx.errorf("unexpected end of table name " +
|
||||||
|
"(table names cannot be empty)")
|
||||||
|
case r == tableSep:
|
||||||
|
return lx.errorf("unexpected table separator " +
|
||||||
|
"(table names cannot be empty)")
|
||||||
|
case r == stringStart || r == rawStringStart:
|
||||||
|
lx.ignore()
|
||||||
|
lx.push(lexTableNameEnd)
|
||||||
|
return lexValue // reuse string lexing
|
||||||
|
default:
|
||||||
|
return lexBareTableName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// lexBareTableName lexes the name of a table. It assumes that at least one
|
||||||
|
// valid character for the table has already been read.
|
||||||
|
func lexBareTableName(lx *lexer) stateFn {
|
||||||
|
r := lx.next()
|
||||||
|
if isBareKeyChar(r) {
|
||||||
|
return lexBareTableName
|
||||||
|
}
|
||||||
|
lx.backup()
|
||||||
|
lx.emit(itemText)
|
||||||
|
return lexTableNameEnd
|
||||||
|
}
|
||||||
|
|
||||||
|
// lexTableNameEnd reads the end of a piece of a table name, optionally
|
||||||
|
// consuming whitespace.
|
||||||
|
func lexTableNameEnd(lx *lexer) stateFn {
|
||||||
|
lx.skip(isWhitespace)
|
||||||
|
switch r := lx.next(); {
|
||||||
|
case isWhitespace(r):
|
||||||
|
return lexTableNameEnd
|
||||||
|
case r == tableSep:
|
||||||
|
lx.ignore()
|
||||||
|
return lexTableNameStart
|
||||||
|
case r == tableEnd:
|
||||||
|
return lx.pop()
|
||||||
|
default:
|
||||||
|
return lx.errorf("expected '.' or ']' to end table name, "+
|
||||||
|
"but got %q instead", r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// lexKeyStart consumes a key name up until the first non-whitespace character.
|
||||||
|
// lexKeyStart will ignore whitespace.
|
||||||
|
func lexKeyStart(lx *lexer) stateFn {
|
||||||
|
r := lx.peek()
|
||||||
|
switch {
|
||||||
|
case r == keySep:
|
||||||
|
return lx.errorf("unexpected key separator %q", keySep)
|
||||||
|
case isWhitespace(r) || isNL(r):
|
||||||
|
lx.next()
|
||||||
|
return lexSkip(lx, lexKeyStart)
|
||||||
|
case r == stringStart || r == rawStringStart:
|
||||||
|
lx.ignore()
|
||||||
|
lx.emit(itemKeyStart)
|
||||||
|
lx.push(lexKeyEnd)
|
||||||
|
return lexValue // reuse string lexing
|
||||||
|
default:
|
||||||
|
lx.ignore()
|
||||||
|
lx.emit(itemKeyStart)
|
||||||
|
return lexBareKey
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// lexBareKey consumes the text of a bare key. Assumes that the first character
|
||||||
|
// (which is not whitespace) has not yet been consumed.
|
||||||
|
func lexBareKey(lx *lexer) stateFn {
|
||||||
|
switch r := lx.next(); {
|
||||||
|
case isBareKeyChar(r):
|
||||||
|
return lexBareKey
|
||||||
|
case isWhitespace(r):
|
||||||
|
lx.backup()
|
||||||
|
lx.emit(itemText)
|
||||||
|
return lexKeyEnd
|
||||||
|
case r == keySep:
|
||||||
|
lx.backup()
|
||||||
|
lx.emit(itemText)
|
||||||
|
return lexKeyEnd
|
||||||
|
default:
|
||||||
|
return lx.errorf("bare keys cannot contain %q", r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// lexKeyEnd consumes the end of a key and trims whitespace (up to the key
|
||||||
|
// separator).
|
||||||
|
func lexKeyEnd(lx *lexer) stateFn {
|
||||||
|
switch r := lx.next(); {
|
||||||
|
case r == keySep:
|
||||||
|
return lexSkip(lx, lexValue)
|
||||||
|
case isWhitespace(r):
|
||||||
|
return lexSkip(lx, lexKeyEnd)
|
||||||
|
default:
|
||||||
|
return lx.errorf("expected key separator %q, but got %q instead",
|
||||||
|
keySep, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// lexValue starts the consumption of a value anywhere a value is expected.
|
||||||
|
// lexValue will ignore whitespace.
|
||||||
|
// After a value is lexed, the last state on the next is popped and returned.
|
||||||
|
func lexValue(lx *lexer) stateFn {
|
||||||
|
// We allow whitespace to precede a value, but NOT newlines.
|
||||||
|
// In array syntax, the array states are responsible for ignoring newlines.
|
||||||
|
r := lx.next()
|
||||||
|
switch {
|
||||||
|
case isWhitespace(r):
|
||||||
|
return lexSkip(lx, lexValue)
|
||||||
|
case isDigit(r):
|
||||||
|
lx.backup() // avoid an extra state and use the same as above
|
||||||
|
return lexNumberOrDateStart
|
||||||
|
}
|
||||||
|
switch r {
|
||||||
|
case arrayStart:
|
||||||
|
lx.ignore()
|
||||||
|
lx.emit(itemArray)
|
||||||
|
return lexArrayValue
|
||||||
|
case inlineTableStart:
|
||||||
|
lx.ignore()
|
||||||
|
lx.emit(itemInlineTableStart)
|
||||||
|
return lexInlineTableValue
|
||||||
|
case stringStart:
|
||||||
|
if lx.accept(stringStart) {
|
||||||
|
if lx.accept(stringStart) {
|
||||||
|
lx.ignore() // Ignore """
|
||||||
|
return lexMultilineString
|
||||||
|
}
|
||||||
|
lx.backup()
|
||||||
|
}
|
||||||
|
lx.ignore() // ignore the '"'
|
||||||
|
return lexString
|
||||||
|
case rawStringStart:
|
||||||
|
if lx.accept(rawStringStart) {
|
||||||
|
if lx.accept(rawStringStart) {
|
||||||
|
lx.ignore() // Ignore """
|
||||||
|
return lexMultilineRawString
|
||||||
|
}
|
||||||
|
lx.backup()
|
||||||
|
}
|
||||||
|
lx.ignore() // ignore the "'"
|
||||||
|
return lexRawString
|
||||||
|
case '+', '-':
|
||||||
|
return lexNumberStart
|
||||||
|
case '.': // special error case, be kind to users
|
||||||
|
return lx.errorf("floats must start with a digit, not '.'")
|
||||||
|
}
|
||||||
|
if unicode.IsLetter(r) {
|
||||||
|
// Be permissive here; lexBool will give a nice error if the
|
||||||
|
// user wrote something like
|
||||||
|
// x = foo
|
||||||
|
// (i.e. not 'true' or 'false' but is something else word-like.)
|
||||||
|
lx.backup()
|
||||||
|
return lexBool
|
||||||
|
}
|
||||||
|
return lx.errorf("expected value but found %q instead", r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// lexArrayValue consumes one value in an array. It assumes that '[' or ','
|
||||||
|
// have already been consumed. All whitespace and newlines are ignored.
|
||||||
|
func lexArrayValue(lx *lexer) stateFn {
|
||||||
|
r := lx.next()
|
||||||
|
switch {
|
||||||
|
case isWhitespace(r) || isNL(r):
|
||||||
|
return lexSkip(lx, lexArrayValue)
|
||||||
|
case r == commentStart:
|
||||||
|
lx.push(lexArrayValue)
|
||||||
|
return lexCommentStart
|
||||||
|
case r == comma:
|
||||||
|
return lx.errorf("unexpected comma")
|
||||||
|
case r == arrayEnd:
|
||||||
|
// NOTE(caleb): The spec isn't clear about whether you can have
|
||||||
|
// a trailing comma or not, so we'll allow it.
|
||||||
|
return lexArrayEnd
|
||||||
|
}
|
||||||
|
|
||||||
|
lx.backup()
|
||||||
|
lx.push(lexArrayValueEnd)
|
||||||
|
return lexValue
|
||||||
|
}
|
||||||
|
|
||||||
|
// lexArrayValueEnd consumes everything between the end of an array value and
|
||||||
|
// the next value (or the end of the array): it ignores whitespace and newlines
|
||||||
|
// and expects either a ',' or a ']'.
|
||||||
|
func lexArrayValueEnd(lx *lexer) stateFn {
|
||||||
|
r := lx.next()
|
||||||
|
switch {
|
||||||
|
case isWhitespace(r) || isNL(r):
|
||||||
|
return lexSkip(lx, lexArrayValueEnd)
|
||||||
|
case r == commentStart:
|
||||||
|
lx.push(lexArrayValueEnd)
|
||||||
|
return lexCommentStart
|
||||||
|
case r == comma:
|
||||||
|
lx.ignore()
|
||||||
|
return lexArrayValue // move on to the next value
|
||||||
|
case r == arrayEnd:
|
||||||
|
return lexArrayEnd
|
||||||
|
}
|
||||||
|
return lx.errorf(
|
||||||
|
"expected a comma or array terminator %q, but got %q instead",
|
||||||
|
arrayEnd, r,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// lexArrayEnd finishes the lexing of an array.
|
||||||
|
// It assumes that a ']' has just been consumed.
|
||||||
|
func lexArrayEnd(lx *lexer) stateFn {
|
||||||
|
lx.ignore()
|
||||||
|
lx.emit(itemArrayEnd)
|
||||||
|
return lx.pop()
|
||||||
|
}
|
||||||
|
|
||||||
|
// lexInlineTableValue consumes one key/value pair in an inline table.
|
||||||
|
// It assumes that '{' or ',' have already been consumed. Whitespace is ignored.
|
||||||
|
func lexInlineTableValue(lx *lexer) stateFn {
|
||||||
|
r := lx.next()
|
||||||
|
switch {
|
||||||
|
case isWhitespace(r):
|
||||||
|
return lexSkip(lx, lexInlineTableValue)
|
||||||
|
case isNL(r):
|
||||||
|
return lx.errorf("newlines not allowed within inline tables")
|
||||||
|
case r == commentStart:
|
||||||
|
lx.push(lexInlineTableValue)
|
||||||
|
return lexCommentStart
|
||||||
|
case r == comma:
|
||||||
|
return lx.errorf("unexpected comma")
|
||||||
|
case r == inlineTableEnd:
|
||||||
|
return lexInlineTableEnd
|
||||||
|
}
|
||||||
|
lx.backup()
|
||||||
|
lx.push(lexInlineTableValueEnd)
|
||||||
|
return lexKeyStart
|
||||||
|
}
|
||||||
|
|
||||||
|
// lexInlineTableValueEnd consumes everything between the end of an inline table
|
||||||
|
// key/value pair and the next pair (or the end of the table):
|
||||||
|
// it ignores whitespace and expects either a ',' or a '}'.
|
||||||
|
func lexInlineTableValueEnd(lx *lexer) stateFn {
|
||||||
|
r := lx.next()
|
||||||
|
switch {
|
||||||
|
case isWhitespace(r):
|
||||||
|
return lexSkip(lx, lexInlineTableValueEnd)
|
||||||
|
case isNL(r):
|
||||||
|
return lx.errorf("newlines not allowed within inline tables")
|
||||||
|
case r == commentStart:
|
||||||
|
lx.push(lexInlineTableValueEnd)
|
||||||
|
return lexCommentStart
|
||||||
|
case r == comma:
|
||||||
|
lx.ignore()
|
||||||
|
return lexInlineTableValue
|
||||||
|
case r == inlineTableEnd:
|
||||||
|
return lexInlineTableEnd
|
||||||
|
}
|
||||||
|
return lx.errorf("expected a comma or an inline table terminator %q, "+
|
||||||
|
"but got %q instead", inlineTableEnd, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// lexInlineTableEnd finishes the lexing of an inline table.
|
||||||
|
// It assumes that a '}' has just been consumed.
|
||||||
|
func lexInlineTableEnd(lx *lexer) stateFn {
|
||||||
|
lx.ignore()
|
||||||
|
lx.emit(itemInlineTableEnd)
|
||||||
|
return lx.pop()
|
||||||
|
}
|
||||||
|
|
||||||
|
// lexString consumes the inner contents of a string. It assumes that the
|
||||||
|
// beginning '"' has already been consumed and ignored.
|
||||||
|
func lexString(lx *lexer) stateFn {
|
||||||
|
r := lx.next()
|
||||||
|
switch {
|
||||||
|
case r == eof:
|
||||||
|
return lx.errorf("unexpected EOF")
|
||||||
|
case isNL(r):
|
||||||
|
return lx.errorf("strings cannot contain newlines")
|
||||||
|
case r == '\\':
|
||||||
|
lx.push(lexString)
|
||||||
|
return lexStringEscape
|
||||||
|
case r == stringEnd:
|
||||||
|
lx.backup()
|
||||||
|
lx.emit(itemString)
|
||||||
|
lx.next()
|
||||||
|
lx.ignore()
|
||||||
|
return lx.pop()
|
||||||
|
}
|
||||||
|
return lexString
|
||||||
|
}
|
||||||
|
|
||||||
|
// lexMultilineString consumes the inner contents of a string. It assumes that
|
||||||
|
// the beginning '"""' has already been consumed and ignored.
|
||||||
|
func lexMultilineString(lx *lexer) stateFn {
|
||||||
|
switch lx.next() {
|
||||||
|
case eof:
|
||||||
|
return lx.errorf("unexpected EOF")
|
||||||
|
case '\\':
|
||||||
|
return lexMultilineStringEscape
|
||||||
|
case stringEnd:
|
||||||
|
if lx.accept(stringEnd) {
|
||||||
|
if lx.accept(stringEnd) {
|
||||||
|
lx.backup()
|
||||||
|
lx.backup()
|
||||||
|
lx.backup()
|
||||||
|
lx.emit(itemMultilineString)
|
||||||
|
lx.next()
|
||||||
|
lx.next()
|
||||||
|
lx.next()
|
||||||
|
lx.ignore()
|
||||||
|
return lx.pop()
|
||||||
|
}
|
||||||
|
lx.backup()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return lexMultilineString
|
||||||
|
}
|
||||||
|
|
||||||
|
// lexRawString consumes a raw string. Nothing can be escaped in such a string.
|
||||||
|
// It assumes that the beginning "'" has already been consumed and ignored.
|
||||||
|
func lexRawString(lx *lexer) stateFn {
|
||||||
|
r := lx.next()
|
||||||
|
switch {
|
||||||
|
case r == eof:
|
||||||
|
return lx.errorf("unexpected EOF")
|
||||||
|
case isNL(r):
|
||||||
|
return lx.errorf("strings cannot contain newlines")
|
||||||
|
case r == rawStringEnd:
|
||||||
|
lx.backup()
|
||||||
|
lx.emit(itemRawString)
|
||||||
|
lx.next()
|
||||||
|
lx.ignore()
|
||||||
|
return lx.pop()
|
||||||
|
}
|
||||||
|
return lexRawString
|
||||||
|
}
|
||||||
|
|
||||||
|
// lexMultilineRawString consumes a raw string. Nothing can be escaped in such
|
||||||
|
// a string. It assumes that the beginning "'''" has already been consumed and
|
||||||
|
// ignored.
|
||||||
|
func lexMultilineRawString(lx *lexer) stateFn {
|
||||||
|
switch lx.next() {
|
||||||
|
case eof:
|
||||||
|
return lx.errorf("unexpected EOF")
|
||||||
|
case rawStringEnd:
|
||||||
|
if lx.accept(rawStringEnd) {
|
||||||
|
if lx.accept(rawStringEnd) {
|
||||||
|
lx.backup()
|
||||||
|
lx.backup()
|
||||||
|
lx.backup()
|
||||||
|
lx.emit(itemRawMultilineString)
|
||||||
|
lx.next()
|
||||||
|
lx.next()
|
||||||
|
lx.next()
|
||||||
|
lx.ignore()
|
||||||
|
return lx.pop()
|
||||||
|
}
|
||||||
|
lx.backup()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return lexMultilineRawString
|
||||||
|
}
|
||||||
|
|
||||||
|
// lexMultilineStringEscape consumes an escaped character. It assumes that the
|
||||||
|
// preceding '\\' has already been consumed.
|
||||||
|
func lexMultilineStringEscape(lx *lexer) stateFn {
|
||||||
|
// Handle the special case first:
|
||||||
|
if isNL(lx.next()) {
|
||||||
|
return lexMultilineString
|
||||||
|
}
|
||||||
|
lx.backup()
|
||||||
|
lx.push(lexMultilineString)
|
||||||
|
return lexStringEscape(lx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func lexStringEscape(lx *lexer) stateFn {
|
||||||
|
r := lx.next()
|
||||||
|
switch r {
|
||||||
|
case 'b':
|
||||||
|
fallthrough
|
||||||
|
case 't':
|
||||||
|
fallthrough
|
||||||
|
case 'n':
|
||||||
|
fallthrough
|
||||||
|
case 'f':
|
||||||
|
fallthrough
|
||||||
|
case 'r':
|
||||||
|
fallthrough
|
||||||
|
case '"':
|
||||||
|
fallthrough
|
||||||
|
case '\\':
|
||||||
|
return lx.pop()
|
||||||
|
case 'u':
|
||||||
|
return lexShortUnicodeEscape
|
||||||
|
case 'U':
|
||||||
|
return lexLongUnicodeEscape
|
||||||
|
}
|
||||||
|
return lx.errorf("invalid escape character %q; only the following "+
|
||||||
|
"escape characters are allowed: "+
|
||||||
|
`\b, \t, \n, \f, \r, \", \\, \uXXXX, and \UXXXXXXXX`, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func lexShortUnicodeEscape(lx *lexer) stateFn {
|
||||||
|
var r rune
|
||||||
|
for i := 0; i < 4; i++ {
|
||||||
|
r = lx.next()
|
||||||
|
if !isHexadecimal(r) {
|
||||||
|
return lx.errorf(`expected four hexadecimal digits after '\u', `+
|
||||||
|
"but got %q instead", lx.current())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return lx.pop()
|
||||||
|
}
|
||||||
|
|
||||||
|
func lexLongUnicodeEscape(lx *lexer) stateFn {
|
||||||
|
var r rune
|
||||||
|
for i := 0; i < 8; i++ {
|
||||||
|
r = lx.next()
|
||||||
|
if !isHexadecimal(r) {
|
||||||
|
return lx.errorf(`expected eight hexadecimal digits after '\U', `+
|
||||||
|
"but got %q instead", lx.current())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return lx.pop()
|
||||||
|
}
|
||||||
|
|
||||||
|
// lexNumberOrDateStart consumes either an integer, a float, or datetime.
|
||||||
|
func lexNumberOrDateStart(lx *lexer) stateFn {
|
||||||
|
r := lx.next()
|
||||||
|
if isDigit(r) {
|
||||||
|
return lexNumberOrDate
|
||||||
|
}
|
||||||
|
switch r {
|
||||||
|
case '_':
|
||||||
|
return lexNumber
|
||||||
|
case 'e', 'E':
|
||||||
|
return lexFloat
|
||||||
|
case '.':
|
||||||
|
return lx.errorf("floats must start with a digit, not '.'")
|
||||||
|
}
|
||||||
|
return lx.errorf("expected a digit but got %q", r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// lexNumberOrDate consumes either an integer, float or datetime.
|
||||||
|
func lexNumberOrDate(lx *lexer) stateFn {
|
||||||
|
r := lx.next()
|
||||||
|
if isDigit(r) {
|
||||||
|
return lexNumberOrDate
|
||||||
|
}
|
||||||
|
switch r {
|
||||||
|
case '-':
|
||||||
|
return lexDatetime
|
||||||
|
case '_':
|
||||||
|
return lexNumber
|
||||||
|
case '.', 'e', 'E':
|
||||||
|
return lexFloat
|
||||||
|
}
|
||||||
|
|
||||||
|
lx.backup()
|
||||||
|
lx.emit(itemInteger)
|
||||||
|
return lx.pop()
|
||||||
|
}
|
||||||
|
|
||||||
|
// lexDatetime consumes a Datetime, to a first approximation.
|
||||||
|
// The parser validates that it matches one of the accepted formats.
|
||||||
|
func lexDatetime(lx *lexer) stateFn {
|
||||||
|
r := lx.next()
|
||||||
|
if isDigit(r) {
|
||||||
|
return lexDatetime
|
||||||
|
}
|
||||||
|
switch r {
|
||||||
|
case '-', 'T', ':', '.', 'Z', '+':
|
||||||
|
return lexDatetime
|
||||||
|
}
|
||||||
|
|
||||||
|
lx.backup()
|
||||||
|
lx.emit(itemDatetime)
|
||||||
|
return lx.pop()
|
||||||
|
}
|
||||||
|
|
||||||
|
// lexNumberStart consumes either an integer or a float. It assumes that a sign
|
||||||
|
// has already been read, but that *no* digits have been consumed.
|
||||||
|
// lexNumberStart will move to the appropriate integer or float states.
|
||||||
|
func lexNumberStart(lx *lexer) stateFn {
|
||||||
|
// We MUST see a digit. Even floats have to start with a digit.
|
||||||
|
r := lx.next()
|
||||||
|
if !isDigit(r) {
|
||||||
|
if r == '.' {
|
||||||
|
return lx.errorf("floats must start with a digit, not '.'")
|
||||||
|
}
|
||||||
|
return lx.errorf("expected a digit but got %q", r)
|
||||||
|
}
|
||||||
|
return lexNumber
|
||||||
|
}
|
||||||
|
|
||||||
|
// lexNumber consumes an integer or a float after seeing the first digit.
|
||||||
|
func lexNumber(lx *lexer) stateFn {
|
||||||
|
r := lx.next()
|
||||||
|
if isDigit(r) {
|
||||||
|
return lexNumber
|
||||||
|
}
|
||||||
|
switch r {
|
||||||
|
case '_':
|
||||||
|
return lexNumber
|
||||||
|
case '.', 'e', 'E':
|
||||||
|
return lexFloat
|
||||||
|
}
|
||||||
|
|
||||||
|
lx.backup()
|
||||||
|
lx.emit(itemInteger)
|
||||||
|
return lx.pop()
|
||||||
|
}
|
||||||
|
|
||||||
|
// lexFloat consumes the elements of a float. It allows any sequence of
|
||||||
|
// float-like characters, so floats emitted by the lexer are only a first
|
||||||
|
// approximation and must be validated by the parser.
|
||||||
|
func lexFloat(lx *lexer) stateFn {
|
||||||
|
r := lx.next()
|
||||||
|
if isDigit(r) {
|
||||||
|
return lexFloat
|
||||||
|
}
|
||||||
|
switch r {
|
||||||
|
case '_', '.', '-', '+', 'e', 'E':
|
||||||
|
return lexFloat
|
||||||
|
}
|
||||||
|
|
||||||
|
lx.backup()
|
||||||
|
lx.emit(itemFloat)
|
||||||
|
return lx.pop()
|
||||||
|
}
|
||||||
|
|
||||||
|
// lexBool consumes a bool string: 'true' or 'false.
|
||||||
|
func lexBool(lx *lexer) stateFn {
|
||||||
|
var rs []rune
|
||||||
|
for {
|
||||||
|
r := lx.next()
|
||||||
|
if !unicode.IsLetter(r) {
|
||||||
|
lx.backup()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
rs = append(rs, r)
|
||||||
|
}
|
||||||
|
s := string(rs)
|
||||||
|
switch s {
|
||||||
|
case "true", "false":
|
||||||
|
lx.emit(itemBool)
|
||||||
|
return lx.pop()
|
||||||
|
}
|
||||||
|
return lx.errorf("expected value but found %q instead", s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// lexCommentStart begins the lexing of a comment. It will emit
|
||||||
|
// itemCommentStart and consume no characters, passing control to lexComment.
|
||||||
|
func lexCommentStart(lx *lexer) stateFn {
|
||||||
|
lx.ignore()
|
||||||
|
lx.emit(itemCommentStart)
|
||||||
|
return lexComment
|
||||||
|
}
|
||||||
|
|
||||||
|
// lexComment lexes an entire comment. It assumes that '#' has been consumed.
|
||||||
|
// It will consume *up to* the first newline character, and pass control
|
||||||
|
// back to the last state on the stack.
|
||||||
|
func lexComment(lx *lexer) stateFn {
|
||||||
|
r := lx.peek()
|
||||||
|
if isNL(r) || r == eof {
|
||||||
|
lx.emit(itemText)
|
||||||
|
return lx.pop()
|
||||||
|
}
|
||||||
|
lx.next()
|
||||||
|
return lexComment
|
||||||
|
}
|
||||||
|
|
||||||
|
// lexSkip ignores all slurped input and moves on to the next state.
|
||||||
|
func lexSkip(lx *lexer, nextState stateFn) stateFn {
|
||||||
|
return func(lx *lexer) stateFn {
|
||||||
|
lx.ignore()
|
||||||
|
return nextState
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// isWhitespace returns true if `r` is a whitespace character according
|
||||||
|
// to the spec.
|
||||||
|
func isWhitespace(r rune) bool {
|
||||||
|
return r == '\t' || r == ' '
|
||||||
|
}
|
||||||
|
|
||||||
|
func isNL(r rune) bool {
|
||||||
|
return r == '\n' || r == '\r'
|
||||||
|
}
|
||||||
|
|
||||||
|
func isDigit(r rune) bool {
|
||||||
|
return r >= '0' && r <= '9'
|
||||||
|
}
|
||||||
|
|
||||||
|
func isHexadecimal(r rune) bool {
|
||||||
|
return (r >= '0' && r <= '9') ||
|
||||||
|
(r >= 'a' && r <= 'f') ||
|
||||||
|
(r >= 'A' && r <= 'F')
|
||||||
|
}
|
||||||
|
|
||||||
|
func isBareKeyChar(r rune) bool {
|
||||||
|
return (r >= 'A' && r <= 'Z') ||
|
||||||
|
(r >= 'a' && r <= 'z') ||
|
||||||
|
(r >= '0' && r <= '9') ||
|
||||||
|
r == '_' ||
|
||||||
|
r == '-'
|
||||||
|
}
|
||||||
|
|
||||||
|
func (itype itemType) String() string {
|
||||||
|
switch itype {
|
||||||
|
case itemError:
|
||||||
|
return "Error"
|
||||||
|
case itemNIL:
|
||||||
|
return "NIL"
|
||||||
|
case itemEOF:
|
||||||
|
return "EOF"
|
||||||
|
case itemText:
|
||||||
|
return "Text"
|
||||||
|
case itemString, itemRawString, itemMultilineString, itemRawMultilineString:
|
||||||
|
return "String"
|
||||||
|
case itemBool:
|
||||||
|
return "Bool"
|
||||||
|
case itemInteger:
|
||||||
|
return "Integer"
|
||||||
|
case itemFloat:
|
||||||
|
return "Float"
|
||||||
|
case itemDatetime:
|
||||||
|
return "DateTime"
|
||||||
|
case itemTableStart:
|
||||||
|
return "TableStart"
|
||||||
|
case itemTableEnd:
|
||||||
|
return "TableEnd"
|
||||||
|
case itemKeyStart:
|
||||||
|
return "KeyStart"
|
||||||
|
case itemArray:
|
||||||
|
return "Array"
|
||||||
|
case itemArrayEnd:
|
||||||
|
return "ArrayEnd"
|
||||||
|
case itemCommentStart:
|
||||||
|
return "CommentStart"
|
||||||
|
}
|
||||||
|
panic(fmt.Sprintf("BUG: Unknown type '%d'.", int(itype)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (item item) String() string {
|
||||||
|
return fmt.Sprintf("(%s, %s)", item.typ.String(), item.val)
|
||||||
|
}
|
592
vendor/github.com/BurntSushi/toml/parse.go
generated
vendored
Normal file
592
vendor/github.com/BurntSushi/toml/parse.go
generated
vendored
Normal file
@ -0,0 +1,592 @@
|
|||||||
|
package toml
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
"unicode"
|
||||||
|
"unicode/utf8"
|
||||||
|
)
|
||||||
|
|
||||||
|
type parser struct {
|
||||||
|
mapping map[string]interface{}
|
||||||
|
types map[string]tomlType
|
||||||
|
lx *lexer
|
||||||
|
|
||||||
|
// A list of keys in the order that they appear in the TOML data.
|
||||||
|
ordered []Key
|
||||||
|
|
||||||
|
// the full key for the current hash in scope
|
||||||
|
context Key
|
||||||
|
|
||||||
|
// the base key name for everything except hashes
|
||||||
|
currentKey string
|
||||||
|
|
||||||
|
// rough approximation of line number
|
||||||
|
approxLine int
|
||||||
|
|
||||||
|
// A map of 'key.group.names' to whether they were created implicitly.
|
||||||
|
implicits map[string]bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type parseError string
|
||||||
|
|
||||||
|
func (pe parseError) Error() string {
|
||||||
|
return string(pe)
|
||||||
|
}
|
||||||
|
|
||||||
|
func parse(data string) (p *parser, err error) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
var ok bool
|
||||||
|
if err, ok = r.(parseError); ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
panic(r)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
p = &parser{
|
||||||
|
mapping: make(map[string]interface{}),
|
||||||
|
types: make(map[string]tomlType),
|
||||||
|
lx: lex(data),
|
||||||
|
ordered: make([]Key, 0),
|
||||||
|
implicits: make(map[string]bool),
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
item := p.next()
|
||||||
|
if item.typ == itemEOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
p.topLevel(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
return p, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *parser) panicf(format string, v ...interface{}) {
|
||||||
|
msg := fmt.Sprintf("Near line %d (last key parsed '%s'): %s",
|
||||||
|
p.approxLine, p.current(), fmt.Sprintf(format, v...))
|
||||||
|
panic(parseError(msg))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *parser) next() item {
|
||||||
|
it := p.lx.nextItem()
|
||||||
|
if it.typ == itemError {
|
||||||
|
p.panicf("%s", it.val)
|
||||||
|
}
|
||||||
|
return it
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *parser) bug(format string, v ...interface{}) {
|
||||||
|
panic(fmt.Sprintf("BUG: "+format+"\n\n", v...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *parser) expect(typ itemType) item {
|
||||||
|
it := p.next()
|
||||||
|
p.assertEqual(typ, it.typ)
|
||||||
|
return it
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *parser) assertEqual(expected, got itemType) {
|
||||||
|
if expected != got {
|
||||||
|
p.bug("Expected '%s' but got '%s'.", expected, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *parser) topLevel(item item) {
|
||||||
|
switch item.typ {
|
||||||
|
case itemCommentStart:
|
||||||
|
p.approxLine = item.line
|
||||||
|
p.expect(itemText)
|
||||||
|
case itemTableStart:
|
||||||
|
kg := p.next()
|
||||||
|
p.approxLine = kg.line
|
||||||
|
|
||||||
|
var key Key
|
||||||
|
for ; kg.typ != itemTableEnd && kg.typ != itemEOF; kg = p.next() {
|
||||||
|
key = append(key, p.keyString(kg))
|
||||||
|
}
|
||||||
|
p.assertEqual(itemTableEnd, kg.typ)
|
||||||
|
|
||||||
|
p.establishContext(key, false)
|
||||||
|
p.setType("", tomlHash)
|
||||||
|
p.ordered = append(p.ordered, key)
|
||||||
|
case itemArrayTableStart:
|
||||||
|
kg := p.next()
|
||||||
|
p.approxLine = kg.line
|
||||||
|
|
||||||
|
var key Key
|
||||||
|
for ; kg.typ != itemArrayTableEnd && kg.typ != itemEOF; kg = p.next() {
|
||||||
|
key = append(key, p.keyString(kg))
|
||||||
|
}
|
||||||
|
p.assertEqual(itemArrayTableEnd, kg.typ)
|
||||||
|
|
||||||
|
p.establishContext(key, true)
|
||||||
|
p.setType("", tomlArrayHash)
|
||||||
|
p.ordered = append(p.ordered, key)
|
||||||
|
case itemKeyStart:
|
||||||
|
kname := p.next()
|
||||||
|
p.approxLine = kname.line
|
||||||
|
p.currentKey = p.keyString(kname)
|
||||||
|
|
||||||
|
val, typ := p.value(p.next())
|
||||||
|
p.setValue(p.currentKey, val)
|
||||||
|
p.setType(p.currentKey, typ)
|
||||||
|
p.ordered = append(p.ordered, p.context.add(p.currentKey))
|
||||||
|
p.currentKey = ""
|
||||||
|
default:
|
||||||
|
p.bug("Unexpected type at top level: %s", item.typ)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets a string for a key (or part of a key in a table name).
|
||||||
|
func (p *parser) keyString(it item) string {
|
||||||
|
switch it.typ {
|
||||||
|
case itemText:
|
||||||
|
return it.val
|
||||||
|
case itemString, itemMultilineString,
|
||||||
|
itemRawString, itemRawMultilineString:
|
||||||
|
s, _ := p.value(it)
|
||||||
|
return s.(string)
|
||||||
|
default:
|
||||||
|
p.bug("Unexpected key type: %s", it.typ)
|
||||||
|
panic("unreachable")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// value translates an expected value from the lexer into a Go value wrapped
|
||||||
|
// as an empty interface.
|
||||||
|
func (p *parser) value(it item) (interface{}, tomlType) {
|
||||||
|
switch it.typ {
|
||||||
|
case itemString:
|
||||||
|
return p.replaceEscapes(it.val), p.typeOfPrimitive(it)
|
||||||
|
case itemMultilineString:
|
||||||
|
trimmed := stripFirstNewline(stripEscapedWhitespace(it.val))
|
||||||
|
return p.replaceEscapes(trimmed), p.typeOfPrimitive(it)
|
||||||
|
case itemRawString:
|
||||||
|
return it.val, p.typeOfPrimitive(it)
|
||||||
|
case itemRawMultilineString:
|
||||||
|
return stripFirstNewline(it.val), p.typeOfPrimitive(it)
|
||||||
|
case itemBool:
|
||||||
|
switch it.val {
|
||||||
|
case "true":
|
||||||
|
return true, p.typeOfPrimitive(it)
|
||||||
|
case "false":
|
||||||
|
return false, p.typeOfPrimitive(it)
|
||||||
|
}
|
||||||
|
p.bug("Expected boolean value, but got '%s'.", it.val)
|
||||||
|
case itemInteger:
|
||||||
|
if !numUnderscoresOK(it.val) {
|
||||||
|
p.panicf("Invalid integer %q: underscores must be surrounded by digits",
|
||||||
|
it.val)
|
||||||
|
}
|
||||||
|
val := strings.Replace(it.val, "_", "", -1)
|
||||||
|
num, err := strconv.ParseInt(val, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
// Distinguish integer values. Normally, it'd be a bug if the lexer
|
||||||
|
// provides an invalid integer, but it's possible that the number is
|
||||||
|
// out of range of valid values (which the lexer cannot determine).
|
||||||
|
// So mark the former as a bug but the latter as a legitimate user
|
||||||
|
// error.
|
||||||
|
if e, ok := err.(*strconv.NumError); ok &&
|
||||||
|
e.Err == strconv.ErrRange {
|
||||||
|
|
||||||
|
p.panicf("Integer '%s' is out of the range of 64-bit "+
|
||||||
|
"signed integers.", it.val)
|
||||||
|
} else {
|
||||||
|
p.bug("Expected integer value, but got '%s'.", it.val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return num, p.typeOfPrimitive(it)
|
||||||
|
case itemFloat:
|
||||||
|
parts := strings.FieldsFunc(it.val, func(r rune) bool {
|
||||||
|
switch r {
|
||||||
|
case '.', 'e', 'E':
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
for _, part := range parts {
|
||||||
|
if !numUnderscoresOK(part) {
|
||||||
|
p.panicf("Invalid float %q: underscores must be "+
|
||||||
|
"surrounded by digits", it.val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !numPeriodsOK(it.val) {
|
||||||
|
// As a special case, numbers like '123.' or '1.e2',
|
||||||
|
// which are valid as far as Go/strconv are concerned,
|
||||||
|
// must be rejected because TOML says that a fractional
|
||||||
|
// part consists of '.' followed by 1+ digits.
|
||||||
|
p.panicf("Invalid float %q: '.' must be followed "+
|
||||||
|
"by one or more digits", it.val)
|
||||||
|
}
|
||||||
|
val := strings.Replace(it.val, "_", "", -1)
|
||||||
|
num, err := strconv.ParseFloat(val, 64)
|
||||||
|
if err != nil {
|
||||||
|
if e, ok := err.(*strconv.NumError); ok &&
|
||||||
|
e.Err == strconv.ErrRange {
|
||||||
|
|
||||||
|
p.panicf("Float '%s' is out of the range of 64-bit "+
|
||||||
|
"IEEE-754 floating-point numbers.", it.val)
|
||||||
|
} else {
|
||||||
|
p.panicf("Invalid float value: %q", it.val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return num, p.typeOfPrimitive(it)
|
||||||
|
case itemDatetime:
|
||||||
|
var t time.Time
|
||||||
|
var ok bool
|
||||||
|
var err error
|
||||||
|
for _, format := range []string{
|
||||||
|
"2006-01-02T15:04:05Z07:00",
|
||||||
|
"2006-01-02T15:04:05",
|
||||||
|
"2006-01-02",
|
||||||
|
} {
|
||||||
|
t, err = time.ParseInLocation(format, it.val, time.Local)
|
||||||
|
if err == nil {
|
||||||
|
ok = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
p.panicf("Invalid TOML Datetime: %q.", it.val)
|
||||||
|
}
|
||||||
|
return t, p.typeOfPrimitive(it)
|
||||||
|
case itemArray:
|
||||||
|
array := make([]interface{}, 0)
|
||||||
|
types := make([]tomlType, 0)
|
||||||
|
|
||||||
|
for it = p.next(); it.typ != itemArrayEnd; it = p.next() {
|
||||||
|
if it.typ == itemCommentStart {
|
||||||
|
p.expect(itemText)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
val, typ := p.value(it)
|
||||||
|
array = append(array, val)
|
||||||
|
types = append(types, typ)
|
||||||
|
}
|
||||||
|
return array, p.typeOfArray(types)
|
||||||
|
case itemInlineTableStart:
|
||||||
|
var (
|
||||||
|
hash = make(map[string]interface{})
|
||||||
|
outerContext = p.context
|
||||||
|
outerKey = p.currentKey
|
||||||
|
)
|
||||||
|
|
||||||
|
p.context = append(p.context, p.currentKey)
|
||||||
|
p.currentKey = ""
|
||||||
|
for it := p.next(); it.typ != itemInlineTableEnd; it = p.next() {
|
||||||
|
if it.typ != itemKeyStart {
|
||||||
|
p.bug("Expected key start but instead found %q, around line %d",
|
||||||
|
it.val, p.approxLine)
|
||||||
|
}
|
||||||
|
if it.typ == itemCommentStart {
|
||||||
|
p.expect(itemText)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// retrieve key
|
||||||
|
k := p.next()
|
||||||
|
p.approxLine = k.line
|
||||||
|
kname := p.keyString(k)
|
||||||
|
|
||||||
|
// retrieve value
|
||||||
|
p.currentKey = kname
|
||||||
|
val, typ := p.value(p.next())
|
||||||
|
// make sure we keep metadata up to date
|
||||||
|
p.setType(kname, typ)
|
||||||
|
p.ordered = append(p.ordered, p.context.add(p.currentKey))
|
||||||
|
hash[kname] = val
|
||||||
|
}
|
||||||
|
p.context = outerContext
|
||||||
|
p.currentKey = outerKey
|
||||||
|
return hash, tomlHash
|
||||||
|
}
|
||||||
|
p.bug("Unexpected value type: %s", it.typ)
|
||||||
|
panic("unreachable")
|
||||||
|
}
|
||||||
|
|
||||||
|
// numUnderscoresOK checks whether each underscore in s is surrounded by
|
||||||
|
// characters that are not underscores.
|
||||||
|
func numUnderscoresOK(s string) bool {
|
||||||
|
accept := false
|
||||||
|
for _, r := range s {
|
||||||
|
if r == '_' {
|
||||||
|
if !accept {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
accept = false
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
accept = true
|
||||||
|
}
|
||||||
|
return accept
|
||||||
|
}
|
||||||
|
|
||||||
|
// numPeriodsOK checks whether every period in s is followed by a digit.
|
||||||
|
func numPeriodsOK(s string) bool {
|
||||||
|
period := false
|
||||||
|
for _, r := range s {
|
||||||
|
if period && !isDigit(r) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
period = r == '.'
|
||||||
|
}
|
||||||
|
return !period
|
||||||
|
}
|
||||||
|
|
||||||
|
// establishContext sets the current context of the parser,
|
||||||
|
// where the context is either a hash or an array of hashes. Which one is
|
||||||
|
// set depends on the value of the `array` parameter.
|
||||||
|
//
|
||||||
|
// Establishing the context also makes sure that the key isn't a duplicate, and
|
||||||
|
// will create implicit hashes automatically.
|
||||||
|
func (p *parser) establishContext(key Key, array bool) {
|
||||||
|
var ok bool
|
||||||
|
|
||||||
|
// Always start at the top level and drill down for our context.
|
||||||
|
hashContext := p.mapping
|
||||||
|
keyContext := make(Key, 0)
|
||||||
|
|
||||||
|
// We only need implicit hashes for key[0:-1]
|
||||||
|
for _, k := range key[0 : len(key)-1] {
|
||||||
|
_, ok = hashContext[k]
|
||||||
|
keyContext = append(keyContext, k)
|
||||||
|
|
||||||
|
// No key? Make an implicit hash and move on.
|
||||||
|
if !ok {
|
||||||
|
p.addImplicit(keyContext)
|
||||||
|
hashContext[k] = make(map[string]interface{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the hash context is actually an array of tables, then set
|
||||||
|
// the hash context to the last element in that array.
|
||||||
|
//
|
||||||
|
// Otherwise, it better be a table, since this MUST be a key group (by
|
||||||
|
// virtue of it not being the last element in a key).
|
||||||
|
switch t := hashContext[k].(type) {
|
||||||
|
case []map[string]interface{}:
|
||||||
|
hashContext = t[len(t)-1]
|
||||||
|
case map[string]interface{}:
|
||||||
|
hashContext = t
|
||||||
|
default:
|
||||||
|
p.panicf("Key '%s' was already created as a hash.", keyContext)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p.context = keyContext
|
||||||
|
if array {
|
||||||
|
// If this is the first element for this array, then allocate a new
|
||||||
|
// list of tables for it.
|
||||||
|
k := key[len(key)-1]
|
||||||
|
if _, ok := hashContext[k]; !ok {
|
||||||
|
hashContext[k] = make([]map[string]interface{}, 0, 5)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a new table. But make sure the key hasn't already been used
|
||||||
|
// for something else.
|
||||||
|
if hash, ok := hashContext[k].([]map[string]interface{}); ok {
|
||||||
|
hashContext[k] = append(hash, make(map[string]interface{}))
|
||||||
|
} else {
|
||||||
|
p.panicf("Key '%s' was already created and cannot be used as "+
|
||||||
|
"an array.", keyContext)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
p.setValue(key[len(key)-1], make(map[string]interface{}))
|
||||||
|
}
|
||||||
|
p.context = append(p.context, key[len(key)-1])
|
||||||
|
}
|
||||||
|
|
||||||
|
// setValue sets the given key to the given value in the current context.
|
||||||
|
// It will make sure that the key hasn't already been defined, account for
|
||||||
|
// implicit key groups.
|
||||||
|
func (p *parser) setValue(key string, value interface{}) {
|
||||||
|
var tmpHash interface{}
|
||||||
|
var ok bool
|
||||||
|
|
||||||
|
hash := p.mapping
|
||||||
|
keyContext := make(Key, 0)
|
||||||
|
for _, k := range p.context {
|
||||||
|
keyContext = append(keyContext, k)
|
||||||
|
if tmpHash, ok = hash[k]; !ok {
|
||||||
|
p.bug("Context for key '%s' has not been established.", keyContext)
|
||||||
|
}
|
||||||
|
switch t := tmpHash.(type) {
|
||||||
|
case []map[string]interface{}:
|
||||||
|
// The context is a table of hashes. Pick the most recent table
|
||||||
|
// defined as the current hash.
|
||||||
|
hash = t[len(t)-1]
|
||||||
|
case map[string]interface{}:
|
||||||
|
hash = t
|
||||||
|
default:
|
||||||
|
p.bug("Expected hash to have type 'map[string]interface{}', but "+
|
||||||
|
"it has '%T' instead.", tmpHash)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
keyContext = append(keyContext, key)
|
||||||
|
|
||||||
|
if _, ok := hash[key]; ok {
|
||||||
|
// Typically, if the given key has already been set, then we have
|
||||||
|
// to raise an error since duplicate keys are disallowed. However,
|
||||||
|
// it's possible that a key was previously defined implicitly. In this
|
||||||
|
// case, it is allowed to be redefined concretely. (See the
|
||||||
|
// `tests/valid/implicit-and-explicit-after.toml` test in `toml-test`.)
|
||||||
|
//
|
||||||
|
// But we have to make sure to stop marking it as an implicit. (So that
|
||||||
|
// another redefinition provokes an error.)
|
||||||
|
//
|
||||||
|
// Note that since it has already been defined (as a hash), we don't
|
||||||
|
// want to overwrite it. So our business is done.
|
||||||
|
if p.isImplicit(keyContext) {
|
||||||
|
p.removeImplicit(keyContext)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, we have a concrete key trying to override a previous
|
||||||
|
// key, which is *always* wrong.
|
||||||
|
p.panicf("Key '%s' has already been defined.", keyContext)
|
||||||
|
}
|
||||||
|
hash[key] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
// setType sets the type of a particular value at a given key.
|
||||||
|
// It should be called immediately AFTER setValue.
|
||||||
|
//
|
||||||
|
// Note that if `key` is empty, then the type given will be applied to the
|
||||||
|
// current context (which is either a table or an array of tables).
|
||||||
|
func (p *parser) setType(key string, typ tomlType) {
|
||||||
|
keyContext := make(Key, 0, len(p.context)+1)
|
||||||
|
for _, k := range p.context {
|
||||||
|
keyContext = append(keyContext, k)
|
||||||
|
}
|
||||||
|
if len(key) > 0 { // allow type setting for hashes
|
||||||
|
keyContext = append(keyContext, key)
|
||||||
|
}
|
||||||
|
p.types[keyContext.String()] = typ
|
||||||
|
}
|
||||||
|
|
||||||
|
// addImplicit sets the given Key as having been created implicitly.
|
||||||
|
func (p *parser) addImplicit(key Key) {
|
||||||
|
p.implicits[key.String()] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// removeImplicit stops tagging the given key as having been implicitly
|
||||||
|
// created.
|
||||||
|
func (p *parser) removeImplicit(key Key) {
|
||||||
|
p.implicits[key.String()] = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// isImplicit returns true if the key group pointed to by the key was created
|
||||||
|
// implicitly.
|
||||||
|
func (p *parser) isImplicit(key Key) bool {
|
||||||
|
return p.implicits[key.String()]
|
||||||
|
}
|
||||||
|
|
||||||
|
// current returns the full key name of the current context.
|
||||||
|
func (p *parser) current() string {
|
||||||
|
if len(p.currentKey) == 0 {
|
||||||
|
return p.context.String()
|
||||||
|
}
|
||||||
|
if len(p.context) == 0 {
|
||||||
|
return p.currentKey
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s.%s", p.context, p.currentKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
func stripFirstNewline(s string) string {
|
||||||
|
if len(s) == 0 || s[0] != '\n' {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
return s[1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
func stripEscapedWhitespace(s string) string {
|
||||||
|
esc := strings.Split(s, "\\\n")
|
||||||
|
if len(esc) > 1 {
|
||||||
|
for i := 1; i < len(esc); i++ {
|
||||||
|
esc[i] = strings.TrimLeftFunc(esc[i], unicode.IsSpace)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return strings.Join(esc, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *parser) replaceEscapes(str string) string {
|
||||||
|
var replaced []rune
|
||||||
|
s := []byte(str)
|
||||||
|
r := 0
|
||||||
|
for r < len(s) {
|
||||||
|
if s[r] != '\\' {
|
||||||
|
c, size := utf8.DecodeRune(s[r:])
|
||||||
|
r += size
|
||||||
|
replaced = append(replaced, c)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
r += 1
|
||||||
|
if r >= len(s) {
|
||||||
|
p.bug("Escape sequence at end of string.")
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
switch s[r] {
|
||||||
|
default:
|
||||||
|
p.bug("Expected valid escape code after \\, but got %q.", s[r])
|
||||||
|
return ""
|
||||||
|
case 'b':
|
||||||
|
replaced = append(replaced, rune(0x0008))
|
||||||
|
r += 1
|
||||||
|
case 't':
|
||||||
|
replaced = append(replaced, rune(0x0009))
|
||||||
|
r += 1
|
||||||
|
case 'n':
|
||||||
|
replaced = append(replaced, rune(0x000A))
|
||||||
|
r += 1
|
||||||
|
case 'f':
|
||||||
|
replaced = append(replaced, rune(0x000C))
|
||||||
|
r += 1
|
||||||
|
case 'r':
|
||||||
|
replaced = append(replaced, rune(0x000D))
|
||||||
|
r += 1
|
||||||
|
case '"':
|
||||||
|
replaced = append(replaced, rune(0x0022))
|
||||||
|
r += 1
|
||||||
|
case '\\':
|
||||||
|
replaced = append(replaced, rune(0x005C))
|
||||||
|
r += 1
|
||||||
|
case 'u':
|
||||||
|
// At this point, we know we have a Unicode escape of the form
|
||||||
|
// `uXXXX` at [r, r+5). (Because the lexer guarantees this
|
||||||
|
// for us.)
|
||||||
|
escaped := p.asciiEscapeToUnicode(s[r+1 : r+5])
|
||||||
|
replaced = append(replaced, escaped)
|
||||||
|
r += 5
|
||||||
|
case 'U':
|
||||||
|
// At this point, we know we have a Unicode escape of the form
|
||||||
|
// `uXXXX` at [r, r+9). (Because the lexer guarantees this
|
||||||
|
// for us.)
|
||||||
|
escaped := p.asciiEscapeToUnicode(s[r+1 : r+9])
|
||||||
|
replaced = append(replaced, escaped)
|
||||||
|
r += 9
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return string(replaced)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *parser) asciiEscapeToUnicode(bs []byte) rune {
|
||||||
|
s := string(bs)
|
||||||
|
hex, err := strconv.ParseUint(strings.ToLower(s), 16, 32)
|
||||||
|
if err != nil {
|
||||||
|
p.bug("Could not parse '%s' as a hexadecimal number, but the "+
|
||||||
|
"lexer claims it's OK: %s", s, err)
|
||||||
|
}
|
||||||
|
if !utf8.ValidRune(rune(hex)) {
|
||||||
|
p.panicf("Escaped character '\\u%s' is not valid UTF-8.", s)
|
||||||
|
}
|
||||||
|
return rune(hex)
|
||||||
|
}
|
||||||
|
|
||||||
|
func isStringType(ty itemType) bool {
|
||||||
|
return ty == itemString || ty == itemMultilineString ||
|
||||||
|
ty == itemRawString || ty == itemRawMultilineString
|
||||||
|
}
|
1
vendor/github.com/BurntSushi/toml/session.vim
generated
vendored
Normal file
1
vendor/github.com/BurntSushi/toml/session.vim
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
au BufWritePost *.go silent!make tags > /dev/null 2>&1
|
91
vendor/github.com/BurntSushi/toml/type_check.go
generated
vendored
Normal file
91
vendor/github.com/BurntSushi/toml/type_check.go
generated
vendored
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
package toml
|
||||||
|
|
||||||
|
// tomlType represents any Go type that corresponds to a TOML type.
|
||||||
|
// While the first draft of the TOML spec has a simplistic type system that
|
||||||
|
// probably doesn't need this level of sophistication, we seem to be militating
|
||||||
|
// toward adding real composite types.
|
||||||
|
type tomlType interface {
|
||||||
|
typeString() string
|
||||||
|
}
|
||||||
|
|
||||||
|
// typeEqual accepts any two types and returns true if they are equal.
|
||||||
|
func typeEqual(t1, t2 tomlType) bool {
|
||||||
|
if t1 == nil || t2 == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return t1.typeString() == t2.typeString()
|
||||||
|
}
|
||||||
|
|
||||||
|
func typeIsHash(t tomlType) bool {
|
||||||
|
return typeEqual(t, tomlHash) || typeEqual(t, tomlArrayHash)
|
||||||
|
}
|
||||||
|
|
||||||
|
type tomlBaseType string
|
||||||
|
|
||||||
|
func (btype tomlBaseType) typeString() string {
|
||||||
|
return string(btype)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (btype tomlBaseType) String() string {
|
||||||
|
return btype.typeString()
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
tomlInteger tomlBaseType = "Integer"
|
||||||
|
tomlFloat tomlBaseType = "Float"
|
||||||
|
tomlDatetime tomlBaseType = "Datetime"
|
||||||
|
tomlString tomlBaseType = "String"
|
||||||
|
tomlBool tomlBaseType = "Bool"
|
||||||
|
tomlArray tomlBaseType = "Array"
|
||||||
|
tomlHash tomlBaseType = "Hash"
|
||||||
|
tomlArrayHash tomlBaseType = "ArrayHash"
|
||||||
|
)
|
||||||
|
|
||||||
|
// typeOfPrimitive returns a tomlType of any primitive value in TOML.
|
||||||
|
// Primitive values are: Integer, Float, Datetime, String and Bool.
|
||||||
|
//
|
||||||
|
// Passing a lexer item other than the following will cause a BUG message
|
||||||
|
// to occur: itemString, itemBool, itemInteger, itemFloat, itemDatetime.
|
||||||
|
func (p *parser) typeOfPrimitive(lexItem item) tomlType {
|
||||||
|
switch lexItem.typ {
|
||||||
|
case itemInteger:
|
||||||
|
return tomlInteger
|
||||||
|
case itemFloat:
|
||||||
|
return tomlFloat
|
||||||
|
case itemDatetime:
|
||||||
|
return tomlDatetime
|
||||||
|
case itemString:
|
||||||
|
return tomlString
|
||||||
|
case itemMultilineString:
|
||||||
|
return tomlString
|
||||||
|
case itemRawString:
|
||||||
|
return tomlString
|
||||||
|
case itemRawMultilineString:
|
||||||
|
return tomlString
|
||||||
|
case itemBool:
|
||||||
|
return tomlBool
|
||||||
|
}
|
||||||
|
p.bug("Cannot infer primitive type of lex item '%s'.", lexItem)
|
||||||
|
panic("unreachable")
|
||||||
|
}
|
||||||
|
|
||||||
|
// typeOfArray returns a tomlType for an array given a list of types of its
|
||||||
|
// values.
|
||||||
|
//
|
||||||
|
// In the current spec, if an array is homogeneous, then its type is always
|
||||||
|
// "Array". If the array is not homogeneous, an error is generated.
|
||||||
|
func (p *parser) typeOfArray(types []tomlType) tomlType {
|
||||||
|
// Empty arrays are cool.
|
||||||
|
if len(types) == 0 {
|
||||||
|
return tomlArray
|
||||||
|
}
|
||||||
|
|
||||||
|
theType := types[0]
|
||||||
|
for _, t := range types[1:] {
|
||||||
|
if !typeEqual(theType, t) {
|
||||||
|
p.panicf("Array contains values of type '%s' and '%s', but "+
|
||||||
|
"arrays must be homogeneous.", theType, t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tomlArray
|
||||||
|
}
|
242
vendor/github.com/BurntSushi/toml/type_fields.go
generated
vendored
Normal file
242
vendor/github.com/BurntSushi/toml/type_fields.go
generated
vendored
Normal file
@ -0,0 +1,242 @@
|
|||||||
|
package toml
|
||||||
|
|
||||||
|
// Struct field handling is adapted from code in encoding/json:
|
||||||
|
//
|
||||||
|
// Copyright 2010 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the Go distribution.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"sort"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A field represents a single field found in a struct.
|
||||||
|
type field struct {
|
||||||
|
name string // the name of the field (`toml` tag included)
|
||||||
|
tag bool // whether field has a `toml` tag
|
||||||
|
index []int // represents the depth of an anonymous field
|
||||||
|
typ reflect.Type // the type of the field
|
||||||
|
}
|
||||||
|
|
||||||
|
// byName sorts field by name, breaking ties with depth,
|
||||||
|
// then breaking ties with "name came from toml tag", then
|
||||||
|
// breaking ties with index sequence.
|
||||||
|
type byName []field
|
||||||
|
|
||||||
|
func (x byName) Len() int { return len(x) }
|
||||||
|
|
||||||
|
func (x byName) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
|
||||||
|
|
||||||
|
func (x byName) Less(i, j int) bool {
|
||||||
|
if x[i].name != x[j].name {
|
||||||
|
return x[i].name < x[j].name
|
||||||
|
}
|
||||||
|
if len(x[i].index) != len(x[j].index) {
|
||||||
|
return len(x[i].index) < len(x[j].index)
|
||||||
|
}
|
||||||
|
if x[i].tag != x[j].tag {
|
||||||
|
return x[i].tag
|
||||||
|
}
|
||||||
|
return byIndex(x).Less(i, j)
|
||||||
|
}
|
||||||
|
|
||||||
|
// byIndex sorts field by index sequence.
|
||||||
|
type byIndex []field
|
||||||
|
|
||||||
|
func (x byIndex) Len() int { return len(x) }
|
||||||
|
|
||||||
|
func (x byIndex) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
|
||||||
|
|
||||||
|
func (x byIndex) Less(i, j int) bool {
|
||||||
|
for k, xik := range x[i].index {
|
||||||
|
if k >= len(x[j].index) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if xik != x[j].index[k] {
|
||||||
|
return xik < x[j].index[k]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return len(x[i].index) < len(x[j].index)
|
||||||
|
}
|
||||||
|
|
||||||
|
// typeFields returns a list of fields that TOML should recognize for the given
|
||||||
|
// type. The algorithm is breadth-first search over the set of structs to
|
||||||
|
// include - the top struct and then any reachable anonymous structs.
|
||||||
|
func typeFields(t reflect.Type) []field {
|
||||||
|
// Anonymous fields to explore at the current level and the next.
|
||||||
|
current := []field{}
|
||||||
|
next := []field{{typ: t}}
|
||||||
|
|
||||||
|
// Count of queued names for current level and the next.
|
||||||
|
count := map[reflect.Type]int{}
|
||||||
|
nextCount := map[reflect.Type]int{}
|
||||||
|
|
||||||
|
// Types already visited at an earlier level.
|
||||||
|
visited := map[reflect.Type]bool{}
|
||||||
|
|
||||||
|
// Fields found.
|
||||||
|
var fields []field
|
||||||
|
|
||||||
|
for len(next) > 0 {
|
||||||
|
current, next = next, current[:0]
|
||||||
|
count, nextCount = nextCount, map[reflect.Type]int{}
|
||||||
|
|
||||||
|
for _, f := range current {
|
||||||
|
if visited[f.typ] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
visited[f.typ] = true
|
||||||
|
|
||||||
|
// Scan f.typ for fields to include.
|
||||||
|
for i := 0; i < f.typ.NumField(); i++ {
|
||||||
|
sf := f.typ.Field(i)
|
||||||
|
if sf.PkgPath != "" && !sf.Anonymous { // unexported
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
opts := getOptions(sf.Tag)
|
||||||
|
if opts.skip {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
index := make([]int, len(f.index)+1)
|
||||||
|
copy(index, f.index)
|
||||||
|
index[len(f.index)] = i
|
||||||
|
|
||||||
|
ft := sf.Type
|
||||||
|
if ft.Name() == "" && ft.Kind() == reflect.Ptr {
|
||||||
|
// Follow pointer.
|
||||||
|
ft = ft.Elem()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Record found field and index sequence.
|
||||||
|
if opts.name != "" || !sf.Anonymous || ft.Kind() != reflect.Struct {
|
||||||
|
tagged := opts.name != ""
|
||||||
|
name := opts.name
|
||||||
|
if name == "" {
|
||||||
|
name = sf.Name
|
||||||
|
}
|
||||||
|
fields = append(fields, field{name, tagged, index, ft})
|
||||||
|
if count[f.typ] > 1 {
|
||||||
|
// If there were multiple instances, add a second,
|
||||||
|
// so that the annihilation code will see a duplicate.
|
||||||
|
// It only cares about the distinction between 1 or 2,
|
||||||
|
// so don't bother generating any more copies.
|
||||||
|
fields = append(fields, fields[len(fields)-1])
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Record new anonymous struct to explore in next round.
|
||||||
|
nextCount[ft]++
|
||||||
|
if nextCount[ft] == 1 {
|
||||||
|
f := field{name: ft.Name(), index: index, typ: ft}
|
||||||
|
next = append(next, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Sort(byName(fields))
|
||||||
|
|
||||||
|
// Delete all fields that are hidden by the Go rules for embedded fields,
|
||||||
|
// except that fields with TOML tags are promoted.
|
||||||
|
|
||||||
|
// The fields are sorted in primary order of name, secondary order
|
||||||
|
// of field index length. Loop over names; for each name, delete
|
||||||
|
// hidden fields by choosing the one dominant field that survives.
|
||||||
|
out := fields[:0]
|
||||||
|
for advance, i := 0, 0; i < len(fields); i += advance {
|
||||||
|
// One iteration per name.
|
||||||
|
// Find the sequence of fields with the name of this first field.
|
||||||
|
fi := fields[i]
|
||||||
|
name := fi.name
|
||||||
|
for advance = 1; i+advance < len(fields); advance++ {
|
||||||
|
fj := fields[i+advance]
|
||||||
|
if fj.name != name {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if advance == 1 { // Only one field with this name
|
||||||
|
out = append(out, fi)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
dominant, ok := dominantField(fields[i : i+advance])
|
||||||
|
if ok {
|
||||||
|
out = append(out, dominant)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fields = out
|
||||||
|
sort.Sort(byIndex(fields))
|
||||||
|
|
||||||
|
return fields
|
||||||
|
}
|
||||||
|
|
||||||
|
// dominantField looks through the fields, all of which are known to
|
||||||
|
// have the same name, to find the single field that dominates the
|
||||||
|
// others using Go's embedding rules, modified by the presence of
|
||||||
|
// TOML tags. If there are multiple top-level fields, the boolean
|
||||||
|
// will be false: This condition is an error in Go and we skip all
|
||||||
|
// the fields.
|
||||||
|
func dominantField(fields []field) (field, bool) {
|
||||||
|
// The fields are sorted in increasing index-length order. The winner
|
||||||
|
// must therefore be one with the shortest index length. Drop all
|
||||||
|
// longer entries, which is easy: just truncate the slice.
|
||||||
|
length := len(fields[0].index)
|
||||||
|
tagged := -1 // Index of first tagged field.
|
||||||
|
for i, f := range fields {
|
||||||
|
if len(f.index) > length {
|
||||||
|
fields = fields[:i]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if f.tag {
|
||||||
|
if tagged >= 0 {
|
||||||
|
// Multiple tagged fields at the same level: conflict.
|
||||||
|
// Return no field.
|
||||||
|
return field{}, false
|
||||||
|
}
|
||||||
|
tagged = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if tagged >= 0 {
|
||||||
|
return fields[tagged], true
|
||||||
|
}
|
||||||
|
// All remaining fields have the same length. If there's more than one,
|
||||||
|
// we have a conflict (two fields named "X" at the same level) and we
|
||||||
|
// return no field.
|
||||||
|
if len(fields) > 1 {
|
||||||
|
return field{}, false
|
||||||
|
}
|
||||||
|
return fields[0], true
|
||||||
|
}
|
||||||
|
|
||||||
|
var fieldCache struct {
|
||||||
|
sync.RWMutex
|
||||||
|
m map[reflect.Type][]field
|
||||||
|
}
|
||||||
|
|
||||||
|
// cachedTypeFields is like typeFields but uses a cache to avoid repeated work.
|
||||||
|
func cachedTypeFields(t reflect.Type) []field {
|
||||||
|
fieldCache.RLock()
|
||||||
|
f := fieldCache.m[t]
|
||||||
|
fieldCache.RUnlock()
|
||||||
|
if f != nil {
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute fields without lock.
|
||||||
|
// Might duplicate effort but won't hold other computations back.
|
||||||
|
f = typeFields(t)
|
||||||
|
if f == nil {
|
||||||
|
f = []field{}
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldCache.Lock()
|
||||||
|
if fieldCache.m == nil {
|
||||||
|
fieldCache.m = map[reflect.Type][]field{}
|
||||||
|
}
|
||||||
|
fieldCache.m[t] = f
|
||||||
|
fieldCache.Unlock()
|
||||||
|
return f
|
||||||
|
}
|
14
vendor/github.com/JeffAshton/win_pdh/AUTHORS
generated
vendored
Normal file
14
vendor/github.com/JeffAshton/win_pdh/AUTHORS
generated
vendored
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
# This is the official list of 'win_pdh' authors for copyright purposes.
|
||||||
|
|
||||||
|
# Names should be added to this file as
|
||||||
|
# Name or Organization <email address>
|
||||||
|
# The email address is not required for organizations.
|
||||||
|
|
||||||
|
# Please keep the list sorted.
|
||||||
|
|
||||||
|
# Contributors
|
||||||
|
# ============
|
||||||
|
|
||||||
|
Alexander Neumann <an2048@googlemail.com>
|
||||||
|
Joseph Watson <jtwatson@linux-consulting.us>
|
||||||
|
Kevin Pors <krpors@gmail.com>
|
23
vendor/github.com/JeffAshton/win_pdh/LICENSE
generated
vendored
Normal file
23
vendor/github.com/JeffAshton/win_pdh/LICENSE
generated
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
Copyright (c) 2010 The win_pdh Authors. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The names of the authors may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
15
vendor/github.com/JeffAshton/win_pdh/README.mdown
generated
vendored
Normal file
15
vendor/github.com/JeffAshton/win_pdh/README.mdown
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
About win_pdh
|
||||||
|
=============
|
||||||
|
|
||||||
|
win_pdh is a Windows Performance Data Helper wrapper package for Go.
|
||||||
|
|
||||||
|
Originally part of [walk](https://github.com/lxn/walk) and [win](https://github.com/lxn/win), it is now a separate
|
||||||
|
project.
|
||||||
|
|
||||||
|
Setup
|
||||||
|
=====
|
||||||
|
|
||||||
|
Make sure you have a working Go installation.
|
||||||
|
See [Getting Started](http://golang.org/doc/install.html)
|
||||||
|
|
||||||
|
Now run `go get github.com/JeffAshton/win_pdh`
|
453
vendor/github.com/JeffAshton/win_pdh/pdh.go
generated
vendored
Normal file
453
vendor/github.com/JeffAshton/win_pdh/pdh.go
generated
vendored
Normal file
@ -0,0 +1,453 @@
|
|||||||
|
// Copyright 2013 The win_pdh Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build windows
|
||||||
|
|
||||||
|
package win_pdh
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Error codes
|
||||||
|
const (
|
||||||
|
ERROR_SUCCESS = 0
|
||||||
|
ERROR_INVALID_FUNCTION = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
HANDLE uintptr
|
||||||
|
)
|
||||||
|
|
||||||
|
// PDH error codes, which can be returned by all Pdh* functions. Taken from mingw-w64 pdhmsg.h
|
||||||
|
const (
|
||||||
|
PDH_CSTATUS_VALID_DATA = 0x00000000 // The returned data is valid.
|
||||||
|
PDH_CSTATUS_NEW_DATA = 0x00000001 // The return data value is valid and different from the last sample.
|
||||||
|
PDH_CSTATUS_NO_MACHINE = 0x800007D0 // Unable to connect to the specified computer, or the computer is offline.
|
||||||
|
PDH_CSTATUS_NO_INSTANCE = 0x800007D1
|
||||||
|
PDH_MORE_DATA = 0x800007D2 // The PdhGetFormattedCounterArray* function can return this if there's 'more data to be displayed'.
|
||||||
|
PDH_CSTATUS_ITEM_NOT_VALIDATED = 0x800007D3
|
||||||
|
PDH_RETRY = 0x800007D4
|
||||||
|
PDH_NO_DATA = 0x800007D5 // The query does not currently contain any counters (for example, limited access)
|
||||||
|
PDH_CALC_NEGATIVE_DENOMINATOR = 0x800007D6
|
||||||
|
PDH_CALC_NEGATIVE_TIMEBASE = 0x800007D7
|
||||||
|
PDH_CALC_NEGATIVE_VALUE = 0x800007D8
|
||||||
|
PDH_DIALOG_CANCELLED = 0x800007D9
|
||||||
|
PDH_END_OF_LOG_FILE = 0x800007DA
|
||||||
|
PDH_ASYNC_QUERY_TIMEOUT = 0x800007DB
|
||||||
|
PDH_CANNOT_SET_DEFAULT_REALTIME_DATASOURCE = 0x800007DC
|
||||||
|
PDH_CSTATUS_NO_OBJECT = 0xC0000BB8
|
||||||
|
PDH_CSTATUS_NO_COUNTER = 0xC0000BB9 // The specified counter could not be found.
|
||||||
|
PDH_CSTATUS_INVALID_DATA = 0xC0000BBA // The counter was successfully found, but the data returned is not valid.
|
||||||
|
PDH_MEMORY_ALLOCATION_FAILURE = 0xC0000BBB
|
||||||
|
PDH_INVALID_HANDLE = 0xC0000BBC
|
||||||
|
PDH_INVALID_ARGUMENT = 0xC0000BBD // Required argument is missing or incorrect.
|
||||||
|
PDH_FUNCTION_NOT_FOUND = 0xC0000BBE
|
||||||
|
PDH_CSTATUS_NO_COUNTERNAME = 0xC0000BBF
|
||||||
|
PDH_CSTATUS_BAD_COUNTERNAME = 0xC0000BC0 // Unable to parse the counter path. Check the format and syntax of the specified path.
|
||||||
|
PDH_INVALID_BUFFER = 0xC0000BC1
|
||||||
|
PDH_INSUFFICIENT_BUFFER = 0xC0000BC2
|
||||||
|
PDH_CANNOT_CONNECT_MACHINE = 0xC0000BC3
|
||||||
|
PDH_INVALID_PATH = 0xC0000BC4
|
||||||
|
PDH_INVALID_INSTANCE = 0xC0000BC5
|
||||||
|
PDH_INVALID_DATA = 0xC0000BC6 // specified counter does not contain valid data or a successful status code.
|
||||||
|
PDH_NO_DIALOG_DATA = 0xC0000BC7
|
||||||
|
PDH_CANNOT_READ_NAME_STRINGS = 0xC0000BC8
|
||||||
|
PDH_LOG_FILE_CREATE_ERROR = 0xC0000BC9
|
||||||
|
PDH_LOG_FILE_OPEN_ERROR = 0xC0000BCA
|
||||||
|
PDH_LOG_TYPE_NOT_FOUND = 0xC0000BCB
|
||||||
|
PDH_NO_MORE_DATA = 0xC0000BCC
|
||||||
|
PDH_ENTRY_NOT_IN_LOG_FILE = 0xC0000BCD
|
||||||
|
PDH_DATA_SOURCE_IS_LOG_FILE = 0xC0000BCE
|
||||||
|
PDH_DATA_SOURCE_IS_REAL_TIME = 0xC0000BCF
|
||||||
|
PDH_UNABLE_READ_LOG_HEADER = 0xC0000BD0
|
||||||
|
PDH_FILE_NOT_FOUND = 0xC0000BD1
|
||||||
|
PDH_FILE_ALREADY_EXISTS = 0xC0000BD2
|
||||||
|
PDH_NOT_IMPLEMENTED = 0xC0000BD3
|
||||||
|
PDH_STRING_NOT_FOUND = 0xC0000BD4
|
||||||
|
PDH_UNABLE_MAP_NAME_FILES = 0x80000BD5
|
||||||
|
PDH_UNKNOWN_LOG_FORMAT = 0xC0000BD6
|
||||||
|
PDH_UNKNOWN_LOGSVC_COMMAND = 0xC0000BD7
|
||||||
|
PDH_LOGSVC_QUERY_NOT_FOUND = 0xC0000BD8
|
||||||
|
PDH_LOGSVC_NOT_OPENED = 0xC0000BD9
|
||||||
|
PDH_WBEM_ERROR = 0xC0000BDA
|
||||||
|
PDH_ACCESS_DENIED = 0xC0000BDB
|
||||||
|
PDH_LOG_FILE_TOO_SMALL = 0xC0000BDC
|
||||||
|
PDH_INVALID_DATASOURCE = 0xC0000BDD
|
||||||
|
PDH_INVALID_SQLDB = 0xC0000BDE
|
||||||
|
PDH_NO_COUNTERS = 0xC0000BDF
|
||||||
|
PDH_SQL_ALLOC_FAILED = 0xC0000BE0
|
||||||
|
PDH_SQL_ALLOCCON_FAILED = 0xC0000BE1
|
||||||
|
PDH_SQL_EXEC_DIRECT_FAILED = 0xC0000BE2
|
||||||
|
PDH_SQL_FETCH_FAILED = 0xC0000BE3
|
||||||
|
PDH_SQL_ROWCOUNT_FAILED = 0xC0000BE4
|
||||||
|
PDH_SQL_MORE_RESULTS_FAILED = 0xC0000BE5
|
||||||
|
PDH_SQL_CONNECT_FAILED = 0xC0000BE6
|
||||||
|
PDH_SQL_BIND_FAILED = 0xC0000BE7
|
||||||
|
PDH_CANNOT_CONNECT_WMI_SERVER = 0xC0000BE8
|
||||||
|
PDH_PLA_COLLECTION_ALREADY_RUNNING = 0xC0000BE9
|
||||||
|
PDH_PLA_ERROR_SCHEDULE_OVERLAP = 0xC0000BEA
|
||||||
|
PDH_PLA_COLLECTION_NOT_FOUND = 0xC0000BEB
|
||||||
|
PDH_PLA_ERROR_SCHEDULE_ELAPSED = 0xC0000BEC
|
||||||
|
PDH_PLA_ERROR_NOSTART = 0xC0000BED
|
||||||
|
PDH_PLA_ERROR_ALREADY_EXISTS = 0xC0000BEE
|
||||||
|
PDH_PLA_ERROR_TYPE_MISMATCH = 0xC0000BEF
|
||||||
|
PDH_PLA_ERROR_FILEPATH = 0xC0000BF0
|
||||||
|
PDH_PLA_SERVICE_ERROR = 0xC0000BF1
|
||||||
|
PDH_PLA_VALIDATION_ERROR = 0xC0000BF2
|
||||||
|
PDH_PLA_VALIDATION_WARNING = 0x80000BF3
|
||||||
|
PDH_PLA_ERROR_NAME_TOO_LONG = 0xC0000BF4
|
||||||
|
PDH_INVALID_SQL_LOG_FORMAT = 0xC0000BF5
|
||||||
|
PDH_COUNTER_ALREADY_IN_QUERY = 0xC0000BF6
|
||||||
|
PDH_BINARY_LOG_CORRUPT = 0xC0000BF7
|
||||||
|
PDH_LOG_SAMPLE_TOO_SMALL = 0xC0000BF8
|
||||||
|
PDH_OS_LATER_VERSION = 0xC0000BF9
|
||||||
|
PDH_OS_EARLIER_VERSION = 0xC0000BFA
|
||||||
|
PDH_INCORRECT_APPEND_TIME = 0xC0000BFB
|
||||||
|
PDH_UNMATCHED_APPEND_COUNTER = 0xC0000BFC
|
||||||
|
PDH_SQL_ALTER_DETAIL_FAILED = 0xC0000BFD
|
||||||
|
PDH_QUERY_PERF_DATA_TIMEOUT = 0xC0000BFE
|
||||||
|
)
|
||||||
|
|
||||||
|
// Formatting options for GetFormattedCounterValue().
|
||||||
|
const (
|
||||||
|
PDH_FMT_RAW = 0x00000010
|
||||||
|
PDH_FMT_ANSI = 0x00000020
|
||||||
|
PDH_FMT_UNICODE = 0x00000040
|
||||||
|
PDH_FMT_LONG = 0x00000100 // Return data as a long int.
|
||||||
|
PDH_FMT_DOUBLE = 0x00000200 // Return data as a double precision floating point real.
|
||||||
|
PDH_FMT_LARGE = 0x00000400 // Return data as a 64 bit integer.
|
||||||
|
PDH_FMT_NOSCALE = 0x00001000 // can be OR-ed: Do not apply the counter's default scaling factor.
|
||||||
|
PDH_FMT_1000 = 0x00002000 // can be OR-ed: multiply the actual value by 1,000.
|
||||||
|
PDH_FMT_NODATA = 0x00004000 // can be OR-ed: unknown what this is for, MSDN says nothing.
|
||||||
|
PDH_FMT_NOCAP100 = 0x00008000 // can be OR-ed: do not cap values > 100.
|
||||||
|
PERF_DETAIL_COSTLY = 0x00010000
|
||||||
|
PERF_DETAIL_STANDARD = 0x0000FFFF
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
PDH_HQUERY HANDLE // query handle
|
||||||
|
PDH_HCOUNTER HANDLE // counter handle
|
||||||
|
)
|
||||||
|
|
||||||
|
// Union specialization for double values
|
||||||
|
type PDH_FMT_COUNTERVALUE_DOUBLE struct {
|
||||||
|
CStatus uint32
|
||||||
|
DoubleValue float64
|
||||||
|
}
|
||||||
|
|
||||||
|
// Union specialization for 64 bit integer values
|
||||||
|
type PDH_FMT_COUNTERVALUE_LARGE struct {
|
||||||
|
CStatus uint32
|
||||||
|
LargeValue int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// Union specialization for long values
|
||||||
|
type PDH_FMT_COUNTERVALUE_LONG struct {
|
||||||
|
CStatus uint32
|
||||||
|
LongValue int32
|
||||||
|
padding [4]byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// Union specialization for double values, used by PdhGetFormattedCounterArrayDouble()
|
||||||
|
type PDH_FMT_COUNTERVALUE_ITEM_DOUBLE struct {
|
||||||
|
SzName *uint16 // pointer to a string
|
||||||
|
FmtValue PDH_FMT_COUNTERVALUE_DOUBLE
|
||||||
|
}
|
||||||
|
|
||||||
|
// Union specialization for 'large' values, used by PdhGetFormattedCounterArrayLarge()
|
||||||
|
type PDH_FMT_COUNTERVALUE_ITEM_LARGE struct {
|
||||||
|
SzName *uint16 // pointer to a string
|
||||||
|
FmtValue PDH_FMT_COUNTERVALUE_LARGE
|
||||||
|
}
|
||||||
|
|
||||||
|
// Union specialization for long values, used by PdhGetFormattedCounterArrayLong()
|
||||||
|
type PDH_FMT_COUNTERVALUE_ITEM_LONG struct {
|
||||||
|
SzName *uint16 // pointer to a string
|
||||||
|
FmtValue PDH_FMT_COUNTERVALUE_LONG
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
// Library
|
||||||
|
libpdhDll *syscall.DLL
|
||||||
|
|
||||||
|
// Functions
|
||||||
|
pdh_AddCounterW *syscall.Proc
|
||||||
|
pdh_AddEnglishCounterW *syscall.Proc
|
||||||
|
pdh_CloseQuery *syscall.Proc
|
||||||
|
pdh_CollectQueryData *syscall.Proc
|
||||||
|
pdh_GetFormattedCounterValue *syscall.Proc
|
||||||
|
pdh_GetFormattedCounterArrayW *syscall.Proc
|
||||||
|
pdh_OpenQuery *syscall.Proc
|
||||||
|
pdh_ValidatePathW *syscall.Proc
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// Library
|
||||||
|
libpdhDll = syscall.MustLoadDLL("pdh.dll")
|
||||||
|
|
||||||
|
// Functions
|
||||||
|
pdh_AddCounterW = libpdhDll.MustFindProc("PdhAddCounterW")
|
||||||
|
pdh_AddEnglishCounterW, _ = libpdhDll.FindProc("PdhAddEnglishCounterW") // XXX: only supported on versions > Vista.
|
||||||
|
pdh_CloseQuery = libpdhDll.MustFindProc("PdhCloseQuery")
|
||||||
|
pdh_CollectQueryData = libpdhDll.MustFindProc("PdhCollectQueryData")
|
||||||
|
pdh_GetFormattedCounterValue = libpdhDll.MustFindProc("PdhGetFormattedCounterValue")
|
||||||
|
pdh_GetFormattedCounterArrayW = libpdhDll.MustFindProc("PdhGetFormattedCounterArrayW")
|
||||||
|
pdh_OpenQuery = libpdhDll.MustFindProc("PdhOpenQuery")
|
||||||
|
pdh_ValidatePathW = libpdhDll.MustFindProc("PdhValidatePathW")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adds the specified counter to the query. This is the internationalized version. Preferably, use the
|
||||||
|
// function PdhAddEnglishCounter instead. hQuery is the query handle, which has been fetched by PdhOpenQuery.
|
||||||
|
// szFullCounterPath is a full, internationalized counter path (this will differ per Windows language version).
|
||||||
|
// dwUserData is a 'user-defined value', which becomes part of the counter information. To retrieve this value
|
||||||
|
// later, call PdhGetCounterInfo() and access dwQueryUserData of the PDH_COUNTER_INFO structure.
|
||||||
|
//
|
||||||
|
// Examples of szFullCounterPath (in an English version of Windows):
|
||||||
|
//
|
||||||
|
// \\Processor(_Total)\\% Idle Time
|
||||||
|
// \\Processor(_Total)\\% Processor Time
|
||||||
|
// \\LogicalDisk(C:)\% Free Space
|
||||||
|
//
|
||||||
|
// To view all (internationalized...) counters on a system, there are three non-programmatic ways: perfmon utility,
|
||||||
|
// the typeperf command, and the the registry editor. perfmon.exe is perhaps the easiest way, because it's basically a
|
||||||
|
// full implemention of the pdh.dll API, except with a GUI and all that. The registry setting also provides an
|
||||||
|
// interface to the available counters, and can be found at the following key:
|
||||||
|
//
|
||||||
|
// HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\CurrentLanguage
|
||||||
|
//
|
||||||
|
// This registry key contains several values as follows:
|
||||||
|
//
|
||||||
|
// 1
|
||||||
|
// 1847
|
||||||
|
// 2
|
||||||
|
// System
|
||||||
|
// 4
|
||||||
|
// Memory
|
||||||
|
// 6
|
||||||
|
// % Processor Time
|
||||||
|
// ... many, many more
|
||||||
|
//
|
||||||
|
// Somehow, these numeric values can be used as szFullCounterPath too:
|
||||||
|
//
|
||||||
|
// \2\6 will correspond to \\System\% Processor Time
|
||||||
|
//
|
||||||
|
// The typeperf command may also be pretty easy. To find all performance counters, simply execute:
|
||||||
|
//
|
||||||
|
// typeperf -qx
|
||||||
|
func PdhAddCounter(hQuery PDH_HQUERY, szFullCounterPath string, dwUserData uintptr, phCounter *PDH_HCOUNTER) uint32 {
|
||||||
|
ptxt, _ := syscall.UTF16PtrFromString(szFullCounterPath)
|
||||||
|
ret, _, _ := pdh_AddCounterW.Call(
|
||||||
|
uintptr(hQuery),
|
||||||
|
uintptr(unsafe.Pointer(ptxt)),
|
||||||
|
dwUserData,
|
||||||
|
uintptr(unsafe.Pointer(phCounter)))
|
||||||
|
|
||||||
|
return uint32(ret)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adds the specified language-neutral counter to the query. See the PdhAddCounter function. This function only exists on
|
||||||
|
// Windows versions higher than Vista.
|
||||||
|
func PdhAddEnglishCounter(hQuery PDH_HQUERY, szFullCounterPath string, dwUserData uintptr, phCounter *PDH_HCOUNTER) uint32 {
|
||||||
|
if pdh_AddEnglishCounterW == nil {
|
||||||
|
return ERROR_INVALID_FUNCTION
|
||||||
|
}
|
||||||
|
|
||||||
|
ptxt, _ := syscall.UTF16PtrFromString(szFullCounterPath)
|
||||||
|
ret, _, _ := pdh_AddEnglishCounterW.Call(
|
||||||
|
uintptr(hQuery),
|
||||||
|
uintptr(unsafe.Pointer(ptxt)),
|
||||||
|
dwUserData,
|
||||||
|
uintptr(unsafe.Pointer(phCounter)))
|
||||||
|
|
||||||
|
return uint32(ret)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Closes all counters contained in the specified query, closes all handles related to the query,
|
||||||
|
// and frees all memory associated with the query.
|
||||||
|
func PdhCloseQuery(hQuery PDH_HQUERY) uint32 {
|
||||||
|
ret, _, _ := pdh_CloseQuery.Call(uintptr(hQuery))
|
||||||
|
|
||||||
|
return uint32(ret)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collects the current raw data value for all counters in the specified query and updates the status
|
||||||
|
// code of each counter. With some counters, this function needs to be repeatedly called before the value
|
||||||
|
// of the counter can be extracted with PdhGetFormattedCounterValue(). For example, the following code
|
||||||
|
// requires at least two calls:
|
||||||
|
//
|
||||||
|
// var handle win.PDH_HQUERY
|
||||||
|
// var counterHandle win.PDH_HCOUNTER
|
||||||
|
// ret := win.PdhOpenQuery(0, 0, &handle)
|
||||||
|
// ret = win.PdhAddEnglishCounter(handle, "\\Processor(_Total)\\% Idle Time", 0, &counterHandle)
|
||||||
|
// var derp win.PDH_FMT_COUNTERVALUE_DOUBLE
|
||||||
|
//
|
||||||
|
// ret = win.PdhCollectQueryData(handle)
|
||||||
|
// fmt.Printf("Collect return code is %x\n", ret) // return code will be PDH_CSTATUS_INVALID_DATA
|
||||||
|
// ret = win.PdhGetFormattedCounterValueDouble(counterHandle, 0, &derp)
|
||||||
|
//
|
||||||
|
// ret = win.PdhCollectQueryData(handle)
|
||||||
|
// fmt.Printf("Collect return code is %x\n", ret) // return code will be ERROR_SUCCESS
|
||||||
|
// ret = win.PdhGetFormattedCounterValueDouble(counterHandle, 0, &derp)
|
||||||
|
//
|
||||||
|
// The PdhCollectQueryData will return an error in the first call because it needs two values for
|
||||||
|
// displaying the correct data for the processor idle time. The second call will have a 0 return code.
|
||||||
|
func PdhCollectQueryData(hQuery PDH_HQUERY) uint32 {
|
||||||
|
ret, _, _ := pdh_CollectQueryData.Call(uintptr(hQuery))
|
||||||
|
|
||||||
|
return uint32(ret)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Formats the given hCounter using a 'double'. The result is set into the specialized union struct pValue.
|
||||||
|
// This function does not directly translate to a Windows counterpart due to union specialization tricks.
|
||||||
|
func PdhGetFormattedCounterValueDouble(hCounter PDH_HCOUNTER, lpdwType *uint32, pValue *PDH_FMT_COUNTERVALUE_DOUBLE) uint32 {
|
||||||
|
ret, _, _ := pdh_GetFormattedCounterValue.Call(
|
||||||
|
uintptr(hCounter),
|
||||||
|
uintptr(PDH_FMT_DOUBLE),
|
||||||
|
uintptr(unsafe.Pointer(lpdwType)),
|
||||||
|
uintptr(unsafe.Pointer(pValue)))
|
||||||
|
|
||||||
|
return uint32(ret)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Formats the given hCounter using a large int (int64). The result is set into the specialized union struct pValue.
|
||||||
|
// This function does not directly translate to a Windows counterpart due to union specialization tricks.
|
||||||
|
func PdhGetFormattedCounterValueLarge(hCounter PDH_HCOUNTER, lpdwType *uint32, pValue *PDH_FMT_COUNTERVALUE_LARGE) uint32 {
|
||||||
|
ret, _, _ := pdh_GetFormattedCounterValue.Call(
|
||||||
|
uintptr(hCounter),
|
||||||
|
uintptr(PDH_FMT_LARGE),
|
||||||
|
uintptr(unsafe.Pointer(lpdwType)),
|
||||||
|
uintptr(unsafe.Pointer(pValue)))
|
||||||
|
|
||||||
|
return uint32(ret)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Formats the given hCounter using a 'long'. The result is set into the specialized union struct pValue.
|
||||||
|
// This function does not directly translate to a Windows counterpart due to union specialization tricks.
|
||||||
|
//
|
||||||
|
// BUG(krpors): Testing this function on multiple systems yielded inconsistent results. For instance,
|
||||||
|
// the pValue.LongValue kept the value '192' on test system A, but on B this was '0', while the padding
|
||||||
|
// bytes of the struct got the correct value. Until someone can figure out this behaviour, prefer to use
|
||||||
|
// the Double or Large counterparts instead. These functions provide actually the same data, except in
|
||||||
|
// a different, working format.
|
||||||
|
func PdhGetFormattedCounterValueLong(hCounter PDH_HCOUNTER, lpdwType *uint32, pValue *PDH_FMT_COUNTERVALUE_LONG) uint32 {
|
||||||
|
ret, _, _ := pdh_GetFormattedCounterValue.Call(
|
||||||
|
uintptr(hCounter),
|
||||||
|
uintptr(PDH_FMT_LONG),
|
||||||
|
uintptr(unsafe.Pointer(lpdwType)),
|
||||||
|
uintptr(unsafe.Pointer(pValue)))
|
||||||
|
|
||||||
|
return uint32(ret)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns an array of formatted counter values. Use this function when you want to format the counter values of a
|
||||||
|
// counter that contains a wildcard character for the instance name. The itemBuffer must a slice of type PDH_FMT_COUNTERVALUE_ITEM_DOUBLE.
|
||||||
|
// An example of how this function can be used:
|
||||||
|
//
|
||||||
|
// okPath := "\\Process(*)\\% Processor Time" // notice the wildcard * character
|
||||||
|
//
|
||||||
|
// // ommitted all necessary stuff ...
|
||||||
|
//
|
||||||
|
// var bufSize uint32
|
||||||
|
// var bufCount uint32
|
||||||
|
// var size uint32 = uint32(unsafe.Sizeof(win.PDH_FMT_COUNTERVALUE_ITEM_DOUBLE{}))
|
||||||
|
// var emptyBuf [1]win.PDH_FMT_COUNTERVALUE_ITEM_DOUBLE // need at least 1 addressable null ptr.
|
||||||
|
//
|
||||||
|
// for {
|
||||||
|
// // collect
|
||||||
|
// ret := win.PdhCollectQueryData(queryHandle)
|
||||||
|
// if ret == win.ERROR_SUCCESS {
|
||||||
|
// ret = win.PdhGetFormattedCounterArrayDouble(counterHandle, &bufSize, &bufCount, &emptyBuf[0]) // uses null ptr here according to MSDN.
|
||||||
|
// if ret == win.PDH_MORE_DATA {
|
||||||
|
// filledBuf := make([]win.PDH_FMT_COUNTERVALUE_ITEM_DOUBLE, bufCount*size)
|
||||||
|
// ret = win.PdhGetFormattedCounterArrayDouble(counterHandle, &bufSize, &bufCount, &filledBuf[0])
|
||||||
|
// for i := 0; i < int(bufCount); i++ {
|
||||||
|
// c := filledBuf[i]
|
||||||
|
// var s string = win.UTF16PtrToString(c.SzName)
|
||||||
|
// fmt.Printf("Index %d -> %s, value %v\n", i, s, c.FmtValue.DoubleValue)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// filledBuf = nil
|
||||||
|
// // Need to at least set bufSize to zero, because if not, the function will not
|
||||||
|
// // return PDH_MORE_DATA and will not set the bufSize.
|
||||||
|
// bufCount = 0
|
||||||
|
// bufSize = 0
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// time.Sleep(2000 * time.Millisecond)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
func PdhGetFormattedCounterArrayDouble(hCounter PDH_HCOUNTER, lpdwBufferSize *uint32, lpdwBufferCount *uint32, itemBuffer *PDH_FMT_COUNTERVALUE_ITEM_DOUBLE) uint32 {
|
||||||
|
ret, _, _ := pdh_GetFormattedCounterArrayW.Call(
|
||||||
|
uintptr(hCounter),
|
||||||
|
uintptr(PDH_FMT_DOUBLE),
|
||||||
|
uintptr(unsafe.Pointer(lpdwBufferSize)),
|
||||||
|
uintptr(unsafe.Pointer(lpdwBufferCount)),
|
||||||
|
uintptr(unsafe.Pointer(itemBuffer)))
|
||||||
|
|
||||||
|
return uint32(ret)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns an array of formatted counter values. Use this function when you want to format the counter values of a
|
||||||
|
// counter that contains a wildcard character for the instance name. The itemBuffer must a slice of type PDH_FMT_COUNTERVALUE_ITEM_LARGE.
|
||||||
|
// For an example usage, see PdhGetFormattedCounterArrayDouble.
|
||||||
|
func PdhGetFormattedCounterArrayLarge(hCounter PDH_HCOUNTER, lpdwBufferSize *uint32, lpdwBufferCount *uint32, itemBuffer *PDH_FMT_COUNTERVALUE_ITEM_LARGE) uint32 {
|
||||||
|
ret, _, _ := pdh_GetFormattedCounterArrayW.Call(
|
||||||
|
uintptr(hCounter),
|
||||||
|
uintptr(PDH_FMT_LARGE),
|
||||||
|
uintptr(unsafe.Pointer(lpdwBufferSize)),
|
||||||
|
uintptr(unsafe.Pointer(lpdwBufferCount)),
|
||||||
|
uintptr(unsafe.Pointer(itemBuffer)))
|
||||||
|
|
||||||
|
return uint32(ret)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns an array of formatted counter values. Use this function when you want to format the counter values of a
|
||||||
|
// counter that contains a wildcard character for the instance name. The itemBuffer must a slice of type PDH_FMT_COUNTERVALUE_ITEM_LONG.
|
||||||
|
// For an example usage, see PdhGetFormattedCounterArrayDouble.
|
||||||
|
//
|
||||||
|
// BUG(krpors): See description of PdhGetFormattedCounterValueLong().
|
||||||
|
func PdhGetFormattedCounterArrayLong(hCounter PDH_HCOUNTER, lpdwBufferSize *uint32, lpdwBufferCount *uint32, itemBuffer *PDH_FMT_COUNTERVALUE_ITEM_LONG) uint32 {
|
||||||
|
ret, _, _ := pdh_GetFormattedCounterArrayW.Call(
|
||||||
|
uintptr(hCounter),
|
||||||
|
uintptr(PDH_FMT_LONG),
|
||||||
|
uintptr(unsafe.Pointer(lpdwBufferSize)),
|
||||||
|
uintptr(unsafe.Pointer(lpdwBufferCount)),
|
||||||
|
uintptr(unsafe.Pointer(itemBuffer)))
|
||||||
|
|
||||||
|
return uint32(ret)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates a new query that is used to manage the collection of performance data.
|
||||||
|
// szDataSource is a null terminated string that specifies the name of the log file from which to
|
||||||
|
// retrieve the performance data. If 0, performance data is collected from a real-time data source.
|
||||||
|
// dwUserData is a user-defined value to associate with this query. To retrieve the user data later,
|
||||||
|
// call PdhGetCounterInfo and access dwQueryUserData of the PDH_COUNTER_INFO structure. phQuery is
|
||||||
|
// the handle to the query, and must be used in subsequent calls. This function returns a PDH_
|
||||||
|
// constant error code, or ERROR_SUCCESS if the call succeeded.
|
||||||
|
func PdhOpenQuery(szDataSource uintptr, dwUserData uintptr, phQuery *PDH_HQUERY) uint32 {
|
||||||
|
ret, _, _ := pdh_OpenQuery.Call(
|
||||||
|
szDataSource,
|
||||||
|
dwUserData,
|
||||||
|
uintptr(unsafe.Pointer(phQuery)))
|
||||||
|
|
||||||
|
return uint32(ret)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validates a path. Will return ERROR_SUCCESS when ok, or PDH_CSTATUS_BAD_COUNTERNAME when the path is
|
||||||
|
// erroneous.
|
||||||
|
func PdhValidatePath(path string) uint32 {
|
||||||
|
ptxt, _ := syscall.UTF16PtrFromString(path)
|
||||||
|
ret, _, _ := pdh_ValidatePathW.Call(uintptr(unsafe.Pointer(ptxt)))
|
||||||
|
|
||||||
|
return uint32(ret)
|
||||||
|
}
|
||||||
|
|
||||||
|
func UTF16PtrToString(s *uint16) string {
|
||||||
|
if s == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return syscall.UTF16ToString((*[1 << 29]uint16)(unsafe.Pointer(s))[0:])
|
||||||
|
}
|
21
vendor/github.com/MakeNowJust/heredoc/LICENSE
generated
vendored
Normal file
21
vendor/github.com/MakeNowJust/heredoc/LICENSE
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2014-2017 TSUYUSATO Kitsune
|
||||||
|
|
||||||
|
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.
|
53
vendor/github.com/MakeNowJust/heredoc/README.md
generated
vendored
Normal file
53
vendor/github.com/MakeNowJust/heredoc/README.md
generated
vendored
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
# heredoc [![CircleCI](https://circleci.com/gh/MakeNowJust/heredoc.svg?style=svg)](https://circleci.com/gh/MakeNowJust/heredoc) [![Go Walker](http://gowalker.org/api/v1/badge)](https://gowalker.org/github.com/MakeNowJust/heredoc)
|
||||||
|
|
||||||
|
## About
|
||||||
|
|
||||||
|
Package heredoc provides the here-document with keeping indent.
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
```console
|
||||||
|
$ go get github.com/MakeNowJust/heredoc
|
||||||
|
```
|
||||||
|
|
||||||
|
## Import
|
||||||
|
|
||||||
|
```go
|
||||||
|
// usual
|
||||||
|
import "github.com/MakeNowJust/heredoc"
|
||||||
|
// shortcuts
|
||||||
|
import . "github.com/MakeNowJust/heredoc/dot"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
. "github.com/MakeNowJust/heredoc/dot"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
fmt.Println(D(`
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipisicing elit,
|
||||||
|
sed do eiusmod tempor incididunt ut labore et dolore magna
|
||||||
|
aliqua. Ut enim ad minim veniam, ...
|
||||||
|
`))
|
||||||
|
// Output:
|
||||||
|
// Lorem ipsum dolor sit amet, consectetur adipisicing elit,
|
||||||
|
// sed do eiusmod tempor incididunt ut labore et dolore magna
|
||||||
|
// aliqua. Ut enim ad minim veniam, ...
|
||||||
|
//
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## API Document
|
||||||
|
|
||||||
|
- [Go Walker - github.com/MakeNowJust/heredoc](https://gowalker.org/github.com/MakeNowJust/heredoc)
|
||||||
|
- [Go Walker - github.com/MakeNowJust/heredoc/dot](https://gowalker.org/github.com/MakeNowJust/heredoc/dot)
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
This software is released under the MIT License, see LICENSE.
|
98
vendor/github.com/MakeNowJust/heredoc/heredoc.go
generated
vendored
Normal file
98
vendor/github.com/MakeNowJust/heredoc/heredoc.go
generated
vendored
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
// Copyright (c) 2014-2017 TSUYUSATO Kitsune
|
||||||
|
// This software is released under the MIT License.
|
||||||
|
// http://opensource.org/licenses/mit-license.php
|
||||||
|
|
||||||
|
// Package heredoc provides creation of here-documents from raw strings.
|
||||||
|
//
|
||||||
|
// Golang supports raw-string syntax.
|
||||||
|
// doc := `
|
||||||
|
// Foo
|
||||||
|
// Bar
|
||||||
|
// `
|
||||||
|
// But raw-string cannot recognize indentation. Thus such content is an indented string, equivalent to
|
||||||
|
// "\n\tFoo\n\tBar\n"
|
||||||
|
// I dont't want this!
|
||||||
|
//
|
||||||
|
// However this problem is solved by package heredoc.
|
||||||
|
// doc := heredoc.Doc(`
|
||||||
|
// Foo
|
||||||
|
// Bar
|
||||||
|
// `)
|
||||||
|
// Is equivalent to
|
||||||
|
// "Foo\nBar\n"
|
||||||
|
package heredoc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"unicode"
|
||||||
|
)
|
||||||
|
|
||||||
|
const maxInt = int(^uint(0) >> 1)
|
||||||
|
|
||||||
|
// Doc returns un-indented string as here-document.
|
||||||
|
func Doc(raw string) string {
|
||||||
|
skipFirstLine := false
|
||||||
|
if raw[0] == '\n' {
|
||||||
|
raw = raw[1:]
|
||||||
|
} else {
|
||||||
|
skipFirstLine = true
|
||||||
|
}
|
||||||
|
|
||||||
|
lines := strings.Split(raw, "\n")
|
||||||
|
|
||||||
|
minIndentSize := getMinIndent(lines, skipFirstLine)
|
||||||
|
lines = removeIndentation(lines, minIndentSize, skipFirstLine)
|
||||||
|
|
||||||
|
return strings.Join(lines, "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
// getMinIndent calculates the minimum indentation in lines, excluding empty lines.
|
||||||
|
func getMinIndent(lines []string, skipFirstLine bool) int {
|
||||||
|
minIndentSize := maxInt
|
||||||
|
|
||||||
|
for i, line := range lines {
|
||||||
|
if i == 0 && skipFirstLine {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
indentSize := 0
|
||||||
|
for _, r := range []rune(line) {
|
||||||
|
if unicode.IsSpace(r) {
|
||||||
|
indentSize += 1
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(line) == indentSize {
|
||||||
|
if i == len(lines)-1 && indentSize < minIndentSize {
|
||||||
|
lines[i] = ""
|
||||||
|
}
|
||||||
|
} else if indentSize < minIndentSize {
|
||||||
|
minIndentSize = indentSize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return minIndentSize
|
||||||
|
}
|
||||||
|
|
||||||
|
// removeIndentation removes n characters from the front of each line in lines.
|
||||||
|
// Skips first line if skipFirstLine is true, skips empty lines.
|
||||||
|
func removeIndentation(lines []string, n int, skipFirstLine bool) []string {
|
||||||
|
for i, line := range lines {
|
||||||
|
if i == 0 && skipFirstLine {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(lines[i]) >= n {
|
||||||
|
lines[i] = line[n:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return lines
|
||||||
|
}
|
||||||
|
|
||||||
|
// Docf returns unindented and formatted string as here-document.
|
||||||
|
// Formatting is done as for fmt.Printf().
|
||||||
|
func Docf(raw string, args ...interface{}) string {
|
||||||
|
return fmt.Sprintf(Doc(raw), args...)
|
||||||
|
}
|
1
vendor/github.com/Microsoft/go-winio/.gitignore
generated
vendored
Normal file
1
vendor/github.com/Microsoft/go-winio/.gitignore
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
*.exe
|
22
vendor/github.com/Microsoft/go-winio/LICENSE
generated
vendored
Normal file
22
vendor/github.com/Microsoft/go-winio/LICENSE
generated
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2015 Microsoft
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
22
vendor/github.com/Microsoft/go-winio/README.md
generated
vendored
Normal file
22
vendor/github.com/Microsoft/go-winio/README.md
generated
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
# go-winio
|
||||||
|
|
||||||
|
This repository contains utilities for efficiently performing Win32 IO operations in
|
||||||
|
Go. Currently, this is focused on accessing named pipes and other file handles, and
|
||||||
|
for using named pipes as a net transport.
|
||||||
|
|
||||||
|
This code relies on IO completion ports to avoid blocking IO on system threads, allowing Go
|
||||||
|
to reuse the thread to schedule another goroutine. This limits support to Windows Vista and
|
||||||
|
newer operating systems. This is similar to the implementation of network sockets in Go's net
|
||||||
|
package.
|
||||||
|
|
||||||
|
Please see the LICENSE file for licensing information.
|
||||||
|
|
||||||
|
This project has adopted the [Microsoft Open Source Code of
|
||||||
|
Conduct](https://opensource.microsoft.com/codeofconduct/). For more information
|
||||||
|
see the [Code of Conduct
|
||||||
|
FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact
|
||||||
|
[opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional
|
||||||
|
questions or comments.
|
||||||
|
|
||||||
|
Thanks to natefinch for the inspiration for this library. See https://github.com/natefinch/npipe
|
||||||
|
for another named pipe implementation.
|
280
vendor/github.com/Microsoft/go-winio/backup.go
generated
vendored
Normal file
280
vendor/github.com/Microsoft/go-winio/backup.go
generated
vendored
Normal file
@ -0,0 +1,280 @@
|
|||||||
|
// +build windows
|
||||||
|
|
||||||
|
package winio
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
"syscall"
|
||||||
|
"unicode/utf16"
|
||||||
|
)
|
||||||
|
|
||||||
|
//sys backupRead(h syscall.Handle, b []byte, bytesRead *uint32, abort bool, processSecurity bool, context *uintptr) (err error) = BackupRead
|
||||||
|
//sys backupWrite(h syscall.Handle, b []byte, bytesWritten *uint32, abort bool, processSecurity bool, context *uintptr) (err error) = BackupWrite
|
||||||
|
|
||||||
|
const (
|
||||||
|
BackupData = uint32(iota + 1)
|
||||||
|
BackupEaData
|
||||||
|
BackupSecurity
|
||||||
|
BackupAlternateData
|
||||||
|
BackupLink
|
||||||
|
BackupPropertyData
|
||||||
|
BackupObjectId
|
||||||
|
BackupReparseData
|
||||||
|
BackupSparseBlock
|
||||||
|
BackupTxfsData
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
StreamSparseAttributes = uint32(8)
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
WRITE_DAC = 0x40000
|
||||||
|
WRITE_OWNER = 0x80000
|
||||||
|
ACCESS_SYSTEM_SECURITY = 0x1000000
|
||||||
|
)
|
||||||
|
|
||||||
|
// BackupHeader represents a backup stream of a file.
|
||||||
|
type BackupHeader struct {
|
||||||
|
Id uint32 // The backup stream ID
|
||||||
|
Attributes uint32 // Stream attributes
|
||||||
|
Size int64 // The size of the stream in bytes
|
||||||
|
Name string // The name of the stream (for BackupAlternateData only).
|
||||||
|
Offset int64 // The offset of the stream in the file (for BackupSparseBlock only).
|
||||||
|
}
|
||||||
|
|
||||||
|
type win32StreamId struct {
|
||||||
|
StreamId uint32
|
||||||
|
Attributes uint32
|
||||||
|
Size uint64
|
||||||
|
NameSize uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
// BackupStreamReader reads from a stream produced by the BackupRead Win32 API and produces a series
|
||||||
|
// of BackupHeader values.
|
||||||
|
type BackupStreamReader struct {
|
||||||
|
r io.Reader
|
||||||
|
bytesLeft int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBackupStreamReader produces a BackupStreamReader from any io.Reader.
|
||||||
|
func NewBackupStreamReader(r io.Reader) *BackupStreamReader {
|
||||||
|
return &BackupStreamReader{r, 0}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next returns the next backup stream and prepares for calls to Read(). It skips the remainder of the current stream if
|
||||||
|
// it was not completely read.
|
||||||
|
func (r *BackupStreamReader) Next() (*BackupHeader, error) {
|
||||||
|
if r.bytesLeft > 0 {
|
||||||
|
if s, ok := r.r.(io.Seeker); ok {
|
||||||
|
// Make sure Seek on io.SeekCurrent sometimes succeeds
|
||||||
|
// before trying the actual seek.
|
||||||
|
if _, err := s.Seek(0, io.SeekCurrent); err == nil {
|
||||||
|
if _, err = s.Seek(r.bytesLeft, io.SeekCurrent); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
r.bytesLeft = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if _, err := io.Copy(ioutil.Discard, r); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var wsi win32StreamId
|
||||||
|
if err := binary.Read(r.r, binary.LittleEndian, &wsi); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
hdr := &BackupHeader{
|
||||||
|
Id: wsi.StreamId,
|
||||||
|
Attributes: wsi.Attributes,
|
||||||
|
Size: int64(wsi.Size),
|
||||||
|
}
|
||||||
|
if wsi.NameSize != 0 {
|
||||||
|
name := make([]uint16, int(wsi.NameSize/2))
|
||||||
|
if err := binary.Read(r.r, binary.LittleEndian, name); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
hdr.Name = syscall.UTF16ToString(name)
|
||||||
|
}
|
||||||
|
if wsi.StreamId == BackupSparseBlock {
|
||||||
|
if err := binary.Read(r.r, binary.LittleEndian, &hdr.Offset); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
hdr.Size -= 8
|
||||||
|
}
|
||||||
|
r.bytesLeft = hdr.Size
|
||||||
|
return hdr, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read reads from the current backup stream.
|
||||||
|
func (r *BackupStreamReader) Read(b []byte) (int, error) {
|
||||||
|
if r.bytesLeft == 0 {
|
||||||
|
return 0, io.EOF
|
||||||
|
}
|
||||||
|
if int64(len(b)) > r.bytesLeft {
|
||||||
|
b = b[:r.bytesLeft]
|
||||||
|
}
|
||||||
|
n, err := r.r.Read(b)
|
||||||
|
r.bytesLeft -= int64(n)
|
||||||
|
if err == io.EOF {
|
||||||
|
err = io.ErrUnexpectedEOF
|
||||||
|
} else if r.bytesLeft == 0 && err == nil {
|
||||||
|
err = io.EOF
|
||||||
|
}
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// BackupStreamWriter writes a stream compatible with the BackupWrite Win32 API.
|
||||||
|
type BackupStreamWriter struct {
|
||||||
|
w io.Writer
|
||||||
|
bytesLeft int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBackupStreamWriter produces a BackupStreamWriter on top of an io.Writer.
|
||||||
|
func NewBackupStreamWriter(w io.Writer) *BackupStreamWriter {
|
||||||
|
return &BackupStreamWriter{w, 0}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteHeader writes the next backup stream header and prepares for calls to Write().
|
||||||
|
func (w *BackupStreamWriter) WriteHeader(hdr *BackupHeader) error {
|
||||||
|
if w.bytesLeft != 0 {
|
||||||
|
return fmt.Errorf("missing %d bytes", w.bytesLeft)
|
||||||
|
}
|
||||||
|
name := utf16.Encode([]rune(hdr.Name))
|
||||||
|
wsi := win32StreamId{
|
||||||
|
StreamId: hdr.Id,
|
||||||
|
Attributes: hdr.Attributes,
|
||||||
|
Size: uint64(hdr.Size),
|
||||||
|
NameSize: uint32(len(name) * 2),
|
||||||
|
}
|
||||||
|
if hdr.Id == BackupSparseBlock {
|
||||||
|
// Include space for the int64 block offset
|
||||||
|
wsi.Size += 8
|
||||||
|
}
|
||||||
|
if err := binary.Write(w.w, binary.LittleEndian, &wsi); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(name) != 0 {
|
||||||
|
if err := binary.Write(w.w, binary.LittleEndian, name); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if hdr.Id == BackupSparseBlock {
|
||||||
|
if err := binary.Write(w.w, binary.LittleEndian, hdr.Offset); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
w.bytesLeft = hdr.Size
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write writes to the current backup stream.
|
||||||
|
func (w *BackupStreamWriter) Write(b []byte) (int, error) {
|
||||||
|
if w.bytesLeft < int64(len(b)) {
|
||||||
|
return 0, fmt.Errorf("too many bytes by %d", int64(len(b))-w.bytesLeft)
|
||||||
|
}
|
||||||
|
n, err := w.w.Write(b)
|
||||||
|
w.bytesLeft -= int64(n)
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// BackupFileReader provides an io.ReadCloser interface on top of the BackupRead Win32 API.
|
||||||
|
type BackupFileReader struct {
|
||||||
|
f *os.File
|
||||||
|
includeSecurity bool
|
||||||
|
ctx uintptr
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBackupFileReader returns a new BackupFileReader from a file handle. If includeSecurity is true,
|
||||||
|
// Read will attempt to read the security descriptor of the file.
|
||||||
|
func NewBackupFileReader(f *os.File, includeSecurity bool) *BackupFileReader {
|
||||||
|
r := &BackupFileReader{f, includeSecurity, 0}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read reads a backup stream from the file by calling the Win32 API BackupRead().
|
||||||
|
func (r *BackupFileReader) Read(b []byte) (int, error) {
|
||||||
|
var bytesRead uint32
|
||||||
|
err := backupRead(syscall.Handle(r.f.Fd()), b, &bytesRead, false, r.includeSecurity, &r.ctx)
|
||||||
|
if err != nil {
|
||||||
|
return 0, &os.PathError{"BackupRead", r.f.Name(), err}
|
||||||
|
}
|
||||||
|
runtime.KeepAlive(r.f)
|
||||||
|
if bytesRead == 0 {
|
||||||
|
return 0, io.EOF
|
||||||
|
}
|
||||||
|
return int(bytesRead), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close frees Win32 resources associated with the BackupFileReader. It does not close
|
||||||
|
// the underlying file.
|
||||||
|
func (r *BackupFileReader) Close() error {
|
||||||
|
if r.ctx != 0 {
|
||||||
|
backupRead(syscall.Handle(r.f.Fd()), nil, nil, true, false, &r.ctx)
|
||||||
|
runtime.KeepAlive(r.f)
|
||||||
|
r.ctx = 0
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// BackupFileWriter provides an io.WriteCloser interface on top of the BackupWrite Win32 API.
|
||||||
|
type BackupFileWriter struct {
|
||||||
|
f *os.File
|
||||||
|
includeSecurity bool
|
||||||
|
ctx uintptr
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBackupFileWriter returns a new BackupFileWriter from a file handle. If includeSecurity is true,
|
||||||
|
// Write() will attempt to restore the security descriptor from the stream.
|
||||||
|
func NewBackupFileWriter(f *os.File, includeSecurity bool) *BackupFileWriter {
|
||||||
|
w := &BackupFileWriter{f, includeSecurity, 0}
|
||||||
|
return w
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write restores a portion of the file using the provided backup stream.
|
||||||
|
func (w *BackupFileWriter) Write(b []byte) (int, error) {
|
||||||
|
var bytesWritten uint32
|
||||||
|
err := backupWrite(syscall.Handle(w.f.Fd()), b, &bytesWritten, false, w.includeSecurity, &w.ctx)
|
||||||
|
if err != nil {
|
||||||
|
return 0, &os.PathError{"BackupWrite", w.f.Name(), err}
|
||||||
|
}
|
||||||
|
runtime.KeepAlive(w.f)
|
||||||
|
if int(bytesWritten) != len(b) {
|
||||||
|
return int(bytesWritten), errors.New("not all bytes could be written")
|
||||||
|
}
|
||||||
|
return len(b), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close frees Win32 resources associated with the BackupFileWriter. It does not
|
||||||
|
// close the underlying file.
|
||||||
|
func (w *BackupFileWriter) Close() error {
|
||||||
|
if w.ctx != 0 {
|
||||||
|
backupWrite(syscall.Handle(w.f.Fd()), nil, nil, true, false, &w.ctx)
|
||||||
|
runtime.KeepAlive(w.f)
|
||||||
|
w.ctx = 0
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// OpenForBackup opens a file or directory, potentially skipping access checks if the backup
|
||||||
|
// or restore privileges have been acquired.
|
||||||
|
//
|
||||||
|
// If the file opened was a directory, it cannot be used with Readdir().
|
||||||
|
func OpenForBackup(path string, access uint32, share uint32, createmode uint32) (*os.File, error) {
|
||||||
|
winPath, err := syscall.UTF16FromString(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
h, err := syscall.CreateFile(&winPath[0], access, share, nil, createmode, syscall.FILE_FLAG_BACKUP_SEMANTICS|syscall.FILE_FLAG_OPEN_REPARSE_POINT, 0)
|
||||||
|
if err != nil {
|
||||||
|
err = &os.PathError{Op: "open", Path: path, Err: err}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return os.NewFile(uintptr(h), path), nil
|
||||||
|
}
|
137
vendor/github.com/Microsoft/go-winio/ea.go
generated
vendored
Normal file
137
vendor/github.com/Microsoft/go-winio/ea.go
generated
vendored
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
package winio
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type fileFullEaInformation struct {
|
||||||
|
NextEntryOffset uint32
|
||||||
|
Flags uint8
|
||||||
|
NameLength uint8
|
||||||
|
ValueLength uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
fileFullEaInformationSize = binary.Size(&fileFullEaInformation{})
|
||||||
|
|
||||||
|
errInvalidEaBuffer = errors.New("invalid extended attribute buffer")
|
||||||
|
errEaNameTooLarge = errors.New("extended attribute name too large")
|
||||||
|
errEaValueTooLarge = errors.New("extended attribute value too large")
|
||||||
|
)
|
||||||
|
|
||||||
|
// ExtendedAttribute represents a single Windows EA.
|
||||||
|
type ExtendedAttribute struct {
|
||||||
|
Name string
|
||||||
|
Value []byte
|
||||||
|
Flags uint8
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseEa(b []byte) (ea ExtendedAttribute, nb []byte, err error) {
|
||||||
|
var info fileFullEaInformation
|
||||||
|
err = binary.Read(bytes.NewReader(b), binary.LittleEndian, &info)
|
||||||
|
if err != nil {
|
||||||
|
err = errInvalidEaBuffer
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
nameOffset := fileFullEaInformationSize
|
||||||
|
nameLen := int(info.NameLength)
|
||||||
|
valueOffset := nameOffset + int(info.NameLength) + 1
|
||||||
|
valueLen := int(info.ValueLength)
|
||||||
|
nextOffset := int(info.NextEntryOffset)
|
||||||
|
if valueLen+valueOffset > len(b) || nextOffset < 0 || nextOffset > len(b) {
|
||||||
|
err = errInvalidEaBuffer
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ea.Name = string(b[nameOffset : nameOffset+nameLen])
|
||||||
|
ea.Value = b[valueOffset : valueOffset+valueLen]
|
||||||
|
ea.Flags = info.Flags
|
||||||
|
if info.NextEntryOffset != 0 {
|
||||||
|
nb = b[info.NextEntryOffset:]
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecodeExtendedAttributes decodes a list of EAs from a FILE_FULL_EA_INFORMATION
|
||||||
|
// buffer retrieved from BackupRead, ZwQueryEaFile, etc.
|
||||||
|
func DecodeExtendedAttributes(b []byte) (eas []ExtendedAttribute, err error) {
|
||||||
|
for len(b) != 0 {
|
||||||
|
ea, nb, err := parseEa(b)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
eas = append(eas, ea)
|
||||||
|
b = nb
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeEa(buf *bytes.Buffer, ea *ExtendedAttribute, last bool) error {
|
||||||
|
if int(uint8(len(ea.Name))) != len(ea.Name) {
|
||||||
|
return errEaNameTooLarge
|
||||||
|
}
|
||||||
|
if int(uint16(len(ea.Value))) != len(ea.Value) {
|
||||||
|
return errEaValueTooLarge
|
||||||
|
}
|
||||||
|
entrySize := uint32(fileFullEaInformationSize + len(ea.Name) + 1 + len(ea.Value))
|
||||||
|
withPadding := (entrySize + 3) &^ 3
|
||||||
|
nextOffset := uint32(0)
|
||||||
|
if !last {
|
||||||
|
nextOffset = withPadding
|
||||||
|
}
|
||||||
|
info := fileFullEaInformation{
|
||||||
|
NextEntryOffset: nextOffset,
|
||||||
|
Flags: ea.Flags,
|
||||||
|
NameLength: uint8(len(ea.Name)),
|
||||||
|
ValueLength: uint16(len(ea.Value)),
|
||||||
|
}
|
||||||
|
|
||||||
|
err := binary.Write(buf, binary.LittleEndian, &info)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = buf.Write([]byte(ea.Name))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = buf.WriteByte(0)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = buf.Write(ea.Value)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = buf.Write([]byte{0, 0, 0}[0 : withPadding-entrySize])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncodeExtendedAttributes encodes a list of EAs into a FILE_FULL_EA_INFORMATION
|
||||||
|
// buffer for use with BackupWrite, ZwSetEaFile, etc.
|
||||||
|
func EncodeExtendedAttributes(eas []ExtendedAttribute) ([]byte, error) {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
for i := range eas {
|
||||||
|
last := false
|
||||||
|
if i == len(eas)-1 {
|
||||||
|
last = true
|
||||||
|
}
|
||||||
|
|
||||||
|
err := writeEa(&buf, &eas[i], last)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return buf.Bytes(), nil
|
||||||
|
}
|
307
vendor/github.com/Microsoft/go-winio/file.go
generated
vendored
Normal file
307
vendor/github.com/Microsoft/go-winio/file.go
generated
vendored
Normal file
@ -0,0 +1,307 @@
|
|||||||
|
// +build windows
|
||||||
|
|
||||||
|
package winio
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"runtime"
|
||||||
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
//sys cancelIoEx(file syscall.Handle, o *syscall.Overlapped) (err error) = CancelIoEx
|
||||||
|
//sys createIoCompletionPort(file syscall.Handle, port syscall.Handle, key uintptr, threadCount uint32) (newport syscall.Handle, err error) = CreateIoCompletionPort
|
||||||
|
//sys getQueuedCompletionStatus(port syscall.Handle, bytes *uint32, key *uintptr, o **ioOperation, timeout uint32) (err error) = GetQueuedCompletionStatus
|
||||||
|
//sys setFileCompletionNotificationModes(h syscall.Handle, flags uint8) (err error) = SetFileCompletionNotificationModes
|
||||||
|
|
||||||
|
type atomicBool int32
|
||||||
|
|
||||||
|
func (b *atomicBool) isSet() bool { return atomic.LoadInt32((*int32)(b)) != 0 }
|
||||||
|
func (b *atomicBool) setFalse() { atomic.StoreInt32((*int32)(b), 0) }
|
||||||
|
func (b *atomicBool) setTrue() { atomic.StoreInt32((*int32)(b), 1) }
|
||||||
|
func (b *atomicBool) swap(new bool) bool {
|
||||||
|
var newInt int32
|
||||||
|
if new {
|
||||||
|
newInt = 1
|
||||||
|
}
|
||||||
|
return atomic.SwapInt32((*int32)(b), newInt) == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
cFILE_SKIP_COMPLETION_PORT_ON_SUCCESS = 1
|
||||||
|
cFILE_SKIP_SET_EVENT_ON_HANDLE = 2
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrFileClosed = errors.New("file has already been closed")
|
||||||
|
ErrTimeout = &timeoutError{}
|
||||||
|
)
|
||||||
|
|
||||||
|
type timeoutError struct{}
|
||||||
|
|
||||||
|
func (e *timeoutError) Error() string { return "i/o timeout" }
|
||||||
|
func (e *timeoutError) Timeout() bool { return true }
|
||||||
|
func (e *timeoutError) Temporary() bool { return true }
|
||||||
|
|
||||||
|
type timeoutChan chan struct{}
|
||||||
|
|
||||||
|
var ioInitOnce sync.Once
|
||||||
|
var ioCompletionPort syscall.Handle
|
||||||
|
|
||||||
|
// ioResult contains the result of an asynchronous IO operation
|
||||||
|
type ioResult struct {
|
||||||
|
bytes uint32
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
// ioOperation represents an outstanding asynchronous Win32 IO
|
||||||
|
type ioOperation struct {
|
||||||
|
o syscall.Overlapped
|
||||||
|
ch chan ioResult
|
||||||
|
}
|
||||||
|
|
||||||
|
func initIo() {
|
||||||
|
h, err := createIoCompletionPort(syscall.InvalidHandle, 0, 0, 0xffffffff)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
ioCompletionPort = h
|
||||||
|
go ioCompletionProcessor(h)
|
||||||
|
}
|
||||||
|
|
||||||
|
// win32File implements Reader, Writer, and Closer on a Win32 handle without blocking in a syscall.
|
||||||
|
// It takes ownership of this handle and will close it if it is garbage collected.
|
||||||
|
type win32File struct {
|
||||||
|
handle syscall.Handle
|
||||||
|
wg sync.WaitGroup
|
||||||
|
wgLock sync.RWMutex
|
||||||
|
closing atomicBool
|
||||||
|
readDeadline deadlineHandler
|
||||||
|
writeDeadline deadlineHandler
|
||||||
|
}
|
||||||
|
|
||||||
|
type deadlineHandler struct {
|
||||||
|
setLock sync.Mutex
|
||||||
|
channel timeoutChan
|
||||||
|
channelLock sync.RWMutex
|
||||||
|
timer *time.Timer
|
||||||
|
timedout atomicBool
|
||||||
|
}
|
||||||
|
|
||||||
|
// makeWin32File makes a new win32File from an existing file handle
|
||||||
|
func makeWin32File(h syscall.Handle) (*win32File, error) {
|
||||||
|
f := &win32File{handle: h}
|
||||||
|
ioInitOnce.Do(initIo)
|
||||||
|
_, err := createIoCompletionPort(h, ioCompletionPort, 0, 0xffffffff)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
err = setFileCompletionNotificationModes(h, cFILE_SKIP_COMPLETION_PORT_ON_SUCCESS|cFILE_SKIP_SET_EVENT_ON_HANDLE)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
f.readDeadline.channel = make(timeoutChan)
|
||||||
|
f.writeDeadline.channel = make(timeoutChan)
|
||||||
|
return f, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func MakeOpenFile(h syscall.Handle) (io.ReadWriteCloser, error) {
|
||||||
|
return makeWin32File(h)
|
||||||
|
}
|
||||||
|
|
||||||
|
// closeHandle closes the resources associated with a Win32 handle
|
||||||
|
func (f *win32File) closeHandle() {
|
||||||
|
f.wgLock.Lock()
|
||||||
|
// Atomically set that we are closing, releasing the resources only once.
|
||||||
|
if !f.closing.swap(true) {
|
||||||
|
f.wgLock.Unlock()
|
||||||
|
// cancel all IO and wait for it to complete
|
||||||
|
cancelIoEx(f.handle, nil)
|
||||||
|
f.wg.Wait()
|
||||||
|
// at this point, no new IO can start
|
||||||
|
syscall.Close(f.handle)
|
||||||
|
f.handle = 0
|
||||||
|
} else {
|
||||||
|
f.wgLock.Unlock()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close closes a win32File.
|
||||||
|
func (f *win32File) Close() error {
|
||||||
|
f.closeHandle()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// prepareIo prepares for a new IO operation.
|
||||||
|
// The caller must call f.wg.Done() when the IO is finished, prior to Close() returning.
|
||||||
|
func (f *win32File) prepareIo() (*ioOperation, error) {
|
||||||
|
f.wgLock.RLock()
|
||||||
|
if f.closing.isSet() {
|
||||||
|
f.wgLock.RUnlock()
|
||||||
|
return nil, ErrFileClosed
|
||||||
|
}
|
||||||
|
f.wg.Add(1)
|
||||||
|
f.wgLock.RUnlock()
|
||||||
|
c := &ioOperation{}
|
||||||
|
c.ch = make(chan ioResult)
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ioCompletionProcessor processes completed async IOs forever
|
||||||
|
func ioCompletionProcessor(h syscall.Handle) {
|
||||||
|
for {
|
||||||
|
var bytes uint32
|
||||||
|
var key uintptr
|
||||||
|
var op *ioOperation
|
||||||
|
err := getQueuedCompletionStatus(h, &bytes, &key, &op, syscall.INFINITE)
|
||||||
|
if op == nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
op.ch <- ioResult{bytes, err}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// asyncIo processes the return value from ReadFile or WriteFile, blocking until
|
||||||
|
// the operation has actually completed.
|
||||||
|
func (f *win32File) asyncIo(c *ioOperation, d *deadlineHandler, bytes uint32, err error) (int, error) {
|
||||||
|
if err != syscall.ERROR_IO_PENDING {
|
||||||
|
return int(bytes), err
|
||||||
|
}
|
||||||
|
|
||||||
|
if f.closing.isSet() {
|
||||||
|
cancelIoEx(f.handle, &c.o)
|
||||||
|
}
|
||||||
|
|
||||||
|
var timeout timeoutChan
|
||||||
|
if d != nil {
|
||||||
|
d.channelLock.Lock()
|
||||||
|
timeout = d.channel
|
||||||
|
d.channelLock.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
var r ioResult
|
||||||
|
select {
|
||||||
|
case r = <-c.ch:
|
||||||
|
err = r.err
|
||||||
|
if err == syscall.ERROR_OPERATION_ABORTED {
|
||||||
|
if f.closing.isSet() {
|
||||||
|
err = ErrFileClosed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case <-timeout:
|
||||||
|
cancelIoEx(f.handle, &c.o)
|
||||||
|
r = <-c.ch
|
||||||
|
err = r.err
|
||||||
|
if err == syscall.ERROR_OPERATION_ABORTED {
|
||||||
|
err = ErrTimeout
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// runtime.KeepAlive is needed, as c is passed via native
|
||||||
|
// code to ioCompletionProcessor, c must remain alive
|
||||||
|
// until the channel read is complete.
|
||||||
|
runtime.KeepAlive(c)
|
||||||
|
return int(r.bytes), err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read reads from a file handle.
|
||||||
|
func (f *win32File) Read(b []byte) (int, error) {
|
||||||
|
c, err := f.prepareIo()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
defer f.wg.Done()
|
||||||
|
|
||||||
|
if f.readDeadline.timedout.isSet() {
|
||||||
|
return 0, ErrTimeout
|
||||||
|
}
|
||||||
|
|
||||||
|
var bytes uint32
|
||||||
|
err = syscall.ReadFile(f.handle, b, &bytes, &c.o)
|
||||||
|
n, err := f.asyncIo(c, &f.readDeadline, bytes, err)
|
||||||
|
runtime.KeepAlive(b)
|
||||||
|
|
||||||
|
// Handle EOF conditions.
|
||||||
|
if err == nil && n == 0 && len(b) != 0 {
|
||||||
|
return 0, io.EOF
|
||||||
|
} else if err == syscall.ERROR_BROKEN_PIPE {
|
||||||
|
return 0, io.EOF
|
||||||
|
} else {
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write writes to a file handle.
|
||||||
|
func (f *win32File) Write(b []byte) (int, error) {
|
||||||
|
c, err := f.prepareIo()
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
defer f.wg.Done()
|
||||||
|
|
||||||
|
if f.writeDeadline.timedout.isSet() {
|
||||||
|
return 0, ErrTimeout
|
||||||
|
}
|
||||||
|
|
||||||
|
var bytes uint32
|
||||||
|
err = syscall.WriteFile(f.handle, b, &bytes, &c.o)
|
||||||
|
n, err := f.asyncIo(c, &f.writeDeadline, bytes, err)
|
||||||
|
runtime.KeepAlive(b)
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *win32File) SetReadDeadline(deadline time.Time) error {
|
||||||
|
return f.readDeadline.set(deadline)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *win32File) SetWriteDeadline(deadline time.Time) error {
|
||||||
|
return f.writeDeadline.set(deadline)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *win32File) Flush() error {
|
||||||
|
return syscall.FlushFileBuffers(f.handle)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *deadlineHandler) set(deadline time.Time) error {
|
||||||
|
d.setLock.Lock()
|
||||||
|
defer d.setLock.Unlock()
|
||||||
|
|
||||||
|
if d.timer != nil {
|
||||||
|
if !d.timer.Stop() {
|
||||||
|
<-d.channel
|
||||||
|
}
|
||||||
|
d.timer = nil
|
||||||
|
}
|
||||||
|
d.timedout.setFalse()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-d.channel:
|
||||||
|
d.channelLock.Lock()
|
||||||
|
d.channel = make(chan struct{})
|
||||||
|
d.channelLock.Unlock()
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
if deadline.IsZero() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
timeoutIO := func() {
|
||||||
|
d.timedout.setTrue()
|
||||||
|
close(d.channel)
|
||||||
|
}
|
||||||
|
|
||||||
|
now := time.Now()
|
||||||
|
duration := deadline.Sub(now)
|
||||||
|
if deadline.After(now) {
|
||||||
|
// Deadline is in the future, set a timer to wait
|
||||||
|
d.timer = time.AfterFunc(duration, timeoutIO)
|
||||||
|
} else {
|
||||||
|
// Deadline is in the past. Cancel all pending IO now.
|
||||||
|
timeoutIO()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
61
vendor/github.com/Microsoft/go-winio/fileinfo.go
generated
vendored
Normal file
61
vendor/github.com/Microsoft/go-winio/fileinfo.go
generated
vendored
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
// +build windows
|
||||||
|
|
||||||
|
package winio
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
//sys getFileInformationByHandleEx(h syscall.Handle, class uint32, buffer *byte, size uint32) (err error) = GetFileInformationByHandleEx
|
||||||
|
//sys setFileInformationByHandle(h syscall.Handle, class uint32, buffer *byte, size uint32) (err error) = SetFileInformationByHandle
|
||||||
|
|
||||||
|
const (
|
||||||
|
fileBasicInfo = 0
|
||||||
|
fileIDInfo = 0x12
|
||||||
|
)
|
||||||
|
|
||||||
|
// FileBasicInfo contains file access time and file attributes information.
|
||||||
|
type FileBasicInfo struct {
|
||||||
|
CreationTime, LastAccessTime, LastWriteTime, ChangeTime syscall.Filetime
|
||||||
|
FileAttributes uint32
|
||||||
|
pad uint32 // padding
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetFileBasicInfo retrieves times and attributes for a file.
|
||||||
|
func GetFileBasicInfo(f *os.File) (*FileBasicInfo, error) {
|
||||||
|
bi := &FileBasicInfo{}
|
||||||
|
if err := getFileInformationByHandleEx(syscall.Handle(f.Fd()), fileBasicInfo, (*byte)(unsafe.Pointer(bi)), uint32(unsafe.Sizeof(*bi))); err != nil {
|
||||||
|
return nil, &os.PathError{Op: "GetFileInformationByHandleEx", Path: f.Name(), Err: err}
|
||||||
|
}
|
||||||
|
runtime.KeepAlive(f)
|
||||||
|
return bi, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetFileBasicInfo sets times and attributes for a file.
|
||||||
|
func SetFileBasicInfo(f *os.File, bi *FileBasicInfo) error {
|
||||||
|
if err := setFileInformationByHandle(syscall.Handle(f.Fd()), fileBasicInfo, (*byte)(unsafe.Pointer(bi)), uint32(unsafe.Sizeof(*bi))); err != nil {
|
||||||
|
return &os.PathError{Op: "SetFileInformationByHandle", Path: f.Name(), Err: err}
|
||||||
|
}
|
||||||
|
runtime.KeepAlive(f)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// FileIDInfo contains the volume serial number and file ID for a file. This pair should be
|
||||||
|
// unique on a system.
|
||||||
|
type FileIDInfo struct {
|
||||||
|
VolumeSerialNumber uint64
|
||||||
|
FileID [16]byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetFileID retrieves the unique (volume, file ID) pair for a file.
|
||||||
|
func GetFileID(f *os.File) (*FileIDInfo, error) {
|
||||||
|
fileID := &FileIDInfo{}
|
||||||
|
if err := getFileInformationByHandleEx(syscall.Handle(f.Fd()), fileIDInfo, (*byte)(unsafe.Pointer(fileID)), uint32(unsafe.Sizeof(*fileID))); err != nil {
|
||||||
|
return nil, &os.PathError{Op: "GetFileInformationByHandleEx", Path: f.Name(), Err: err}
|
||||||
|
}
|
||||||
|
runtime.KeepAlive(f)
|
||||||
|
return fileID, nil
|
||||||
|
}
|
421
vendor/github.com/Microsoft/go-winio/pipe.go
generated
vendored
Normal file
421
vendor/github.com/Microsoft/go-winio/pipe.go
generated
vendored
Normal file
@ -0,0 +1,421 @@
|
|||||||
|
// +build windows
|
||||||
|
|
||||||
|
package winio
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
//sys connectNamedPipe(pipe syscall.Handle, o *syscall.Overlapped) (err error) = ConnectNamedPipe
|
||||||
|
//sys createNamedPipe(name string, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *syscall.SecurityAttributes) (handle syscall.Handle, err error) [failretval==syscall.InvalidHandle] = CreateNamedPipeW
|
||||||
|
//sys createFile(name string, access uint32, mode uint32, sa *syscall.SecurityAttributes, createmode uint32, attrs uint32, templatefile syscall.Handle) (handle syscall.Handle, err error) [failretval==syscall.InvalidHandle] = CreateFileW
|
||||||
|
//sys getNamedPipeInfo(pipe syscall.Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error) = GetNamedPipeInfo
|
||||||
|
//sys getNamedPipeHandleState(pipe syscall.Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) = GetNamedPipeHandleStateW
|
||||||
|
//sys localAlloc(uFlags uint32, length uint32) (ptr uintptr) = LocalAlloc
|
||||||
|
|
||||||
|
const (
|
||||||
|
cERROR_PIPE_BUSY = syscall.Errno(231)
|
||||||
|
cERROR_NO_DATA = syscall.Errno(232)
|
||||||
|
cERROR_PIPE_CONNECTED = syscall.Errno(535)
|
||||||
|
cERROR_SEM_TIMEOUT = syscall.Errno(121)
|
||||||
|
|
||||||
|
cPIPE_ACCESS_DUPLEX = 0x3
|
||||||
|
cFILE_FLAG_FIRST_PIPE_INSTANCE = 0x80000
|
||||||
|
cSECURITY_SQOS_PRESENT = 0x100000
|
||||||
|
cSECURITY_ANONYMOUS = 0
|
||||||
|
|
||||||
|
cPIPE_REJECT_REMOTE_CLIENTS = 0x8
|
||||||
|
|
||||||
|
cPIPE_UNLIMITED_INSTANCES = 255
|
||||||
|
|
||||||
|
cNMPWAIT_USE_DEFAULT_WAIT = 0
|
||||||
|
cNMPWAIT_NOWAIT = 1
|
||||||
|
|
||||||
|
cPIPE_TYPE_MESSAGE = 4
|
||||||
|
|
||||||
|
cPIPE_READMODE_MESSAGE = 2
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// ErrPipeListenerClosed is returned for pipe operations on listeners that have been closed.
|
||||||
|
// This error should match net.errClosing since docker takes a dependency on its text.
|
||||||
|
ErrPipeListenerClosed = errors.New("use of closed network connection")
|
||||||
|
|
||||||
|
errPipeWriteClosed = errors.New("pipe has been closed for write")
|
||||||
|
)
|
||||||
|
|
||||||
|
type win32Pipe struct {
|
||||||
|
*win32File
|
||||||
|
path string
|
||||||
|
}
|
||||||
|
|
||||||
|
type win32MessageBytePipe struct {
|
||||||
|
win32Pipe
|
||||||
|
writeClosed bool
|
||||||
|
readEOF bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type pipeAddress string
|
||||||
|
|
||||||
|
func (f *win32Pipe) LocalAddr() net.Addr {
|
||||||
|
return pipeAddress(f.path)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *win32Pipe) RemoteAddr() net.Addr {
|
||||||
|
return pipeAddress(f.path)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *win32Pipe) SetDeadline(t time.Time) error {
|
||||||
|
f.SetReadDeadline(t)
|
||||||
|
f.SetWriteDeadline(t)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CloseWrite closes the write side of a message pipe in byte mode.
|
||||||
|
func (f *win32MessageBytePipe) CloseWrite() error {
|
||||||
|
if f.writeClosed {
|
||||||
|
return errPipeWriteClosed
|
||||||
|
}
|
||||||
|
err := f.win32File.Flush()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = f.win32File.Write(nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
f.writeClosed = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write writes bytes to a message pipe in byte mode. Zero-byte writes are ignored, since
|
||||||
|
// they are used to implement CloseWrite().
|
||||||
|
func (f *win32MessageBytePipe) Write(b []byte) (int, error) {
|
||||||
|
if f.writeClosed {
|
||||||
|
return 0, errPipeWriteClosed
|
||||||
|
}
|
||||||
|
if len(b) == 0 {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
return f.win32File.Write(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read reads bytes from a message pipe in byte mode. A read of a zero-byte message on a message
|
||||||
|
// mode pipe will return io.EOF, as will all subsequent reads.
|
||||||
|
func (f *win32MessageBytePipe) Read(b []byte) (int, error) {
|
||||||
|
if f.readEOF {
|
||||||
|
return 0, io.EOF
|
||||||
|
}
|
||||||
|
n, err := f.win32File.Read(b)
|
||||||
|
if err == io.EOF {
|
||||||
|
// If this was the result of a zero-byte read, then
|
||||||
|
// it is possible that the read was due to a zero-size
|
||||||
|
// message. Since we are simulating CloseWrite with a
|
||||||
|
// zero-byte message, ensure that all future Read() calls
|
||||||
|
// also return EOF.
|
||||||
|
f.readEOF = true
|
||||||
|
} else if err == syscall.ERROR_MORE_DATA {
|
||||||
|
// ERROR_MORE_DATA indicates that the pipe's read mode is message mode
|
||||||
|
// and the message still has more bytes. Treat this as a success, since
|
||||||
|
// this package presents all named pipes as byte streams.
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s pipeAddress) Network() string {
|
||||||
|
return "pipe"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s pipeAddress) String() string {
|
||||||
|
return string(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DialPipe connects to a named pipe by path, timing out if the connection
|
||||||
|
// takes longer than the specified duration. If timeout is nil, then we use
|
||||||
|
// a default timeout of 5 seconds. (We do not use WaitNamedPipe.)
|
||||||
|
func DialPipe(path string, timeout *time.Duration) (net.Conn, error) {
|
||||||
|
var absTimeout time.Time
|
||||||
|
if timeout != nil {
|
||||||
|
absTimeout = time.Now().Add(*timeout)
|
||||||
|
} else {
|
||||||
|
absTimeout = time.Now().Add(time.Second * 2)
|
||||||
|
}
|
||||||
|
var err error
|
||||||
|
var h syscall.Handle
|
||||||
|
for {
|
||||||
|
h, err = createFile(path, syscall.GENERIC_READ|syscall.GENERIC_WRITE, 0, nil, syscall.OPEN_EXISTING, syscall.FILE_FLAG_OVERLAPPED|cSECURITY_SQOS_PRESENT|cSECURITY_ANONYMOUS, 0)
|
||||||
|
if err != cERROR_PIPE_BUSY {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if time.Now().After(absTimeout) {
|
||||||
|
return nil, ErrTimeout
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait 10 msec and try again. This is a rather simplistic
|
||||||
|
// view, as we always try each 10 milliseconds.
|
||||||
|
time.Sleep(time.Millisecond * 10)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, &os.PathError{Op: "open", Path: path, Err: err}
|
||||||
|
}
|
||||||
|
|
||||||
|
var flags uint32
|
||||||
|
err = getNamedPipeInfo(h, &flags, nil, nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
f, err := makeWin32File(h)
|
||||||
|
if err != nil {
|
||||||
|
syscall.Close(h)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the pipe is in message mode, return a message byte pipe, which
|
||||||
|
// supports CloseWrite().
|
||||||
|
if flags&cPIPE_TYPE_MESSAGE != 0 {
|
||||||
|
return &win32MessageBytePipe{
|
||||||
|
win32Pipe: win32Pipe{win32File: f, path: path},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
return &win32Pipe{win32File: f, path: path}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type acceptResponse struct {
|
||||||
|
f *win32File
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
type win32PipeListener struct {
|
||||||
|
firstHandle syscall.Handle
|
||||||
|
path string
|
||||||
|
securityDescriptor []byte
|
||||||
|
config PipeConfig
|
||||||
|
acceptCh chan (chan acceptResponse)
|
||||||
|
closeCh chan int
|
||||||
|
doneCh chan int
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeServerPipeHandle(path string, securityDescriptor []byte, c *PipeConfig, first bool) (syscall.Handle, error) {
|
||||||
|
var flags uint32 = cPIPE_ACCESS_DUPLEX | syscall.FILE_FLAG_OVERLAPPED
|
||||||
|
if first {
|
||||||
|
flags |= cFILE_FLAG_FIRST_PIPE_INSTANCE
|
||||||
|
}
|
||||||
|
|
||||||
|
var mode uint32 = cPIPE_REJECT_REMOTE_CLIENTS
|
||||||
|
if c.MessageMode {
|
||||||
|
mode |= cPIPE_TYPE_MESSAGE
|
||||||
|
}
|
||||||
|
|
||||||
|
sa := &syscall.SecurityAttributes{}
|
||||||
|
sa.Length = uint32(unsafe.Sizeof(*sa))
|
||||||
|
if securityDescriptor != nil {
|
||||||
|
len := uint32(len(securityDescriptor))
|
||||||
|
sa.SecurityDescriptor = localAlloc(0, len)
|
||||||
|
defer localFree(sa.SecurityDescriptor)
|
||||||
|
copy((*[0xffff]byte)(unsafe.Pointer(sa.SecurityDescriptor))[:], securityDescriptor)
|
||||||
|
}
|
||||||
|
h, err := createNamedPipe(path, flags, mode, cPIPE_UNLIMITED_INSTANCES, uint32(c.OutputBufferSize), uint32(c.InputBufferSize), 0, sa)
|
||||||
|
if err != nil {
|
||||||
|
return 0, &os.PathError{Op: "open", Path: path, Err: err}
|
||||||
|
}
|
||||||
|
return h, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *win32PipeListener) makeServerPipe() (*win32File, error) {
|
||||||
|
h, err := makeServerPipeHandle(l.path, l.securityDescriptor, &l.config, false)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
f, err := makeWin32File(h)
|
||||||
|
if err != nil {
|
||||||
|
syscall.Close(h)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return f, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *win32PipeListener) makeConnectedServerPipe() (*win32File, error) {
|
||||||
|
p, err := l.makeServerPipe()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for the client to connect.
|
||||||
|
ch := make(chan error)
|
||||||
|
go func(p *win32File) {
|
||||||
|
ch <- connectPipe(p)
|
||||||
|
}(p)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case err = <-ch:
|
||||||
|
if err != nil {
|
||||||
|
p.Close()
|
||||||
|
p = nil
|
||||||
|
}
|
||||||
|
case <-l.closeCh:
|
||||||
|
// Abort the connect request by closing the handle.
|
||||||
|
p.Close()
|
||||||
|
p = nil
|
||||||
|
err = <-ch
|
||||||
|
if err == nil || err == ErrFileClosed {
|
||||||
|
err = ErrPipeListenerClosed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return p, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *win32PipeListener) listenerRoutine() {
|
||||||
|
closed := false
|
||||||
|
for !closed {
|
||||||
|
select {
|
||||||
|
case <-l.closeCh:
|
||||||
|
closed = true
|
||||||
|
case responseCh := <-l.acceptCh:
|
||||||
|
var (
|
||||||
|
p *win32File
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
for {
|
||||||
|
p, err = l.makeConnectedServerPipe()
|
||||||
|
// If the connection was immediately closed by the client, try
|
||||||
|
// again.
|
||||||
|
if err != cERROR_NO_DATA {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
responseCh <- acceptResponse{p, err}
|
||||||
|
closed = err == ErrPipeListenerClosed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
syscall.Close(l.firstHandle)
|
||||||
|
l.firstHandle = 0
|
||||||
|
// Notify Close() and Accept() callers that the handle has been closed.
|
||||||
|
close(l.doneCh)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PipeConfig contain configuration for the pipe listener.
|
||||||
|
type PipeConfig struct {
|
||||||
|
// SecurityDescriptor contains a Windows security descriptor in SDDL format.
|
||||||
|
SecurityDescriptor string
|
||||||
|
|
||||||
|
// MessageMode determines whether the pipe is in byte or message mode. In either
|
||||||
|
// case the pipe is read in byte mode by default. The only practical difference in
|
||||||
|
// this implementation is that CloseWrite() is only supported for message mode pipes;
|
||||||
|
// CloseWrite() is implemented as a zero-byte write, but zero-byte writes are only
|
||||||
|
// transferred to the reader (and returned as io.EOF in this implementation)
|
||||||
|
// when the pipe is in message mode.
|
||||||
|
MessageMode bool
|
||||||
|
|
||||||
|
// InputBufferSize specifies the size the input buffer, in bytes.
|
||||||
|
InputBufferSize int32
|
||||||
|
|
||||||
|
// OutputBufferSize specifies the size the input buffer, in bytes.
|
||||||
|
OutputBufferSize int32
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListenPipe creates a listener on a Windows named pipe path, e.g. \\.\pipe\mypipe.
|
||||||
|
// The pipe must not already exist.
|
||||||
|
func ListenPipe(path string, c *PipeConfig) (net.Listener, error) {
|
||||||
|
var (
|
||||||
|
sd []byte
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
if c == nil {
|
||||||
|
c = &PipeConfig{}
|
||||||
|
}
|
||||||
|
if c.SecurityDescriptor != "" {
|
||||||
|
sd, err = SddlToSecurityDescriptor(c.SecurityDescriptor)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
h, err := makeServerPipeHandle(path, sd, c, true)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Create a client handle and connect it. This results in the pipe
|
||||||
|
// instance always existing, so that clients see ERROR_PIPE_BUSY
|
||||||
|
// rather than ERROR_FILE_NOT_FOUND. This ties the first instance
|
||||||
|
// up so that no other instances can be used. This would have been
|
||||||
|
// cleaner if the Win32 API matched CreateFile with ConnectNamedPipe
|
||||||
|
// instead of CreateNamedPipe. (Apparently created named pipes are
|
||||||
|
// considered to be in listening state regardless of whether any
|
||||||
|
// active calls to ConnectNamedPipe are outstanding.)
|
||||||
|
h2, err := createFile(path, 0, 0, nil, syscall.OPEN_EXISTING, cSECURITY_SQOS_PRESENT|cSECURITY_ANONYMOUS, 0)
|
||||||
|
if err != nil {
|
||||||
|
syscall.Close(h)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Close the client handle. The server side of the instance will
|
||||||
|
// still be busy, leading to ERROR_PIPE_BUSY instead of
|
||||||
|
// ERROR_NOT_FOUND, as long as we don't close the server handle,
|
||||||
|
// or disconnect the client with DisconnectNamedPipe.
|
||||||
|
syscall.Close(h2)
|
||||||
|
l := &win32PipeListener{
|
||||||
|
firstHandle: h,
|
||||||
|
path: path,
|
||||||
|
securityDescriptor: sd,
|
||||||
|
config: *c,
|
||||||
|
acceptCh: make(chan (chan acceptResponse)),
|
||||||
|
closeCh: make(chan int),
|
||||||
|
doneCh: make(chan int),
|
||||||
|
}
|
||||||
|
go l.listenerRoutine()
|
||||||
|
return l, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func connectPipe(p *win32File) error {
|
||||||
|
c, err := p.prepareIo()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer p.wg.Done()
|
||||||
|
|
||||||
|
err = connectNamedPipe(p.handle, &c.o)
|
||||||
|
_, err = p.asyncIo(c, nil, 0, err)
|
||||||
|
if err != nil && err != cERROR_PIPE_CONNECTED {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *win32PipeListener) Accept() (net.Conn, error) {
|
||||||
|
ch := make(chan acceptResponse)
|
||||||
|
select {
|
||||||
|
case l.acceptCh <- ch:
|
||||||
|
response := <-ch
|
||||||
|
err := response.err
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if l.config.MessageMode {
|
||||||
|
return &win32MessageBytePipe{
|
||||||
|
win32Pipe: win32Pipe{win32File: response.f, path: l.path},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
return &win32Pipe{win32File: response.f, path: l.path}, nil
|
||||||
|
case <-l.doneCh:
|
||||||
|
return nil, ErrPipeListenerClosed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *win32PipeListener) Close() error {
|
||||||
|
select {
|
||||||
|
case l.closeCh <- 1:
|
||||||
|
<-l.doneCh
|
||||||
|
case <-l.doneCh:
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *win32PipeListener) Addr() net.Addr {
|
||||||
|
return pipeAddress(l.path)
|
||||||
|
}
|
202
vendor/github.com/Microsoft/go-winio/privilege.go
generated
vendored
Normal file
202
vendor/github.com/Microsoft/go-winio/privilege.go
generated
vendored
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
// +build windows
|
||||||
|
|
||||||
|
package winio
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
"runtime"
|
||||||
|
"sync"
|
||||||
|
"syscall"
|
||||||
|
"unicode/utf16"
|
||||||
|
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
|
)
|
||||||
|
|
||||||
|
//sys adjustTokenPrivileges(token windows.Token, releaseAll bool, input *byte, outputSize uint32, output *byte, requiredSize *uint32) (success bool, err error) [true] = advapi32.AdjustTokenPrivileges
|
||||||
|
//sys impersonateSelf(level uint32) (err error) = advapi32.ImpersonateSelf
|
||||||
|
//sys revertToSelf() (err error) = advapi32.RevertToSelf
|
||||||
|
//sys openThreadToken(thread syscall.Handle, accessMask uint32, openAsSelf bool, token *windows.Token) (err error) = advapi32.OpenThreadToken
|
||||||
|
//sys getCurrentThread() (h syscall.Handle) = GetCurrentThread
|
||||||
|
//sys lookupPrivilegeValue(systemName string, name string, luid *uint64) (err error) = advapi32.LookupPrivilegeValueW
|
||||||
|
//sys lookupPrivilegeName(systemName string, luid *uint64, buffer *uint16, size *uint32) (err error) = advapi32.LookupPrivilegeNameW
|
||||||
|
//sys lookupPrivilegeDisplayName(systemName string, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) = advapi32.LookupPrivilegeDisplayNameW
|
||||||
|
|
||||||
|
const (
|
||||||
|
SE_PRIVILEGE_ENABLED = 2
|
||||||
|
|
||||||
|
ERROR_NOT_ALL_ASSIGNED syscall.Errno = 1300
|
||||||
|
|
||||||
|
SeBackupPrivilege = "SeBackupPrivilege"
|
||||||
|
SeRestorePrivilege = "SeRestorePrivilege"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
securityAnonymous = iota
|
||||||
|
securityIdentification
|
||||||
|
securityImpersonation
|
||||||
|
securityDelegation
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
privNames = make(map[string]uint64)
|
||||||
|
privNameMutex sync.Mutex
|
||||||
|
)
|
||||||
|
|
||||||
|
// PrivilegeError represents an error enabling privileges.
|
||||||
|
type PrivilegeError struct {
|
||||||
|
privileges []uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *PrivilegeError) Error() string {
|
||||||
|
s := ""
|
||||||
|
if len(e.privileges) > 1 {
|
||||||
|
s = "Could not enable privileges "
|
||||||
|
} else {
|
||||||
|
s = "Could not enable privilege "
|
||||||
|
}
|
||||||
|
for i, p := range e.privileges {
|
||||||
|
if i != 0 {
|
||||||
|
s += ", "
|
||||||
|
}
|
||||||
|
s += `"`
|
||||||
|
s += getPrivilegeName(p)
|
||||||
|
s += `"`
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// RunWithPrivilege enables a single privilege for a function call.
|
||||||
|
func RunWithPrivilege(name string, fn func() error) error {
|
||||||
|
return RunWithPrivileges([]string{name}, fn)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RunWithPrivileges enables privileges for a function call.
|
||||||
|
func RunWithPrivileges(names []string, fn func() error) error {
|
||||||
|
privileges, err := mapPrivileges(names)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
runtime.LockOSThread()
|
||||||
|
defer runtime.UnlockOSThread()
|
||||||
|
token, err := newThreadToken()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer releaseThreadToken(token)
|
||||||
|
err = adjustPrivileges(token, privileges, SE_PRIVILEGE_ENABLED)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return fn()
|
||||||
|
}
|
||||||
|
|
||||||
|
func mapPrivileges(names []string) ([]uint64, error) {
|
||||||
|
var privileges []uint64
|
||||||
|
privNameMutex.Lock()
|
||||||
|
defer privNameMutex.Unlock()
|
||||||
|
for _, name := range names {
|
||||||
|
p, ok := privNames[name]
|
||||||
|
if !ok {
|
||||||
|
err := lookupPrivilegeValue("", name, &p)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
privNames[name] = p
|
||||||
|
}
|
||||||
|
privileges = append(privileges, p)
|
||||||
|
}
|
||||||
|
return privileges, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnableProcessPrivileges enables privileges globally for the process.
|
||||||
|
func EnableProcessPrivileges(names []string) error {
|
||||||
|
return enableDisableProcessPrivilege(names, SE_PRIVILEGE_ENABLED)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DisableProcessPrivileges disables privileges globally for the process.
|
||||||
|
func DisableProcessPrivileges(names []string) error {
|
||||||
|
return enableDisableProcessPrivilege(names, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func enableDisableProcessPrivilege(names []string, action uint32) error {
|
||||||
|
privileges, err := mapPrivileges(names)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
p, _ := windows.GetCurrentProcess()
|
||||||
|
var token windows.Token
|
||||||
|
err = windows.OpenProcessToken(p, windows.TOKEN_ADJUST_PRIVILEGES|windows.TOKEN_QUERY, &token)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer token.Close()
|
||||||
|
return adjustPrivileges(token, privileges, action)
|
||||||
|
}
|
||||||
|
|
||||||
|
func adjustPrivileges(token windows.Token, privileges []uint64, action uint32) error {
|
||||||
|
var b bytes.Buffer
|
||||||
|
binary.Write(&b, binary.LittleEndian, uint32(len(privileges)))
|
||||||
|
for _, p := range privileges {
|
||||||
|
binary.Write(&b, binary.LittleEndian, p)
|
||||||
|
binary.Write(&b, binary.LittleEndian, action)
|
||||||
|
}
|
||||||
|
prevState := make([]byte, b.Len())
|
||||||
|
reqSize := uint32(0)
|
||||||
|
success, err := adjustTokenPrivileges(token, false, &b.Bytes()[0], uint32(len(prevState)), &prevState[0], &reqSize)
|
||||||
|
if !success {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err == ERROR_NOT_ALL_ASSIGNED {
|
||||||
|
return &PrivilegeError{privileges}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getPrivilegeName(luid uint64) string {
|
||||||
|
var nameBuffer [256]uint16
|
||||||
|
bufSize := uint32(len(nameBuffer))
|
||||||
|
err := lookupPrivilegeName("", &luid, &nameBuffer[0], &bufSize)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Sprintf("<unknown privilege %d>", luid)
|
||||||
|
}
|
||||||
|
|
||||||
|
var displayNameBuffer [256]uint16
|
||||||
|
displayBufSize := uint32(len(displayNameBuffer))
|
||||||
|
var langID uint32
|
||||||
|
err = lookupPrivilegeDisplayName("", &nameBuffer[0], &displayNameBuffer[0], &displayBufSize, &langID)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Sprintf("<unknown privilege %s>", string(utf16.Decode(nameBuffer[:bufSize])))
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(utf16.Decode(displayNameBuffer[:displayBufSize]))
|
||||||
|
}
|
||||||
|
|
||||||
|
func newThreadToken() (windows.Token, error) {
|
||||||
|
err := impersonateSelf(securityImpersonation)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var token windows.Token
|
||||||
|
err = openThreadToken(getCurrentThread(), syscall.TOKEN_ADJUST_PRIVILEGES|syscall.TOKEN_QUERY, false, &token)
|
||||||
|
if err != nil {
|
||||||
|
rerr := revertToSelf()
|
||||||
|
if rerr != nil {
|
||||||
|
panic(rerr)
|
||||||
|
}
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return token, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func releaseThreadToken(h windows.Token) {
|
||||||
|
err := revertToSelf()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
h.Close()
|
||||||
|
}
|
128
vendor/github.com/Microsoft/go-winio/reparse.go
generated
vendored
Normal file
128
vendor/github.com/Microsoft/go-winio/reparse.go
generated
vendored
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
package winio
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"unicode/utf16"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
reparseTagMountPoint = 0xA0000003
|
||||||
|
reparseTagSymlink = 0xA000000C
|
||||||
|
)
|
||||||
|
|
||||||
|
type reparseDataBuffer struct {
|
||||||
|
ReparseTag uint32
|
||||||
|
ReparseDataLength uint16
|
||||||
|
Reserved uint16
|
||||||
|
SubstituteNameOffset uint16
|
||||||
|
SubstituteNameLength uint16
|
||||||
|
PrintNameOffset uint16
|
||||||
|
PrintNameLength uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReparsePoint describes a Win32 symlink or mount point.
|
||||||
|
type ReparsePoint struct {
|
||||||
|
Target string
|
||||||
|
IsMountPoint bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnsupportedReparsePointError is returned when trying to decode a non-symlink or
|
||||||
|
// mount point reparse point.
|
||||||
|
type UnsupportedReparsePointError struct {
|
||||||
|
Tag uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *UnsupportedReparsePointError) Error() string {
|
||||||
|
return fmt.Sprintf("unsupported reparse point %x", e.Tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecodeReparsePoint decodes a Win32 REPARSE_DATA_BUFFER structure containing either a symlink
|
||||||
|
// or a mount point.
|
||||||
|
func DecodeReparsePoint(b []byte) (*ReparsePoint, error) {
|
||||||
|
tag := binary.LittleEndian.Uint32(b[0:4])
|
||||||
|
return DecodeReparsePointData(tag, b[8:])
|
||||||
|
}
|
||||||
|
|
||||||
|
func DecodeReparsePointData(tag uint32, b []byte) (*ReparsePoint, error) {
|
||||||
|
isMountPoint := false
|
||||||
|
switch tag {
|
||||||
|
case reparseTagMountPoint:
|
||||||
|
isMountPoint = true
|
||||||
|
case reparseTagSymlink:
|
||||||
|
default:
|
||||||
|
return nil, &UnsupportedReparsePointError{tag}
|
||||||
|
}
|
||||||
|
nameOffset := 8 + binary.LittleEndian.Uint16(b[4:6])
|
||||||
|
if !isMountPoint {
|
||||||
|
nameOffset += 4
|
||||||
|
}
|
||||||
|
nameLength := binary.LittleEndian.Uint16(b[6:8])
|
||||||
|
name := make([]uint16, nameLength/2)
|
||||||
|
err := binary.Read(bytes.NewReader(b[nameOffset:nameOffset+nameLength]), binary.LittleEndian, &name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &ReparsePoint{string(utf16.Decode(name)), isMountPoint}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func isDriveLetter(c byte) bool {
|
||||||
|
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncodeReparsePoint encodes a Win32 REPARSE_DATA_BUFFER structure describing a symlink or
|
||||||
|
// mount point.
|
||||||
|
func EncodeReparsePoint(rp *ReparsePoint) []byte {
|
||||||
|
// Generate an NT path and determine if this is a relative path.
|
||||||
|
var ntTarget string
|
||||||
|
relative := false
|
||||||
|
if strings.HasPrefix(rp.Target, `\\?\`) {
|
||||||
|
ntTarget = `\??\` + rp.Target[4:]
|
||||||
|
} else if strings.HasPrefix(rp.Target, `\\`) {
|
||||||
|
ntTarget = `\??\UNC\` + rp.Target[2:]
|
||||||
|
} else if len(rp.Target) >= 2 && isDriveLetter(rp.Target[0]) && rp.Target[1] == ':' {
|
||||||
|
ntTarget = `\??\` + rp.Target
|
||||||
|
} else {
|
||||||
|
ntTarget = rp.Target
|
||||||
|
relative = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// The paths must be NUL-terminated even though they are counted strings.
|
||||||
|
target16 := utf16.Encode([]rune(rp.Target + "\x00"))
|
||||||
|
ntTarget16 := utf16.Encode([]rune(ntTarget + "\x00"))
|
||||||
|
|
||||||
|
size := int(unsafe.Sizeof(reparseDataBuffer{})) - 8
|
||||||
|
size += len(ntTarget16)*2 + len(target16)*2
|
||||||
|
|
||||||
|
tag := uint32(reparseTagMountPoint)
|
||||||
|
if !rp.IsMountPoint {
|
||||||
|
tag = reparseTagSymlink
|
||||||
|
size += 4 // Add room for symlink flags
|
||||||
|
}
|
||||||
|
|
||||||
|
data := reparseDataBuffer{
|
||||||
|
ReparseTag: tag,
|
||||||
|
ReparseDataLength: uint16(size),
|
||||||
|
SubstituteNameOffset: 0,
|
||||||
|
SubstituteNameLength: uint16((len(ntTarget16) - 1) * 2),
|
||||||
|
PrintNameOffset: uint16(len(ntTarget16) * 2),
|
||||||
|
PrintNameLength: uint16((len(target16) - 1) * 2),
|
||||||
|
}
|
||||||
|
|
||||||
|
var b bytes.Buffer
|
||||||
|
binary.Write(&b, binary.LittleEndian, &data)
|
||||||
|
if !rp.IsMountPoint {
|
||||||
|
flags := uint32(0)
|
||||||
|
if relative {
|
||||||
|
flags |= 1
|
||||||
|
}
|
||||||
|
binary.Write(&b, binary.LittleEndian, flags)
|
||||||
|
}
|
||||||
|
|
||||||
|
binary.Write(&b, binary.LittleEndian, ntTarget16)
|
||||||
|
binary.Write(&b, binary.LittleEndian, target16)
|
||||||
|
return b.Bytes()
|
||||||
|
}
|
98
vendor/github.com/Microsoft/go-winio/sd.go
generated
vendored
Normal file
98
vendor/github.com/Microsoft/go-winio/sd.go
generated
vendored
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
// +build windows
|
||||||
|
|
||||||
|
package winio
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
//sys lookupAccountName(systemName *uint16, accountName string, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) = advapi32.LookupAccountNameW
|
||||||
|
//sys convertSidToStringSid(sid *byte, str **uint16) (err error) = advapi32.ConvertSidToStringSidW
|
||||||
|
//sys convertStringSecurityDescriptorToSecurityDescriptor(str string, revision uint32, sd *uintptr, size *uint32) (err error) = advapi32.ConvertStringSecurityDescriptorToSecurityDescriptorW
|
||||||
|
//sys convertSecurityDescriptorToStringSecurityDescriptor(sd *byte, revision uint32, secInfo uint32, sddl **uint16, sddlSize *uint32) (err error) = advapi32.ConvertSecurityDescriptorToStringSecurityDescriptorW
|
||||||
|
//sys localFree(mem uintptr) = LocalFree
|
||||||
|
//sys getSecurityDescriptorLength(sd uintptr) (len uint32) = advapi32.GetSecurityDescriptorLength
|
||||||
|
|
||||||
|
const (
|
||||||
|
cERROR_NONE_MAPPED = syscall.Errno(1332)
|
||||||
|
)
|
||||||
|
|
||||||
|
type AccountLookupError struct {
|
||||||
|
Name string
|
||||||
|
Err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *AccountLookupError) Error() string {
|
||||||
|
if e.Name == "" {
|
||||||
|
return "lookup account: empty account name specified"
|
||||||
|
}
|
||||||
|
var s string
|
||||||
|
switch e.Err {
|
||||||
|
case cERROR_NONE_MAPPED:
|
||||||
|
s = "not found"
|
||||||
|
default:
|
||||||
|
s = e.Err.Error()
|
||||||
|
}
|
||||||
|
return "lookup account " + e.Name + ": " + s
|
||||||
|
}
|
||||||
|
|
||||||
|
type SddlConversionError struct {
|
||||||
|
Sddl string
|
||||||
|
Err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *SddlConversionError) Error() string {
|
||||||
|
return "convert " + e.Sddl + ": " + e.Err.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
// LookupSidByName looks up the SID of an account by name
|
||||||
|
func LookupSidByName(name string) (sid string, err error) {
|
||||||
|
if name == "" {
|
||||||
|
return "", &AccountLookupError{name, cERROR_NONE_MAPPED}
|
||||||
|
}
|
||||||
|
|
||||||
|
var sidSize, sidNameUse, refDomainSize uint32
|
||||||
|
err = lookupAccountName(nil, name, nil, &sidSize, nil, &refDomainSize, &sidNameUse)
|
||||||
|
if err != nil && err != syscall.ERROR_INSUFFICIENT_BUFFER {
|
||||||
|
return "", &AccountLookupError{name, err}
|
||||||
|
}
|
||||||
|
sidBuffer := make([]byte, sidSize)
|
||||||
|
refDomainBuffer := make([]uint16, refDomainSize)
|
||||||
|
err = lookupAccountName(nil, name, &sidBuffer[0], &sidSize, &refDomainBuffer[0], &refDomainSize, &sidNameUse)
|
||||||
|
if err != nil {
|
||||||
|
return "", &AccountLookupError{name, err}
|
||||||
|
}
|
||||||
|
var strBuffer *uint16
|
||||||
|
err = convertSidToStringSid(&sidBuffer[0], &strBuffer)
|
||||||
|
if err != nil {
|
||||||
|
return "", &AccountLookupError{name, err}
|
||||||
|
}
|
||||||
|
sid = syscall.UTF16ToString((*[0xffff]uint16)(unsafe.Pointer(strBuffer))[:])
|
||||||
|
localFree(uintptr(unsafe.Pointer(strBuffer)))
|
||||||
|
return sid, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func SddlToSecurityDescriptor(sddl string) ([]byte, error) {
|
||||||
|
var sdBuffer uintptr
|
||||||
|
err := convertStringSecurityDescriptorToSecurityDescriptor(sddl, 1, &sdBuffer, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, &SddlConversionError{sddl, err}
|
||||||
|
}
|
||||||
|
defer localFree(sdBuffer)
|
||||||
|
sd := make([]byte, getSecurityDescriptorLength(sdBuffer))
|
||||||
|
copy(sd, (*[0xffff]byte)(unsafe.Pointer(sdBuffer))[:len(sd)])
|
||||||
|
return sd, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func SecurityDescriptorToSddl(sd []byte) (string, error) {
|
||||||
|
var sddl *uint16
|
||||||
|
// The returned string length seems to including an aribtrary number of terminating NULs.
|
||||||
|
// Don't use it.
|
||||||
|
err := convertSecurityDescriptorToStringSecurityDescriptor(&sd[0], 1, 0xff, &sddl, nil)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer localFree(uintptr(unsafe.Pointer(sddl)))
|
||||||
|
return syscall.UTF16ToString((*[0xffff]uint16)(unsafe.Pointer(sddl))[:]), nil
|
||||||
|
}
|
3
vendor/github.com/Microsoft/go-winio/syscall.go
generated
vendored
Normal file
3
vendor/github.com/Microsoft/go-winio/syscall.go
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
package winio
|
||||||
|
|
||||||
|
//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go file.go pipe.go sd.go fileinfo.go privilege.go backup.go
|
520
vendor/github.com/Microsoft/go-winio/zsyscall_windows.go
generated
vendored
Normal file
520
vendor/github.com/Microsoft/go-winio/zsyscall_windows.go
generated
vendored
Normal file
@ -0,0 +1,520 @@
|
|||||||
|
// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT
|
||||||
|
|
||||||
|
package winio
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ unsafe.Pointer
|
||||||
|
|
||||||
|
// Do the interface allocations only once for common
|
||||||
|
// Errno values.
|
||||||
|
const (
|
||||||
|
errnoERROR_IO_PENDING = 997
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
|
||||||
|
)
|
||||||
|
|
||||||
|
// errnoErr returns common boxed Errno values, to prevent
|
||||||
|
// allocations at runtime.
|
||||||
|
func errnoErr(e syscall.Errno) error {
|
||||||
|
switch e {
|
||||||
|
case 0:
|
||||||
|
return nil
|
||||||
|
case errnoERROR_IO_PENDING:
|
||||||
|
return errERROR_IO_PENDING
|
||||||
|
}
|
||||||
|
// TODO: add more here, after collecting data on the common
|
||||||
|
// error values see on Windows. (perhaps when running
|
||||||
|
// all.bat?)
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
|
||||||
|
modadvapi32 = windows.NewLazySystemDLL("advapi32.dll")
|
||||||
|
|
||||||
|
procCancelIoEx = modkernel32.NewProc("CancelIoEx")
|
||||||
|
procCreateIoCompletionPort = modkernel32.NewProc("CreateIoCompletionPort")
|
||||||
|
procGetQueuedCompletionStatus = modkernel32.NewProc("GetQueuedCompletionStatus")
|
||||||
|
procSetFileCompletionNotificationModes = modkernel32.NewProc("SetFileCompletionNotificationModes")
|
||||||
|
procConnectNamedPipe = modkernel32.NewProc("ConnectNamedPipe")
|
||||||
|
procCreateNamedPipeW = modkernel32.NewProc("CreateNamedPipeW")
|
||||||
|
procCreateFileW = modkernel32.NewProc("CreateFileW")
|
||||||
|
procWaitNamedPipeW = modkernel32.NewProc("WaitNamedPipeW")
|
||||||
|
procGetNamedPipeInfo = modkernel32.NewProc("GetNamedPipeInfo")
|
||||||
|
procGetNamedPipeHandleStateW = modkernel32.NewProc("GetNamedPipeHandleStateW")
|
||||||
|
procLocalAlloc = modkernel32.NewProc("LocalAlloc")
|
||||||
|
procLookupAccountNameW = modadvapi32.NewProc("LookupAccountNameW")
|
||||||
|
procConvertSidToStringSidW = modadvapi32.NewProc("ConvertSidToStringSidW")
|
||||||
|
procConvertStringSecurityDescriptorToSecurityDescriptorW = modadvapi32.NewProc("ConvertStringSecurityDescriptorToSecurityDescriptorW")
|
||||||
|
procConvertSecurityDescriptorToStringSecurityDescriptorW = modadvapi32.NewProc("ConvertSecurityDescriptorToStringSecurityDescriptorW")
|
||||||
|
procLocalFree = modkernel32.NewProc("LocalFree")
|
||||||
|
procGetSecurityDescriptorLength = modadvapi32.NewProc("GetSecurityDescriptorLength")
|
||||||
|
procGetFileInformationByHandleEx = modkernel32.NewProc("GetFileInformationByHandleEx")
|
||||||
|
procSetFileInformationByHandle = modkernel32.NewProc("SetFileInformationByHandle")
|
||||||
|
procAdjustTokenPrivileges = modadvapi32.NewProc("AdjustTokenPrivileges")
|
||||||
|
procImpersonateSelf = modadvapi32.NewProc("ImpersonateSelf")
|
||||||
|
procRevertToSelf = modadvapi32.NewProc("RevertToSelf")
|
||||||
|
procOpenThreadToken = modadvapi32.NewProc("OpenThreadToken")
|
||||||
|
procGetCurrentThread = modkernel32.NewProc("GetCurrentThread")
|
||||||
|
procLookupPrivilegeValueW = modadvapi32.NewProc("LookupPrivilegeValueW")
|
||||||
|
procLookupPrivilegeNameW = modadvapi32.NewProc("LookupPrivilegeNameW")
|
||||||
|
procLookupPrivilegeDisplayNameW = modadvapi32.NewProc("LookupPrivilegeDisplayNameW")
|
||||||
|
procBackupRead = modkernel32.NewProc("BackupRead")
|
||||||
|
procBackupWrite = modkernel32.NewProc("BackupWrite")
|
||||||
|
)
|
||||||
|
|
||||||
|
func cancelIoEx(file syscall.Handle, o *syscall.Overlapped) (err error) {
|
||||||
|
r1, _, e1 := syscall.Syscall(procCancelIoEx.Addr(), 2, uintptr(file), uintptr(unsafe.Pointer(o)), 0)
|
||||||
|
if r1 == 0 {
|
||||||
|
if e1 != 0 {
|
||||||
|
err = errnoErr(e1)
|
||||||
|
} else {
|
||||||
|
err = syscall.EINVAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func createIoCompletionPort(file syscall.Handle, port syscall.Handle, key uintptr, threadCount uint32) (newport syscall.Handle, err error) {
|
||||||
|
r0, _, e1 := syscall.Syscall6(procCreateIoCompletionPort.Addr(), 4, uintptr(file), uintptr(port), uintptr(key), uintptr(threadCount), 0, 0)
|
||||||
|
newport = syscall.Handle(r0)
|
||||||
|
if newport == 0 {
|
||||||
|
if e1 != 0 {
|
||||||
|
err = errnoErr(e1)
|
||||||
|
} else {
|
||||||
|
err = syscall.EINVAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func getQueuedCompletionStatus(port syscall.Handle, bytes *uint32, key *uintptr, o **ioOperation, timeout uint32) (err error) {
|
||||||
|
r1, _, e1 := syscall.Syscall6(procGetQueuedCompletionStatus.Addr(), 5, uintptr(port), uintptr(unsafe.Pointer(bytes)), uintptr(unsafe.Pointer(key)), uintptr(unsafe.Pointer(o)), uintptr(timeout), 0)
|
||||||
|
if r1 == 0 {
|
||||||
|
if e1 != 0 {
|
||||||
|
err = errnoErr(e1)
|
||||||
|
} else {
|
||||||
|
err = syscall.EINVAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func setFileCompletionNotificationModes(h syscall.Handle, flags uint8) (err error) {
|
||||||
|
r1, _, e1 := syscall.Syscall(procSetFileCompletionNotificationModes.Addr(), 2, uintptr(h), uintptr(flags), 0)
|
||||||
|
if r1 == 0 {
|
||||||
|
if e1 != 0 {
|
||||||
|
err = errnoErr(e1)
|
||||||
|
} else {
|
||||||
|
err = syscall.EINVAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func connectNamedPipe(pipe syscall.Handle, o *syscall.Overlapped) (err error) {
|
||||||
|
r1, _, e1 := syscall.Syscall(procConnectNamedPipe.Addr(), 2, uintptr(pipe), uintptr(unsafe.Pointer(o)), 0)
|
||||||
|
if r1 == 0 {
|
||||||
|
if e1 != 0 {
|
||||||
|
err = errnoErr(e1)
|
||||||
|
} else {
|
||||||
|
err = syscall.EINVAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func createNamedPipe(name string, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *syscall.SecurityAttributes) (handle syscall.Handle, err error) {
|
||||||
|
var _p0 *uint16
|
||||||
|
_p0, err = syscall.UTF16PtrFromString(name)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return _createNamedPipe(_p0, flags, pipeMode, maxInstances, outSize, inSize, defaultTimeout, sa)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _createNamedPipe(name *uint16, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *syscall.SecurityAttributes) (handle syscall.Handle, err error) {
|
||||||
|
r0, _, e1 := syscall.Syscall9(procCreateNamedPipeW.Addr(), 8, uintptr(unsafe.Pointer(name)), uintptr(flags), uintptr(pipeMode), uintptr(maxInstances), uintptr(outSize), uintptr(inSize), uintptr(defaultTimeout), uintptr(unsafe.Pointer(sa)), 0)
|
||||||
|
handle = syscall.Handle(r0)
|
||||||
|
if handle == syscall.InvalidHandle {
|
||||||
|
if e1 != 0 {
|
||||||
|
err = errnoErr(e1)
|
||||||
|
} else {
|
||||||
|
err = syscall.EINVAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func createFile(name string, access uint32, mode uint32, sa *syscall.SecurityAttributes, createmode uint32, attrs uint32, templatefile syscall.Handle) (handle syscall.Handle, err error) {
|
||||||
|
var _p0 *uint16
|
||||||
|
_p0, err = syscall.UTF16PtrFromString(name)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return _createFile(_p0, access, mode, sa, createmode, attrs, templatefile)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _createFile(name *uint16, access uint32, mode uint32, sa *syscall.SecurityAttributes, createmode uint32, attrs uint32, templatefile syscall.Handle) (handle syscall.Handle, err error) {
|
||||||
|
r0, _, e1 := syscall.Syscall9(procCreateFileW.Addr(), 7, uintptr(unsafe.Pointer(name)), uintptr(access), uintptr(mode), uintptr(unsafe.Pointer(sa)), uintptr(createmode), uintptr(attrs), uintptr(templatefile), 0, 0)
|
||||||
|
handle = syscall.Handle(r0)
|
||||||
|
if handle == syscall.InvalidHandle {
|
||||||
|
if e1 != 0 {
|
||||||
|
err = errnoErr(e1)
|
||||||
|
} else {
|
||||||
|
err = syscall.EINVAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func waitNamedPipe(name string, timeout uint32) (err error) {
|
||||||
|
var _p0 *uint16
|
||||||
|
_p0, err = syscall.UTF16PtrFromString(name)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return _waitNamedPipe(_p0, timeout)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _waitNamedPipe(name *uint16, timeout uint32) (err error) {
|
||||||
|
r1, _, e1 := syscall.Syscall(procWaitNamedPipeW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(timeout), 0)
|
||||||
|
if r1 == 0 {
|
||||||
|
if e1 != 0 {
|
||||||
|
err = errnoErr(e1)
|
||||||
|
} else {
|
||||||
|
err = syscall.EINVAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func getNamedPipeInfo(pipe syscall.Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error) {
|
||||||
|
r1, _, e1 := syscall.Syscall6(procGetNamedPipeInfo.Addr(), 5, uintptr(pipe), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(outSize)), uintptr(unsafe.Pointer(inSize)), uintptr(unsafe.Pointer(maxInstances)), 0)
|
||||||
|
if r1 == 0 {
|
||||||
|
if e1 != 0 {
|
||||||
|
err = errnoErr(e1)
|
||||||
|
} else {
|
||||||
|
err = syscall.EINVAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func getNamedPipeHandleState(pipe syscall.Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) {
|
||||||
|
r1, _, e1 := syscall.Syscall9(procGetNamedPipeHandleStateW.Addr(), 7, uintptr(pipe), uintptr(unsafe.Pointer(state)), uintptr(unsafe.Pointer(curInstances)), uintptr(unsafe.Pointer(maxCollectionCount)), uintptr(unsafe.Pointer(collectDataTimeout)), uintptr(unsafe.Pointer(userName)), uintptr(maxUserNameSize), 0, 0)
|
||||||
|
if r1 == 0 {
|
||||||
|
if e1 != 0 {
|
||||||
|
err = errnoErr(e1)
|
||||||
|
} else {
|
||||||
|
err = syscall.EINVAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func localAlloc(uFlags uint32, length uint32) (ptr uintptr) {
|
||||||
|
r0, _, _ := syscall.Syscall(procLocalAlloc.Addr(), 2, uintptr(uFlags), uintptr(length), 0)
|
||||||
|
ptr = uintptr(r0)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func lookupAccountName(systemName *uint16, accountName string, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) {
|
||||||
|
var _p0 *uint16
|
||||||
|
_p0, err = syscall.UTF16PtrFromString(accountName)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return _lookupAccountName(systemName, _p0, sid, sidSize, refDomain, refDomainSize, sidNameUse)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _lookupAccountName(systemName *uint16, accountName *uint16, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) {
|
||||||
|
r1, _, e1 := syscall.Syscall9(procLookupAccountNameW.Addr(), 7, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(accountName)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(sidSize)), uintptr(unsafe.Pointer(refDomain)), uintptr(unsafe.Pointer(refDomainSize)), uintptr(unsafe.Pointer(sidNameUse)), 0, 0)
|
||||||
|
if r1 == 0 {
|
||||||
|
if e1 != 0 {
|
||||||
|
err = errnoErr(e1)
|
||||||
|
} else {
|
||||||
|
err = syscall.EINVAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertSidToStringSid(sid *byte, str **uint16) (err error) {
|
||||||
|
r1, _, e1 := syscall.Syscall(procConvertSidToStringSidW.Addr(), 2, uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(str)), 0)
|
||||||
|
if r1 == 0 {
|
||||||
|
if e1 != 0 {
|
||||||
|
err = errnoErr(e1)
|
||||||
|
} else {
|
||||||
|
err = syscall.EINVAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertStringSecurityDescriptorToSecurityDescriptor(str string, revision uint32, sd *uintptr, size *uint32) (err error) {
|
||||||
|
var _p0 *uint16
|
||||||
|
_p0, err = syscall.UTF16PtrFromString(str)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return _convertStringSecurityDescriptorToSecurityDescriptor(_p0, revision, sd, size)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _convertStringSecurityDescriptorToSecurityDescriptor(str *uint16, revision uint32, sd *uintptr, size *uint32) (err error) {
|
||||||
|
r1, _, e1 := syscall.Syscall6(procConvertStringSecurityDescriptorToSecurityDescriptorW.Addr(), 4, uintptr(unsafe.Pointer(str)), uintptr(revision), uintptr(unsafe.Pointer(sd)), uintptr(unsafe.Pointer(size)), 0, 0)
|
||||||
|
if r1 == 0 {
|
||||||
|
if e1 != 0 {
|
||||||
|
err = errnoErr(e1)
|
||||||
|
} else {
|
||||||
|
err = syscall.EINVAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertSecurityDescriptorToStringSecurityDescriptor(sd *byte, revision uint32, secInfo uint32, sddl **uint16, sddlSize *uint32) (err error) {
|
||||||
|
r1, _, e1 := syscall.Syscall6(procConvertSecurityDescriptorToStringSecurityDescriptorW.Addr(), 5, uintptr(unsafe.Pointer(sd)), uintptr(revision), uintptr(secInfo), uintptr(unsafe.Pointer(sddl)), uintptr(unsafe.Pointer(sddlSize)), 0)
|
||||||
|
if r1 == 0 {
|
||||||
|
if e1 != 0 {
|
||||||
|
err = errnoErr(e1)
|
||||||
|
} else {
|
||||||
|
err = syscall.EINVAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func localFree(mem uintptr) {
|
||||||
|
syscall.Syscall(procLocalFree.Addr(), 1, uintptr(mem), 0, 0)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func getSecurityDescriptorLength(sd uintptr) (len uint32) {
|
||||||
|
r0, _, _ := syscall.Syscall(procGetSecurityDescriptorLength.Addr(), 1, uintptr(sd), 0, 0)
|
||||||
|
len = uint32(r0)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func getFileInformationByHandleEx(h syscall.Handle, class uint32, buffer *byte, size uint32) (err error) {
|
||||||
|
r1, _, e1 := syscall.Syscall6(procGetFileInformationByHandleEx.Addr(), 4, uintptr(h), uintptr(class), uintptr(unsafe.Pointer(buffer)), uintptr(size), 0, 0)
|
||||||
|
if r1 == 0 {
|
||||||
|
if e1 != 0 {
|
||||||
|
err = errnoErr(e1)
|
||||||
|
} else {
|
||||||
|
err = syscall.EINVAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func setFileInformationByHandle(h syscall.Handle, class uint32, buffer *byte, size uint32) (err error) {
|
||||||
|
r1, _, e1 := syscall.Syscall6(procSetFileInformationByHandle.Addr(), 4, uintptr(h), uintptr(class), uintptr(unsafe.Pointer(buffer)), uintptr(size), 0, 0)
|
||||||
|
if r1 == 0 {
|
||||||
|
if e1 != 0 {
|
||||||
|
err = errnoErr(e1)
|
||||||
|
} else {
|
||||||
|
err = syscall.EINVAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func adjustTokenPrivileges(token windows.Token, releaseAll bool, input *byte, outputSize uint32, output *byte, requiredSize *uint32) (success bool, err error) {
|
||||||
|
var _p0 uint32
|
||||||
|
if releaseAll {
|
||||||
|
_p0 = 1
|
||||||
|
} else {
|
||||||
|
_p0 = 0
|
||||||
|
}
|
||||||
|
r0, _, e1 := syscall.Syscall6(procAdjustTokenPrivileges.Addr(), 6, uintptr(token), uintptr(_p0), uintptr(unsafe.Pointer(input)), uintptr(outputSize), uintptr(unsafe.Pointer(output)), uintptr(unsafe.Pointer(requiredSize)))
|
||||||
|
success = r0 != 0
|
||||||
|
if true {
|
||||||
|
if e1 != 0 {
|
||||||
|
err = errnoErr(e1)
|
||||||
|
} else {
|
||||||
|
err = syscall.EINVAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func impersonateSelf(level uint32) (err error) {
|
||||||
|
r1, _, e1 := syscall.Syscall(procImpersonateSelf.Addr(), 1, uintptr(level), 0, 0)
|
||||||
|
if r1 == 0 {
|
||||||
|
if e1 != 0 {
|
||||||
|
err = errnoErr(e1)
|
||||||
|
} else {
|
||||||
|
err = syscall.EINVAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func revertToSelf() (err error) {
|
||||||
|
r1, _, e1 := syscall.Syscall(procRevertToSelf.Addr(), 0, 0, 0, 0)
|
||||||
|
if r1 == 0 {
|
||||||
|
if e1 != 0 {
|
||||||
|
err = errnoErr(e1)
|
||||||
|
} else {
|
||||||
|
err = syscall.EINVAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func openThreadToken(thread syscall.Handle, accessMask uint32, openAsSelf bool, token *windows.Token) (err error) {
|
||||||
|
var _p0 uint32
|
||||||
|
if openAsSelf {
|
||||||
|
_p0 = 1
|
||||||
|
} else {
|
||||||
|
_p0 = 0
|
||||||
|
}
|
||||||
|
r1, _, e1 := syscall.Syscall6(procOpenThreadToken.Addr(), 4, uintptr(thread), uintptr(accessMask), uintptr(_p0), uintptr(unsafe.Pointer(token)), 0, 0)
|
||||||
|
if r1 == 0 {
|
||||||
|
if e1 != 0 {
|
||||||
|
err = errnoErr(e1)
|
||||||
|
} else {
|
||||||
|
err = syscall.EINVAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func getCurrentThread() (h syscall.Handle) {
|
||||||
|
r0, _, _ := syscall.Syscall(procGetCurrentThread.Addr(), 0, 0, 0, 0)
|
||||||
|
h = syscall.Handle(r0)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func lookupPrivilegeValue(systemName string, name string, luid *uint64) (err error) {
|
||||||
|
var _p0 *uint16
|
||||||
|
_p0, err = syscall.UTF16PtrFromString(systemName)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var _p1 *uint16
|
||||||
|
_p1, err = syscall.UTF16PtrFromString(name)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return _lookupPrivilegeValue(_p0, _p1, luid)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _lookupPrivilegeValue(systemName *uint16, name *uint16, luid *uint64) (err error) {
|
||||||
|
r1, _, e1 := syscall.Syscall(procLookupPrivilegeValueW.Addr(), 3, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(luid)))
|
||||||
|
if r1 == 0 {
|
||||||
|
if e1 != 0 {
|
||||||
|
err = errnoErr(e1)
|
||||||
|
} else {
|
||||||
|
err = syscall.EINVAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func lookupPrivilegeName(systemName string, luid *uint64, buffer *uint16, size *uint32) (err error) {
|
||||||
|
var _p0 *uint16
|
||||||
|
_p0, err = syscall.UTF16PtrFromString(systemName)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return _lookupPrivilegeName(_p0, luid, buffer, size)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _lookupPrivilegeName(systemName *uint16, luid *uint64, buffer *uint16, size *uint32) (err error) {
|
||||||
|
r1, _, e1 := syscall.Syscall6(procLookupPrivilegeNameW.Addr(), 4, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(luid)), uintptr(unsafe.Pointer(buffer)), uintptr(unsafe.Pointer(size)), 0, 0)
|
||||||
|
if r1 == 0 {
|
||||||
|
if e1 != 0 {
|
||||||
|
err = errnoErr(e1)
|
||||||
|
} else {
|
||||||
|
err = syscall.EINVAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func lookupPrivilegeDisplayName(systemName string, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) {
|
||||||
|
var _p0 *uint16
|
||||||
|
_p0, err = syscall.UTF16PtrFromString(systemName)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return _lookupPrivilegeDisplayName(_p0, name, buffer, size, languageId)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _lookupPrivilegeDisplayName(systemName *uint16, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) {
|
||||||
|
r1, _, e1 := syscall.Syscall6(procLookupPrivilegeDisplayNameW.Addr(), 5, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(buffer)), uintptr(unsafe.Pointer(size)), uintptr(unsafe.Pointer(languageId)), 0)
|
||||||
|
if r1 == 0 {
|
||||||
|
if e1 != 0 {
|
||||||
|
err = errnoErr(e1)
|
||||||
|
} else {
|
||||||
|
err = syscall.EINVAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func backupRead(h syscall.Handle, b []byte, bytesRead *uint32, abort bool, processSecurity bool, context *uintptr) (err error) {
|
||||||
|
var _p0 *byte
|
||||||
|
if len(b) > 0 {
|
||||||
|
_p0 = &b[0]
|
||||||
|
}
|
||||||
|
var _p1 uint32
|
||||||
|
if abort {
|
||||||
|
_p1 = 1
|
||||||
|
} else {
|
||||||
|
_p1 = 0
|
||||||
|
}
|
||||||
|
var _p2 uint32
|
||||||
|
if processSecurity {
|
||||||
|
_p2 = 1
|
||||||
|
} else {
|
||||||
|
_p2 = 0
|
||||||
|
}
|
||||||
|
r1, _, e1 := syscall.Syscall9(procBackupRead.Addr(), 7, uintptr(h), uintptr(unsafe.Pointer(_p0)), uintptr(len(b)), uintptr(unsafe.Pointer(bytesRead)), uintptr(_p1), uintptr(_p2), uintptr(unsafe.Pointer(context)), 0, 0)
|
||||||
|
if r1 == 0 {
|
||||||
|
if e1 != 0 {
|
||||||
|
err = errnoErr(e1)
|
||||||
|
} else {
|
||||||
|
err = syscall.EINVAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func backupWrite(h syscall.Handle, b []byte, bytesWritten *uint32, abort bool, processSecurity bool, context *uintptr) (err error) {
|
||||||
|
var _p0 *byte
|
||||||
|
if len(b) > 0 {
|
||||||
|
_p0 = &b[0]
|
||||||
|
}
|
||||||
|
var _p1 uint32
|
||||||
|
if abort {
|
||||||
|
_p1 = 1
|
||||||
|
} else {
|
||||||
|
_p1 = 0
|
||||||
|
}
|
||||||
|
var _p2 uint32
|
||||||
|
if processSecurity {
|
||||||
|
_p2 = 1
|
||||||
|
} else {
|
||||||
|
_p2 = 0
|
||||||
|
}
|
||||||
|
r1, _, e1 := syscall.Syscall9(procBackupWrite.Addr(), 7, uintptr(h), uintptr(unsafe.Pointer(_p0)), uintptr(len(b)), uintptr(unsafe.Pointer(bytesWritten)), uintptr(_p1), uintptr(_p2), uintptr(unsafe.Pointer(context)), 0, 0)
|
||||||
|
if r1 == 0 {
|
||||||
|
if e1 != 0 {
|
||||||
|
err = errnoErr(e1)
|
||||||
|
} else {
|
||||||
|
err = syscall.EINVAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
1
vendor/github.com/Microsoft/hcsshim/.gitignore
generated
vendored
Normal file
1
vendor/github.com/Microsoft/hcsshim/.gitignore
generated
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
*.exe
|
17
vendor/github.com/Microsoft/hcsshim/.gometalinter.json
generated
vendored
Normal file
17
vendor/github.com/Microsoft/hcsshim/.gometalinter.json
generated
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"Vendor": true,
|
||||||
|
"Deadline": "2m",
|
||||||
|
"Sort": [
|
||||||
|
"linter",
|
||||||
|
"severity",
|
||||||
|
"path",
|
||||||
|
"line"
|
||||||
|
],
|
||||||
|
"Skip": [
|
||||||
|
"internal\\schema2"
|
||||||
|
],
|
||||||
|
"EnableGC": true,
|
||||||
|
"Enable": [
|
||||||
|
"gofmt"
|
||||||
|
]
|
||||||
|
}
|
21
vendor/github.com/Microsoft/hcsshim/LICENSE
generated
vendored
Normal file
21
vendor/github.com/Microsoft/hcsshim/LICENSE
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2015 Microsoft
|
||||||
|
|
||||||
|
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.
|
41
vendor/github.com/Microsoft/hcsshim/README.md
generated
vendored
Normal file
41
vendor/github.com/Microsoft/hcsshim/README.md
generated
vendored
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
# hcsshim
|
||||||
|
|
||||||
|
[![Build status](https://ci.appveyor.com/api/projects/status/nbcw28mnkqml0loa/branch/master?svg=true)](https://ci.appveyor.com/project/WindowsVirtualization/hcsshim/branch/master)
|
||||||
|
|
||||||
|
This package contains the Golang interface for using the Windows [Host Compute Service](https://blogs.technet.microsoft.com/virtualization/2017/01/27/introducing-the-host-compute-service-hcs/) (HCS) to launch and manage [Windows Containers](https://docs.microsoft.com/en-us/virtualization/windowscontainers/about/). It also contains other helpers and functions for managing Windows Containers such as the Golang interface for the Host Network Service (HNS).
|
||||||
|
|
||||||
|
It is primarily used in the [Moby Project](https://github.com/moby/moby), but it can be freely used by other projects as well.
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
This project welcomes contributions and suggestions. Most contributions require you to agree to a
|
||||||
|
Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
|
||||||
|
the rights to use your contribution. For details, visit https://cla.microsoft.com.
|
||||||
|
|
||||||
|
When you submit a pull request, a CLA-bot will automatically determine whether you need to provide
|
||||||
|
a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions
|
||||||
|
provided by the bot. You will only need to do this once across all repos using our CLA.
|
||||||
|
|
||||||
|
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
|
||||||
|
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
|
||||||
|
contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
|
||||||
|
This project requires Golang 1.9 or newer to build.
|
||||||
|
|
||||||
|
For system requirements to run this project, see the Microsoft docs on [Windows Container requirements](https://docs.microsoft.com/en-us/virtualization/windowscontainers/deploy-containers/system-requirements).
|
||||||
|
|
||||||
|
## Reporting Security Issues
|
||||||
|
|
||||||
|
Security issues and bugs should be reported privately, via email, to the Microsoft Security
|
||||||
|
Response Center (MSRC) at [secure@microsoft.com](mailto:secure@microsoft.com). You should
|
||||||
|
receive a response within 24 hours. If for some reason you do not, please follow up via
|
||||||
|
email to ensure we received your original message. Further information, including the
|
||||||
|
[MSRC PGP](https://technet.microsoft.com/en-us/security/dn606155) key, can be found in
|
||||||
|
the [Security TechCenter](https://technet.microsoft.com/en-us/security/default).
|
||||||
|
|
||||||
|
For additional details, see [Report a Computer Security Vulnerability](https://technet.microsoft.com/en-us/security/ff852094.aspx) on Technet
|
||||||
|
|
||||||
|
---------------
|
||||||
|
Copyright (c) 2018 Microsoft Corp. All rights reserved.
|
28
vendor/github.com/Microsoft/hcsshim/appveyor.yml
generated
vendored
Normal file
28
vendor/github.com/Microsoft/hcsshim/appveyor.yml
generated
vendored
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
version: 0.1.{build}
|
||||||
|
|
||||||
|
image: Visual Studio 2017
|
||||||
|
|
||||||
|
clone_folder: c:\gopath\src\github.com\Microsoft\hcsshim
|
||||||
|
|
||||||
|
environment:
|
||||||
|
GOPATH: c:\gopath
|
||||||
|
PATH: C:\mingw-w64\x86_64-7.2.0-posix-seh-rt_v5-rev1\mingw64\bin;%GOPATH%\bin;%PATH%
|
||||||
|
|
||||||
|
build_script:
|
||||||
|
- go get -u github.com/alecthomas/gometalinter
|
||||||
|
- gometalinter.exe --install
|
||||||
|
- gometalinter.exe --config .gometalinter.json ./...
|
||||||
|
- go get -v -d -t -tags "functional integration admin" ./...
|
||||||
|
- go build ./cmd/wclayer
|
||||||
|
- go build ./cmd/runhcs
|
||||||
|
- go test -c ./pkg/go-runhcs/ -tags integration
|
||||||
|
- go build ./cmd/tar2ext4
|
||||||
|
- go test -v ./... -tags admin
|
||||||
|
- go test -c ./functional/ -tags functional
|
||||||
|
|
||||||
|
artifacts:
|
||||||
|
- path: 'wclayer.exe'
|
||||||
|
- path: 'runhcs.exe'
|
||||||
|
- path: 'go-runhcs.test.exe'
|
||||||
|
- path: 'tar2ext4.exe'
|
||||||
|
- path: 'functional.test.exe'
|
192
vendor/github.com/Microsoft/hcsshim/container.go
generated
vendored
Normal file
192
vendor/github.com/Microsoft/hcsshim/container.go
generated
vendored
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
package hcsshim
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/Microsoft/hcsshim/internal/hcs"
|
||||||
|
"github.com/Microsoft/hcsshim/internal/mergemaps"
|
||||||
|
"github.com/Microsoft/hcsshim/internal/schema1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ContainerProperties holds the properties for a container and the processes running in that container
|
||||||
|
type ContainerProperties = schema1.ContainerProperties
|
||||||
|
|
||||||
|
// MemoryStats holds the memory statistics for a container
|
||||||
|
type MemoryStats = schema1.MemoryStats
|
||||||
|
|
||||||
|
// ProcessorStats holds the processor statistics for a container
|
||||||
|
type ProcessorStats = schema1.ProcessorStats
|
||||||
|
|
||||||
|
// StorageStats holds the storage statistics for a container
|
||||||
|
type StorageStats = schema1.StorageStats
|
||||||
|
|
||||||
|
// NetworkStats holds the network statistics for a container
|
||||||
|
type NetworkStats = schema1.NetworkStats
|
||||||
|
|
||||||
|
// Statistics is the structure returned by a statistics call on a container
|
||||||
|
type Statistics = schema1.Statistics
|
||||||
|
|
||||||
|
// ProcessList is the structure of an item returned by a ProcessList call on a container
|
||||||
|
type ProcessListItem = schema1.ProcessListItem
|
||||||
|
|
||||||
|
// MappedVirtualDiskController is the structure of an item returned by a MappedVirtualDiskList call on a container
|
||||||
|
type MappedVirtualDiskController = schema1.MappedVirtualDiskController
|
||||||
|
|
||||||
|
// Type of Request Support in ModifySystem
|
||||||
|
type RequestType = schema1.RequestType
|
||||||
|
|
||||||
|
// Type of Resource Support in ModifySystem
|
||||||
|
type ResourceType = schema1.ResourceType
|
||||||
|
|
||||||
|
// RequestType const
|
||||||
|
const (
|
||||||
|
Add = schema1.Add
|
||||||
|
Remove = schema1.Remove
|
||||||
|
Network = schema1.Network
|
||||||
|
)
|
||||||
|
|
||||||
|
// ResourceModificationRequestResponse is the structure used to send request to the container to modify the system
|
||||||
|
// Supported resource types are Network and Request Types are Add/Remove
|
||||||
|
type ResourceModificationRequestResponse = schema1.ResourceModificationRequestResponse
|
||||||
|
|
||||||
|
type container struct {
|
||||||
|
system *hcs.System
|
||||||
|
}
|
||||||
|
|
||||||
|
// createComputeSystemAdditionalJSON is read from the environment at initialisation
|
||||||
|
// time. It allows an environment variable to define additional JSON which
|
||||||
|
// is merged in the CreateComputeSystem call to HCS.
|
||||||
|
var createContainerAdditionalJSON []byte
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
createContainerAdditionalJSON = ([]byte)(os.Getenv("HCSSHIM_CREATECONTAINER_ADDITIONALJSON"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateContainer creates a new container with the given configuration but does not start it.
|
||||||
|
func CreateContainer(id string, c *ContainerConfig) (Container, error) {
|
||||||
|
fullConfig, err := mergemaps.MergeJSON(c, createContainerAdditionalJSON)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to merge additional JSON '%s': %s", createContainerAdditionalJSON, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
system, err := hcs.CreateComputeSystem(id, fullConfig)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &container{system}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// OpenContainer opens an existing container by ID.
|
||||||
|
func OpenContainer(id string) (Container, error) {
|
||||||
|
system, err := hcs.OpenComputeSystem(id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &container{system}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetContainers gets a list of the containers on the system that match the query
|
||||||
|
func GetContainers(q ComputeSystemQuery) ([]ContainerProperties, error) {
|
||||||
|
return hcs.GetComputeSystems(q)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start synchronously starts the container.
|
||||||
|
func (container *container) Start() error {
|
||||||
|
return convertSystemError(container.system.Start(), container)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shutdown requests a container shutdown, but it may not actually be shutdown until Wait() succeeds.
|
||||||
|
func (container *container) Shutdown() error {
|
||||||
|
return convertSystemError(container.system.Shutdown(), container)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Terminate requests a container terminate, but it may not actually be terminated until Wait() succeeds.
|
||||||
|
func (container *container) Terminate() error {
|
||||||
|
return convertSystemError(container.system.Terminate(), container)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Waits synchronously waits for the container to shutdown or terminate.
|
||||||
|
func (container *container) Wait() error {
|
||||||
|
return convertSystemError(container.system.Wait(), container)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WaitTimeout synchronously waits for the container to terminate or the duration to elapse. It
|
||||||
|
// returns false if timeout occurs.
|
||||||
|
func (container *container) WaitTimeout(t time.Duration) error {
|
||||||
|
return convertSystemError(container.system.WaitTimeout(t), container)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pause pauses the execution of a container.
|
||||||
|
func (container *container) Pause() error {
|
||||||
|
return convertSystemError(container.system.Pause(), container)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resume resumes the execution of a container.
|
||||||
|
func (container *container) Resume() error {
|
||||||
|
return convertSystemError(container.system.Resume(), container)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasPendingUpdates returns true if the container has updates pending to install
|
||||||
|
func (container *container) HasPendingUpdates() (bool, error) {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Statistics returns statistics for the container. This is a legacy v1 call
|
||||||
|
func (container *container) Statistics() (Statistics, error) {
|
||||||
|
properties, err := container.system.Properties(schema1.PropertyTypeStatistics)
|
||||||
|
if err != nil {
|
||||||
|
return Statistics{}, convertSystemError(err, container)
|
||||||
|
}
|
||||||
|
|
||||||
|
return properties.Statistics, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProcessList returns an array of ProcessListItems for the container. This is a legacy v1 call
|
||||||
|
func (container *container) ProcessList() ([]ProcessListItem, error) {
|
||||||
|
properties, err := container.system.Properties(schema1.PropertyTypeProcessList)
|
||||||
|
if err != nil {
|
||||||
|
return nil, convertSystemError(err, container)
|
||||||
|
}
|
||||||
|
|
||||||
|
return properties.ProcessList, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is a legacy v1 call
|
||||||
|
func (container *container) MappedVirtualDisks() (map[int]MappedVirtualDiskController, error) {
|
||||||
|
properties, err := container.system.Properties(schema1.PropertyTypeMappedVirtualDisk)
|
||||||
|
if err != nil {
|
||||||
|
return nil, convertSystemError(err, container)
|
||||||
|
}
|
||||||
|
|
||||||
|
return properties.MappedVirtualDiskControllers, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateProcess launches a new process within the container.
|
||||||
|
func (container *container) CreateProcess(c *ProcessConfig) (Process, error) {
|
||||||
|
p, err := container.system.CreateProcess(c)
|
||||||
|
if err != nil {
|
||||||
|
return nil, convertSystemError(err, container)
|
||||||
|
}
|
||||||
|
return &process{p}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// OpenProcess gets an interface to an existing process within the container.
|
||||||
|
func (container *container) OpenProcess(pid int) (Process, error) {
|
||||||
|
p, err := container.system.OpenProcess(pid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, convertSystemError(err, container)
|
||||||
|
}
|
||||||
|
return &process{p}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close cleans up any state associated with the container but does not terminate or wait for it.
|
||||||
|
func (container *container) Close() error {
|
||||||
|
return convertSystemError(container.system.Close(), container)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Modify the System
|
||||||
|
func (container *container) Modify(config *ResourceModificationRequestResponse) error {
|
||||||
|
return convertSystemError(container.system.Modify(config), container)
|
||||||
|
}
|
257
vendor/github.com/Microsoft/hcsshim/errors.go
generated
vendored
Normal file
257
vendor/github.com/Microsoft/hcsshim/errors.go
generated
vendored
Normal file
@ -0,0 +1,257 @@
|
|||||||
|
package hcsshim
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/Microsoft/hcsshim/internal/hns"
|
||||||
|
|
||||||
|
"github.com/Microsoft/hcsshim/internal/hcs"
|
||||||
|
"github.com/Microsoft/hcsshim/internal/hcserror"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// ErrComputeSystemDoesNotExist is an error encountered when the container being operated on no longer exists = hcs.exist
|
||||||
|
ErrComputeSystemDoesNotExist = hcs.ErrComputeSystemDoesNotExist
|
||||||
|
|
||||||
|
// ErrElementNotFound is an error encountered when the object being referenced does not exist
|
||||||
|
ErrElementNotFound = hcs.ErrElementNotFound
|
||||||
|
|
||||||
|
// ErrElementNotFound is an error encountered when the object being referenced does not exist
|
||||||
|
ErrNotSupported = hcs.ErrNotSupported
|
||||||
|
|
||||||
|
// ErrInvalidData is an error encountered when the request being sent to hcs is invalid/unsupported
|
||||||
|
// decimal -2147024883 / hex 0x8007000d
|
||||||
|
ErrInvalidData = hcs.ErrInvalidData
|
||||||
|
|
||||||
|
// ErrHandleClose is an error encountered when the handle generating the notification being waited on has been closed
|
||||||
|
ErrHandleClose = hcs.ErrHandleClose
|
||||||
|
|
||||||
|
// ErrAlreadyClosed is an error encountered when using a handle that has been closed by the Close method
|
||||||
|
ErrAlreadyClosed = hcs.ErrAlreadyClosed
|
||||||
|
|
||||||
|
// ErrInvalidNotificationType is an error encountered when an invalid notification type is used
|
||||||
|
ErrInvalidNotificationType = hcs.ErrInvalidNotificationType
|
||||||
|
|
||||||
|
// ErrInvalidProcessState is an error encountered when the process is not in a valid state for the requested operation
|
||||||
|
ErrInvalidProcessState = hcs.ErrInvalidProcessState
|
||||||
|
|
||||||
|
// ErrTimeout is an error encountered when waiting on a notification times out
|
||||||
|
ErrTimeout = hcs.ErrTimeout
|
||||||
|
|
||||||
|
// ErrUnexpectedContainerExit is the error encountered when a container exits while waiting for
|
||||||
|
// a different expected notification
|
||||||
|
ErrUnexpectedContainerExit = hcs.ErrUnexpectedContainerExit
|
||||||
|
|
||||||
|
// ErrUnexpectedProcessAbort is the error encountered when communication with the compute service
|
||||||
|
// is lost while waiting for a notification
|
||||||
|
ErrUnexpectedProcessAbort = hcs.ErrUnexpectedProcessAbort
|
||||||
|
|
||||||
|
// ErrUnexpectedValue is an error encountered when hcs returns an invalid value
|
||||||
|
ErrUnexpectedValue = hcs.ErrUnexpectedValue
|
||||||
|
|
||||||
|
// ErrVmcomputeAlreadyStopped is an error encountered when a shutdown or terminate request is made on a stopped container
|
||||||
|
ErrVmcomputeAlreadyStopped = hcs.ErrVmcomputeAlreadyStopped
|
||||||
|
|
||||||
|
// ErrVmcomputeOperationPending is an error encountered when the operation is being completed asynchronously
|
||||||
|
ErrVmcomputeOperationPending = hcs.ErrVmcomputeOperationPending
|
||||||
|
|
||||||
|
// ErrVmcomputeOperationInvalidState is an error encountered when the compute system is not in a valid state for the requested operation
|
||||||
|
ErrVmcomputeOperationInvalidState = hcs.ErrVmcomputeOperationInvalidState
|
||||||
|
|
||||||
|
// ErrProcNotFound is an error encountered when the the process cannot be found
|
||||||
|
ErrProcNotFound = hcs.ErrProcNotFound
|
||||||
|
|
||||||
|
// ErrVmcomputeOperationAccessIsDenied is an error which can be encountered when enumerating compute systems in RS1/RS2
|
||||||
|
// builds when the underlying silo might be in the process of terminating. HCS was fixed in RS3.
|
||||||
|
ErrVmcomputeOperationAccessIsDenied = hcs.ErrVmcomputeOperationAccessIsDenied
|
||||||
|
|
||||||
|
// ErrVmcomputeInvalidJSON is an error encountered when the compute system does not support/understand the messages sent by management
|
||||||
|
ErrVmcomputeInvalidJSON = hcs.ErrVmcomputeInvalidJSON
|
||||||
|
|
||||||
|
// ErrVmcomputeUnknownMessage is an error encountered guest compute system doesn't support the message
|
||||||
|
ErrVmcomputeUnknownMessage = hcs.ErrVmcomputeUnknownMessage
|
||||||
|
|
||||||
|
// ErrNotSupported is an error encountered when hcs doesn't support the request
|
||||||
|
ErrPlatformNotSupported = hcs.ErrPlatformNotSupported
|
||||||
|
)
|
||||||
|
|
||||||
|
type EndpointNotFoundError = hns.EndpointNotFoundError
|
||||||
|
type NetworkNotFoundError = hns.NetworkNotFoundError
|
||||||
|
|
||||||
|
// ProcessError is an error encountered in HCS during an operation on a Process object
|
||||||
|
type ProcessError struct {
|
||||||
|
Process *process
|
||||||
|
Operation string
|
||||||
|
ExtraInfo string
|
||||||
|
Err error
|
||||||
|
Events []hcs.ErrorEvent
|
||||||
|
}
|
||||||
|
|
||||||
|
// ContainerError is an error encountered in HCS during an operation on a Container object
|
||||||
|
type ContainerError struct {
|
||||||
|
Container *container
|
||||||
|
Operation string
|
||||||
|
ExtraInfo string
|
||||||
|
Err error
|
||||||
|
Events []hcs.ErrorEvent
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *ContainerError) Error() string {
|
||||||
|
if e == nil {
|
||||||
|
return "<nil>"
|
||||||
|
}
|
||||||
|
|
||||||
|
if e.Container == nil {
|
||||||
|
return "unexpected nil container for error: " + e.Err.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
s := "container " + e.Container.system.ID()
|
||||||
|
|
||||||
|
if e.Operation != "" {
|
||||||
|
s += " encountered an error during " + e.Operation
|
||||||
|
}
|
||||||
|
|
||||||
|
switch e.Err.(type) {
|
||||||
|
case nil:
|
||||||
|
break
|
||||||
|
case syscall.Errno:
|
||||||
|
s += fmt.Sprintf(": failure in a Windows system call: %s (0x%x)", e.Err, hcserror.Win32FromError(e.Err))
|
||||||
|
default:
|
||||||
|
s += fmt.Sprintf(": %s", e.Err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, ev := range e.Events {
|
||||||
|
s += "\n" + ev.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
if e.ExtraInfo != "" {
|
||||||
|
s += " extra info: " + e.ExtraInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeContainerError(container *container, operation string, extraInfo string, err error) error {
|
||||||
|
// Don't double wrap errors
|
||||||
|
if _, ok := err.(*ContainerError); ok {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
containerError := &ContainerError{Container: container, Operation: operation, ExtraInfo: extraInfo, Err: err}
|
||||||
|
return containerError
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *ProcessError) Error() string {
|
||||||
|
if e == nil {
|
||||||
|
return "<nil>"
|
||||||
|
}
|
||||||
|
|
||||||
|
if e.Process == nil {
|
||||||
|
return "Unexpected nil process for error: " + e.Err.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
s := fmt.Sprintf("process %d in container %s", e.Process.p.Pid(), e.Process.p.SystemID())
|
||||||
|
if e.Operation != "" {
|
||||||
|
s += " encountered an error during " + e.Operation
|
||||||
|
}
|
||||||
|
|
||||||
|
switch e.Err.(type) {
|
||||||
|
case nil:
|
||||||
|
break
|
||||||
|
case syscall.Errno:
|
||||||
|
s += fmt.Sprintf(": failure in a Windows system call: %s (0x%x)", e.Err, hcserror.Win32FromError(e.Err))
|
||||||
|
default:
|
||||||
|
s += fmt.Sprintf(": %s", e.Err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, ev := range e.Events {
|
||||||
|
s += "\n" + ev.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeProcessError(process *process, operation string, extraInfo string, err error) error {
|
||||||
|
// Don't double wrap errors
|
||||||
|
if _, ok := err.(*ProcessError); ok {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
processError := &ProcessError{Process: process, Operation: operation, ExtraInfo: extraInfo, Err: err}
|
||||||
|
return processError
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsNotExist checks if an error is caused by the Container or Process not existing.
|
||||||
|
// Note: Currently, ErrElementNotFound can mean that a Process has either
|
||||||
|
// already exited, or does not exist. Both IsAlreadyStopped and IsNotExist
|
||||||
|
// will currently return true when the error is ErrElementNotFound or ErrProcNotFound.
|
||||||
|
func IsNotExist(err error) bool {
|
||||||
|
if _, ok := err.(EndpointNotFoundError); ok {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if _, ok := err.(NetworkNotFoundError); ok {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return hcs.IsNotExist(getInnerError(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsAlreadyClosed checks if an error is caused by the Container or Process having been
|
||||||
|
// already closed by a call to the Close() method.
|
||||||
|
func IsAlreadyClosed(err error) bool {
|
||||||
|
return hcs.IsAlreadyClosed(getInnerError(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsPending returns a boolean indicating whether the error is that
|
||||||
|
// the requested operation is being completed in the background.
|
||||||
|
func IsPending(err error) bool {
|
||||||
|
return hcs.IsPending(getInnerError(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsTimeout returns a boolean indicating whether the error is caused by
|
||||||
|
// a timeout waiting for the operation to complete.
|
||||||
|
func IsTimeout(err error) bool {
|
||||||
|
return hcs.IsTimeout(getInnerError(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsAlreadyStopped returns a boolean indicating whether the error is caused by
|
||||||
|
// a Container or Process being already stopped.
|
||||||
|
// Note: Currently, ErrElementNotFound can mean that a Process has either
|
||||||
|
// already exited, or does not exist. Both IsAlreadyStopped and IsNotExist
|
||||||
|
// will currently return true when the error is ErrElementNotFound or ErrProcNotFound.
|
||||||
|
func IsAlreadyStopped(err error) bool {
|
||||||
|
return hcs.IsAlreadyStopped(getInnerError(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsNotSupported returns a boolean indicating whether the error is caused by
|
||||||
|
// unsupported platform requests
|
||||||
|
// Note: Currently Unsupported platform requests can be mean either
|
||||||
|
// ErrVmcomputeInvalidJSON, ErrInvalidData, ErrNotSupported or ErrVmcomputeUnknownMessage
|
||||||
|
// is thrown from the Platform
|
||||||
|
func IsNotSupported(err error) bool {
|
||||||
|
return hcs.IsNotSupported(getInnerError(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
func getInnerError(err error) error {
|
||||||
|
switch pe := err.(type) {
|
||||||
|
case nil:
|
||||||
|
return nil
|
||||||
|
case *ContainerError:
|
||||||
|
err = pe.Err
|
||||||
|
case *ProcessError:
|
||||||
|
err = pe.Err
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertSystemError(err error, c *container) error {
|
||||||
|
if serr, ok := err.(*hcs.SystemError); ok {
|
||||||
|
return &ContainerError{Container: c, Operation: serr.Op, ExtraInfo: serr.Extra, Err: serr.Err, Events: serr.Events}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertProcessError(err error, p *process) error {
|
||||||
|
if perr, ok := err.(*hcs.ProcessError); ok {
|
||||||
|
return &ProcessError{Process: p, Operation: perr.Op, Err: perr.Err, Events: perr.Events}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
12
vendor/github.com/Microsoft/hcsshim/functional_tests.ps1
generated
vendored
Normal file
12
vendor/github.com/Microsoft/hcsshim/functional_tests.ps1
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# Requirements so far:
|
||||||
|
# dockerd running
|
||||||
|
# - image microsoft/nanoserver (matching host base image) docker load -i c:\baseimages\nanoserver.tar
|
||||||
|
# - image alpine (linux) docker pull --platform=linux alpine
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: Add this a parameter for debugging. ie "functional-tests -debug=$true"
|
||||||
|
#$env:HCSSHIM_FUNCTIONAL_TESTS_DEBUG="yes please"
|
||||||
|
|
||||||
|
#pushd uvm
|
||||||
|
go test -v -tags "functional uvmcreate uvmscratch uvmscsi uvmvpmem uvmvsmb uvmp9" ./...
|
||||||
|
#popd
|
150
vendor/github.com/Microsoft/hcsshim/hcn/hcn.go
generated
vendored
Normal file
150
vendor/github.com/Microsoft/hcsshim/hcn/hcn.go
generated
vendored
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
// Package hcn is a shim for the Host Compute Networking (HCN) service, which manages networking for Windows Server
|
||||||
|
// containers and Hyper-V containers. Previous to RS5, HCN was referred to as Host Networking Service (HNS).
|
||||||
|
package hcn
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/Microsoft/hcsshim/internal/guid"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:generate go run ../mksyscall_windows.go -output zsyscall_windows.go hcn.go
|
||||||
|
|
||||||
|
/// HNS V1 API
|
||||||
|
|
||||||
|
//sys SetCurrentThreadCompartmentId(compartmentId uint32) (hr error) = iphlpapi.SetCurrentThreadCompartmentId
|
||||||
|
//sys _hnsCall(method string, path string, object string, response **uint16) (hr error) = vmcompute.HNSCall?
|
||||||
|
|
||||||
|
/// HCN V2 API
|
||||||
|
|
||||||
|
// Network
|
||||||
|
//sys hcnEnumerateNetworks(query string, networks **uint16, result **uint16) (hr error) = computenetwork.HcnEnumerateNetworks?
|
||||||
|
//sys hcnCreateNetwork(id *_guid, settings string, network *hcnNetwork, result **uint16) (hr error) = computenetwork.HcnCreateNetwork?
|
||||||
|
//sys hcnOpenNetwork(id *_guid, network *hcnNetwork, result **uint16) (hr error) = computenetwork.HcnOpenNetwork?
|
||||||
|
//sys hcnModifyNetwork(network hcnNetwork, settings string, result **uint16) (hr error) = computenetwork.HcnModifyNetwork?
|
||||||
|
//sys hcnQueryNetworkProperties(network hcnNetwork, query string, properties **uint16, result **uint16) (hr error) = computenetwork.HcnQueryNetworkProperties?
|
||||||
|
//sys hcnDeleteNetwork(id *_guid, result **uint16) (hr error) = computenetwork.HcnDeleteNetwork?
|
||||||
|
//sys hcnCloseNetwork(network hcnNetwork) (hr error) = computenetwork.HcnCloseNetwork?
|
||||||
|
|
||||||
|
// Endpoint
|
||||||
|
//sys hcnEnumerateEndpoints(query string, endpoints **uint16, result **uint16) (hr error) = computenetwork.HcnEnumerateEndpoints?
|
||||||
|
//sys hcnCreateEndpoint(network hcnNetwork, id *_guid, settings string, endpoint *hcnEndpoint, result **uint16) (hr error) = computenetwork.HcnCreateEndpoint?
|
||||||
|
//sys hcnOpenEndpoint(id *_guid, endpoint *hcnEndpoint, result **uint16) (hr error) = computenetwork.HcnOpenEndpoint?
|
||||||
|
//sys hcnModifyEndpoint(endpoint hcnEndpoint, settings string, result **uint16) (hr error) = computenetwork.HcnModifyEndpoint?
|
||||||
|
//sys hcnQueryEndpointProperties(endpoint hcnEndpoint, query string, properties **uint16, result **uint16) (hr error) = computenetwork.HcnQueryEndpointProperties?
|
||||||
|
//sys hcnDeleteEndpoint(id *_guid, result **uint16) (hr error) = computenetwork.HcnDeleteEndpoint?
|
||||||
|
//sys hcnCloseEndpoint(endpoint hcnEndpoint) (hr error) = computenetwork.HcnCloseEndpoint?
|
||||||
|
|
||||||
|
// Namespace
|
||||||
|
//sys hcnEnumerateNamespaces(query string, namespaces **uint16, result **uint16) (hr error) = computenetwork.HcnEnumerateNamespaces?
|
||||||
|
//sys hcnCreateNamespace(id *_guid, settings string, namespace *hcnNamespace, result **uint16) (hr error) = computenetwork.HcnCreateNamespace?
|
||||||
|
//sys hcnOpenNamespace(id *_guid, namespace *hcnNamespace, result **uint16) (hr error) = computenetwork.HcnOpenNamespace?
|
||||||
|
//sys hcnModifyNamespace(namespace hcnNamespace, settings string, result **uint16) (hr error) = computenetwork.HcnModifyNamespace?
|
||||||
|
//sys hcnQueryNamespaceProperties(namespace hcnNamespace, query string, properties **uint16, result **uint16) (hr error) = computenetwork.HcnQueryNamespaceProperties?
|
||||||
|
//sys hcnDeleteNamespace(id *_guid, result **uint16) (hr error) = computenetwork.HcnDeleteNamespace?
|
||||||
|
//sys hcnCloseNamespace(namespace hcnNamespace) (hr error) = computenetwork.HcnCloseNamespace?
|
||||||
|
|
||||||
|
// LoadBalancer
|
||||||
|
//sys hcnEnumerateLoadBalancers(query string, loadBalancers **uint16, result **uint16) (hr error) = computenetwork.HcnEnumerateLoadBalancers?
|
||||||
|
//sys hcnCreateLoadBalancer(id *_guid, settings string, loadBalancer *hcnLoadBalancer, result **uint16) (hr error) = computenetwork.HcnCreateLoadBalancer?
|
||||||
|
//sys hcnOpenLoadBalancer(id *_guid, loadBalancer *hcnLoadBalancer, result **uint16) (hr error) = computenetwork.HcnOpenLoadBalancer?
|
||||||
|
//sys hcnModifyLoadBalancer(loadBalancer hcnLoadBalancer, settings string, result **uint16) (hr error) = computenetwork.HcnModifyLoadBalancer?
|
||||||
|
//sys hcnQueryLoadBalancerProperties(loadBalancer hcnLoadBalancer, query string, properties **uint16, result **uint16) (hr error) = computenetwork.HcnQueryLoadBalancerProperties?
|
||||||
|
//sys hcnDeleteLoadBalancer(id *_guid, result **uint16) (hr error) = computenetwork.HcnDeleteLoadBalancer?
|
||||||
|
//sys hcnCloseLoadBalancer(loadBalancer hcnLoadBalancer) (hr error) = computenetwork.HcnCloseLoadBalancer?
|
||||||
|
|
||||||
|
// Service
|
||||||
|
//sys hcnOpenService(service *hcnService, result **uint16) (hr error) = computenetwork.HcnOpenService?
|
||||||
|
//sys hcnRegisterServiceCallback(service hcnService, callback int32, context int32, callbackHandle *hcnCallbackHandle) (hr error) = computenetwork.HcnRegisterServiceCallback?
|
||||||
|
//sys hcnUnregisterServiceCallback(callbackHandle hcnCallbackHandle) (hr error) = computenetwork.HcnUnregisterServiceCallback?
|
||||||
|
//sys hcnCloseService(service hcnService) (hr error) = computenetwork.HcnCloseService?
|
||||||
|
|
||||||
|
type _guid = guid.GUID
|
||||||
|
|
||||||
|
type hcnNetwork syscall.Handle
|
||||||
|
type hcnEndpoint syscall.Handle
|
||||||
|
type hcnNamespace syscall.Handle
|
||||||
|
type hcnLoadBalancer syscall.Handle
|
||||||
|
type hcnService syscall.Handle
|
||||||
|
type hcnCallbackHandle syscall.Handle
|
||||||
|
|
||||||
|
// SchemaVersion for HCN Objects/Queries.
|
||||||
|
type SchemaVersion = Version // hcnglobals.go
|
||||||
|
|
||||||
|
// HostComputeQueryFlags are passed in to a HostComputeQuery to determine which
|
||||||
|
// properties of an object are returned.
|
||||||
|
type HostComputeQueryFlags uint32
|
||||||
|
|
||||||
|
var (
|
||||||
|
// HostComputeQueryFlagsNone returns an object with the standard properties.
|
||||||
|
HostComputeQueryFlagsNone HostComputeQueryFlags
|
||||||
|
// HostComputeQueryFlagsDetailed returns an object with all properties.
|
||||||
|
HostComputeQueryFlagsDetailed HostComputeQueryFlags = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
// HostComputeQuery is the format for HCN queries.
|
||||||
|
type HostComputeQuery struct {
|
||||||
|
SchemaVersion SchemaVersion `json:""`
|
||||||
|
Flags HostComputeQueryFlags `json:",omitempty"`
|
||||||
|
Filter string `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// defaultQuery generates HCN Query.
|
||||||
|
// Passed into get/enumerate calls to filter results.
|
||||||
|
func defaultQuery() HostComputeQuery {
|
||||||
|
query := HostComputeQuery{
|
||||||
|
SchemaVersion: SchemaVersion{
|
||||||
|
Major: 2,
|
||||||
|
Minor: 0,
|
||||||
|
},
|
||||||
|
Flags: HostComputeQueryFlagsNone,
|
||||||
|
}
|
||||||
|
return query
|
||||||
|
}
|
||||||
|
|
||||||
|
func defaultQueryJson() string {
|
||||||
|
query := defaultQuery()
|
||||||
|
queryJson, err := json.Marshal(query)
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return string(queryJson)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PlatformDoesNotSupportError happens when users are attempting to use a newer shim on an older OS
|
||||||
|
func platformDoesNotSupportError(featureName string) error {
|
||||||
|
return fmt.Errorf("Platform does not support feature %s", featureName)
|
||||||
|
}
|
||||||
|
|
||||||
|
// V2ApiSupported returns an error if the HCN version does not support the V2 Apis.
|
||||||
|
func V2ApiSupported() error {
|
||||||
|
supported := GetSupportedFeatures()
|
||||||
|
if supported.Api.V2 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return platformDoesNotSupportError("V2 Api/Schema")
|
||||||
|
}
|
||||||
|
|
||||||
|
func V2SchemaVersion() SchemaVersion {
|
||||||
|
return SchemaVersion{
|
||||||
|
Major: 2,
|
||||||
|
Minor: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RequestType are the different operations performed to settings.
|
||||||
|
// Used to update the settings of Endpoint/Namespace objects.
|
||||||
|
type RequestType string
|
||||||
|
|
||||||
|
var (
|
||||||
|
// RequestTypeAdd adds the provided settings object.
|
||||||
|
RequestTypeAdd RequestType = "Add"
|
||||||
|
// RequestTypeRemove removes the provided settings object.
|
||||||
|
RequestTypeRemove RequestType = "Remove"
|
||||||
|
// RequestTypeUpdate replaces settings with the ones provided.
|
||||||
|
RequestTypeUpdate RequestType = "Update"
|
||||||
|
// RequestTypeRefresh refreshes the settings provided.
|
||||||
|
RequestTypeRefresh RequestType = "Refresh"
|
||||||
|
)
|
366
vendor/github.com/Microsoft/hcsshim/hcn/hcnendpoint.go
generated
vendored
Normal file
366
vendor/github.com/Microsoft/hcsshim/hcn/hcnendpoint.go
generated
vendored
Normal file
@ -0,0 +1,366 @@
|
|||||||
|
package hcn
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/Microsoft/hcsshim/internal/guid"
|
||||||
|
"github.com/Microsoft/hcsshim/internal/interop"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// IpConfig is assoicated with an endpoint
|
||||||
|
type IpConfig struct {
|
||||||
|
IpAddress string `json:",omitempty"`
|
||||||
|
PrefixLength uint8 `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// EndpointFlags are special settings on an endpoint.
|
||||||
|
type EndpointFlags uint32
|
||||||
|
|
||||||
|
var (
|
||||||
|
// EndpointFlagsNone is the default.
|
||||||
|
EndpointFlagsNone EndpointFlags
|
||||||
|
// EndpointFlagsRemoteEndpoint means that an endpoint is on another host.
|
||||||
|
EndpointFlagsRemoteEndpoint EndpointFlags = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
// HostComputeEndpoint represents a network endpoint
|
||||||
|
type HostComputeEndpoint struct {
|
||||||
|
Id string `json:"ID,omitempty"`
|
||||||
|
Name string `json:",omitempty"`
|
||||||
|
HostComputeNetwork string `json:",omitempty"` // GUID
|
||||||
|
HostComputeNamespace string `json:",omitempty"` // GUID
|
||||||
|
Policies []EndpointPolicy `json:",omitempty"`
|
||||||
|
IpConfigurations []IpConfig `json:",omitempty"`
|
||||||
|
Dns Dns `json:",omitempty"`
|
||||||
|
Routes []Route `json:",omitempty"`
|
||||||
|
MacAddress string `json:",omitempty"`
|
||||||
|
Flags EndpointFlags `json:",omitempty"`
|
||||||
|
SchemaVersion SchemaVersion `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// EndpointResourceType are the two different Endpoint settings resources.
|
||||||
|
type EndpointResourceType string
|
||||||
|
|
||||||
|
var (
|
||||||
|
// EndpointResourceTypePolicy is for Endpoint Policies. Ex: ACL, NAT
|
||||||
|
EndpointResourceTypePolicy EndpointResourceType = "Policy"
|
||||||
|
// EndpointResourceTypePort is for Endpoint Port settings.
|
||||||
|
EndpointResourceTypePort EndpointResourceType = "Port"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ModifyEndpointSettingRequest is the structure used to send request to modify an endpoint.
|
||||||
|
// Used to update policy/port on an endpoint.
|
||||||
|
type ModifyEndpointSettingRequest struct {
|
||||||
|
ResourceType EndpointResourceType `json:",omitempty"` // Policy, Port
|
||||||
|
RequestType RequestType `json:",omitempty"` // Add, Remove, Update, Refresh
|
||||||
|
Settings json.RawMessage `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PolicyEndpointRequest struct {
|
||||||
|
Policies []EndpointPolicy `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func getEndpoint(endpointGuid guid.GUID, query string) (*HostComputeEndpoint, error) {
|
||||||
|
// Open endpoint.
|
||||||
|
var (
|
||||||
|
endpointHandle hcnEndpoint
|
||||||
|
resultBuffer *uint16
|
||||||
|
propertiesBuffer *uint16
|
||||||
|
)
|
||||||
|
hr := hcnOpenEndpoint(&endpointGuid, &endpointHandle, &resultBuffer)
|
||||||
|
if err := checkForErrors("hcnOpenEndpoint", hr, resultBuffer); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Query endpoint.
|
||||||
|
hr = hcnQueryEndpointProperties(endpointHandle, query, &propertiesBuffer, &resultBuffer)
|
||||||
|
if err := checkForErrors("hcnQueryEndpointProperties", hr, resultBuffer); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
properties := interop.ConvertAndFreeCoTaskMemString(propertiesBuffer)
|
||||||
|
// Close endpoint.
|
||||||
|
hr = hcnCloseEndpoint(endpointHandle)
|
||||||
|
if err := checkForErrors("hcnCloseEndpoint", hr, nil); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Convert output to HostComputeEndpoint
|
||||||
|
var outputEndpoint HostComputeEndpoint
|
||||||
|
if err := json.Unmarshal([]byte(properties), &outputEndpoint); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &outputEndpoint, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func enumerateEndpoints(query string) ([]HostComputeEndpoint, error) {
|
||||||
|
// Enumerate all Endpoint Guids
|
||||||
|
var (
|
||||||
|
resultBuffer *uint16
|
||||||
|
endpointBuffer *uint16
|
||||||
|
)
|
||||||
|
hr := hcnEnumerateEndpoints(query, &endpointBuffer, &resultBuffer)
|
||||||
|
if err := checkForErrors("hcnEnumerateEndpoints", hr, resultBuffer); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
endpoints := interop.ConvertAndFreeCoTaskMemString(endpointBuffer)
|
||||||
|
var endpointIds []guid.GUID
|
||||||
|
err := json.Unmarshal([]byte(endpoints), &endpointIds)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var outputEndpoints []HostComputeEndpoint
|
||||||
|
for _, endpointGuid := range endpointIds {
|
||||||
|
endpoint, err := getEndpoint(endpointGuid, query)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
outputEndpoints = append(outputEndpoints, *endpoint)
|
||||||
|
}
|
||||||
|
return outputEndpoints, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func createEndpoint(networkId string, endpointSettings string) (*HostComputeEndpoint, error) {
|
||||||
|
networkGuid := guid.FromString(networkId)
|
||||||
|
// Open network.
|
||||||
|
var networkHandle hcnNetwork
|
||||||
|
var resultBuffer *uint16
|
||||||
|
hr := hcnOpenNetwork(&networkGuid, &networkHandle, &resultBuffer)
|
||||||
|
if err := checkForErrors("hcnOpenNetwork", hr, resultBuffer); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Create endpoint.
|
||||||
|
endpointId := guid.GUID{}
|
||||||
|
var endpointHandle hcnEndpoint
|
||||||
|
hr = hcnCreateEndpoint(networkHandle, &endpointId, endpointSettings, &endpointHandle, &resultBuffer)
|
||||||
|
if err := checkForErrors("hcnCreateEndpoint", hr, resultBuffer); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Query endpoint.
|
||||||
|
hcnQuery := defaultQuery()
|
||||||
|
query, err := json.Marshal(hcnQuery)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var propertiesBuffer *uint16
|
||||||
|
hr = hcnQueryEndpointProperties(endpointHandle, string(query), &propertiesBuffer, &resultBuffer)
|
||||||
|
if err := checkForErrors("hcnQueryEndpointProperties", hr, resultBuffer); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
properties := interop.ConvertAndFreeCoTaskMemString(propertiesBuffer)
|
||||||
|
// Close endpoint.
|
||||||
|
hr = hcnCloseEndpoint(endpointHandle)
|
||||||
|
if err := checkForErrors("hcnCloseEndpoint", hr, nil); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Close network.
|
||||||
|
hr = hcnCloseNetwork(networkHandle)
|
||||||
|
if err := checkForErrors("hcnCloseNetwork", hr, nil); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Convert output to HostComputeEndpoint
|
||||||
|
var outputEndpoint HostComputeEndpoint
|
||||||
|
if err := json.Unmarshal([]byte(properties), &outputEndpoint); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &outputEndpoint, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func modifyEndpoint(endpointId string, settings string) (*HostComputeEndpoint, error) {
|
||||||
|
endpointGuid := guid.FromString(endpointId)
|
||||||
|
// Open endpoint
|
||||||
|
var (
|
||||||
|
endpointHandle hcnEndpoint
|
||||||
|
resultBuffer *uint16
|
||||||
|
propertiesBuffer *uint16
|
||||||
|
)
|
||||||
|
hr := hcnOpenEndpoint(&endpointGuid, &endpointHandle, &resultBuffer)
|
||||||
|
if err := checkForErrors("hcnOpenEndpoint", hr, resultBuffer); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Modify endpoint
|
||||||
|
hr = hcnModifyEndpoint(endpointHandle, settings, &resultBuffer)
|
||||||
|
if err := checkForErrors("hcnModifyEndpoint", hr, resultBuffer); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Query endpoint.
|
||||||
|
hcnQuery := defaultQuery()
|
||||||
|
query, err := json.Marshal(hcnQuery)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
hr = hcnQueryEndpointProperties(endpointHandle, string(query), &propertiesBuffer, &resultBuffer)
|
||||||
|
if err := checkForErrors("hcnQueryEndpointProperties", hr, resultBuffer); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
properties := interop.ConvertAndFreeCoTaskMemString(propertiesBuffer)
|
||||||
|
// Close endpoint.
|
||||||
|
hr = hcnCloseEndpoint(endpointHandle)
|
||||||
|
if err := checkForErrors("hcnCloseEndpoint", hr, nil); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Convert output to HostComputeEndpoint
|
||||||
|
var outputEndpoint HostComputeEndpoint
|
||||||
|
if err := json.Unmarshal([]byte(properties), &outputEndpoint); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &outputEndpoint, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteEndpoint(endpointId string) error {
|
||||||
|
endpointGuid := guid.FromString(endpointId)
|
||||||
|
var resultBuffer *uint16
|
||||||
|
hr := hcnDeleteEndpoint(&endpointGuid, &resultBuffer)
|
||||||
|
if err := checkForErrors("hcnDeleteEndpoint", hr, resultBuffer); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListEndpoints makes a call to list all available endpoints.
|
||||||
|
func ListEndpoints() ([]HostComputeEndpoint, error) {
|
||||||
|
hcnQuery := defaultQuery()
|
||||||
|
endpoints, err := ListEndpointsQuery(hcnQuery)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return endpoints, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListEndpointsQuery makes a call to query the list of available endpoints.
|
||||||
|
func ListEndpointsQuery(query HostComputeQuery) ([]HostComputeEndpoint, error) {
|
||||||
|
queryJson, err := json.Marshal(query)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
endpoints, err := enumerateEndpoints(string(queryJson))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return endpoints, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListEndpointsOfNetwork queries the list of endpoints on a network.
|
||||||
|
func ListEndpointsOfNetwork(networkId string) ([]HostComputeEndpoint, error) {
|
||||||
|
hcnQuery := defaultQuery()
|
||||||
|
// TODO: Once query can convert schema, change to {HostComputeNetwork:networkId}
|
||||||
|
mapA := map[string]string{"VirtualNetwork": networkId}
|
||||||
|
filter, err := json.Marshal(mapA)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
hcnQuery.Filter = string(filter)
|
||||||
|
|
||||||
|
return ListEndpointsQuery(hcnQuery)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetEndpointByID returns an endpoint specified by Id
|
||||||
|
func GetEndpointByID(endpointId string) (*HostComputeEndpoint, error) {
|
||||||
|
hcnQuery := defaultQuery()
|
||||||
|
mapA := map[string]string{"ID": endpointId}
|
||||||
|
filter, err := json.Marshal(mapA)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
hcnQuery.Filter = string(filter)
|
||||||
|
|
||||||
|
endpoints, err := ListEndpointsQuery(hcnQuery)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(endpoints) == 0 {
|
||||||
|
return nil, EndpointNotFoundError{EndpointID: endpointId}
|
||||||
|
}
|
||||||
|
return &endpoints[0], err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetEndpointByName returns an endpoint specified by Name
|
||||||
|
func GetEndpointByName(endpointName string) (*HostComputeEndpoint, error) {
|
||||||
|
hcnQuery := defaultQuery()
|
||||||
|
mapA := map[string]string{"Name": endpointName}
|
||||||
|
filter, err := json.Marshal(mapA)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
hcnQuery.Filter = string(filter)
|
||||||
|
|
||||||
|
endpoints, err := ListEndpointsQuery(hcnQuery)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(endpoints) == 0 {
|
||||||
|
return nil, EndpointNotFoundError{EndpointName: endpointName}
|
||||||
|
}
|
||||||
|
return &endpoints[0], err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create Endpoint.
|
||||||
|
func (endpoint *HostComputeEndpoint) Create() (*HostComputeEndpoint, error) {
|
||||||
|
logrus.Debugf("hcn::HostComputeEndpoint::Create id=%s", endpoint.Id)
|
||||||
|
|
||||||
|
jsonString, err := json.Marshal(endpoint)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.Debugf("hcn::HostComputeEndpoint::Create JSON: %s", jsonString)
|
||||||
|
endpoint, hcnErr := createEndpoint(endpoint.HostComputeNetwork, string(jsonString))
|
||||||
|
if hcnErr != nil {
|
||||||
|
return nil, hcnErr
|
||||||
|
}
|
||||||
|
return endpoint, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete Endpoint.
|
||||||
|
func (endpoint *HostComputeEndpoint) Delete() (*HostComputeEndpoint, error) {
|
||||||
|
logrus.Debugf("hcn::HostComputeEndpoint::Delete id=%s", endpoint.Id)
|
||||||
|
|
||||||
|
if err := deleteEndpoint(endpoint.Id); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ModifyEndpointSettings updates the Port/Policy of an Endpoint.
|
||||||
|
func ModifyEndpointSettings(endpointId string, request *ModifyEndpointSettingRequest) error {
|
||||||
|
logrus.Debugf("hcn::HostComputeEndpoint::ModifyEndpointSettings id=%s", endpointId)
|
||||||
|
|
||||||
|
endpointSettingsRequest, err := json.Marshal(request)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = modifyEndpoint(endpointId, string(endpointSettingsRequest))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApplyPolicy applies a Policy (ex: ACL) on the Endpoint.
|
||||||
|
func (endpoint *HostComputeEndpoint) ApplyPolicy(endpointPolicy PolicyEndpointRequest) error {
|
||||||
|
logrus.Debugf("hcn::HostComputeEndpoint::ApplyPolicy id=%s", endpoint.Id)
|
||||||
|
|
||||||
|
settingsJson, err := json.Marshal(endpointPolicy)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
requestMessage := &ModifyEndpointSettingRequest{
|
||||||
|
ResourceType: EndpointResourceTypePolicy,
|
||||||
|
RequestType: RequestTypeUpdate,
|
||||||
|
Settings: settingsJson,
|
||||||
|
}
|
||||||
|
|
||||||
|
return ModifyEndpointSettings(endpoint.Id, requestMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NamespaceAttach modifies a Namespace to add an endpoint.
|
||||||
|
func (endpoint *HostComputeEndpoint) NamespaceAttach(namespaceId string) error {
|
||||||
|
return AddNamespaceEndpoint(namespaceId, endpoint.Id)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NamespaceDetach modifies a Namespace to remove an endpoint.
|
||||||
|
func (endpoint *HostComputeEndpoint) NamespaceDetach(namespaceId string) error {
|
||||||
|
return RemoveNamespaceEndpoint(namespaceId, endpoint.Id)
|
||||||
|
}
|
95
vendor/github.com/Microsoft/hcsshim/hcn/hcnerrors.go
generated
vendored
Normal file
95
vendor/github.com/Microsoft/hcsshim/hcn/hcnerrors.go
generated
vendored
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
// Package hcn is a shim for the Host Compute Networking (HCN) service, which manages networking for Windows Server
|
||||||
|
// containers and Hyper-V containers. Previous to RS5, HCN was referred to as Host Networking Service (HNS).
|
||||||
|
package hcn
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/Microsoft/hcsshim/internal/hcserror"
|
||||||
|
"github.com/Microsoft/hcsshim/internal/interop"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func checkForErrors(methodName string, hr error, resultBuffer *uint16) error {
|
||||||
|
errorFound := false
|
||||||
|
|
||||||
|
if hr != nil {
|
||||||
|
errorFound = true
|
||||||
|
}
|
||||||
|
|
||||||
|
result := ""
|
||||||
|
if resultBuffer != nil {
|
||||||
|
result = interop.ConvertAndFreeCoTaskMemString(resultBuffer)
|
||||||
|
if result != "" {
|
||||||
|
errorFound = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if errorFound {
|
||||||
|
returnError := hcserror.New(hr, methodName, result)
|
||||||
|
logrus.Debugf(returnError.Error()) // HCN errors logged for debugging.
|
||||||
|
return returnError
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NetworkNotFoundError results from a failed seach for a network by Id or Name
|
||||||
|
type NetworkNotFoundError struct {
|
||||||
|
NetworkName string
|
||||||
|
NetworkID string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e NetworkNotFoundError) Error() string {
|
||||||
|
if e.NetworkName == "" {
|
||||||
|
return fmt.Sprintf("Network Name %s not found", e.NetworkName)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("Network Id %s not found", e.NetworkID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EndpointNotFoundError results from a failed seach for an endpoint by Id or Name
|
||||||
|
type EndpointNotFoundError struct {
|
||||||
|
EndpointName string
|
||||||
|
EndpointID string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e EndpointNotFoundError) Error() string {
|
||||||
|
if e.EndpointName == "" {
|
||||||
|
return fmt.Sprintf("Endpoint Name %s not found", e.EndpointName)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("Endpoint Id %s not found", e.EndpointID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NamespaceNotFoundError results from a failed seach for a namsepace by Id
|
||||||
|
type NamespaceNotFoundError struct {
|
||||||
|
NamespaceID string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e NamespaceNotFoundError) Error() string {
|
||||||
|
return fmt.Sprintf("Namespace %s not found", e.NamespaceID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadBalancerNotFoundError results from a failed seach for a loadbalancer by Id
|
||||||
|
type LoadBalancerNotFoundError struct {
|
||||||
|
LoadBalancerId string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e LoadBalancerNotFoundError) Error() string {
|
||||||
|
return fmt.Sprintf("LoadBalancer %s not found", e.LoadBalancerId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsNotFoundError returns a boolean indicating whether the error was caused by
|
||||||
|
// a resource not being found.
|
||||||
|
func IsNotFoundError(err error) bool {
|
||||||
|
switch err.(type) {
|
||||||
|
case NetworkNotFoundError:
|
||||||
|
return true
|
||||||
|
case EndpointNotFoundError:
|
||||||
|
return true
|
||||||
|
case NamespaceNotFoundError:
|
||||||
|
return true
|
||||||
|
case LoadBalancerNotFoundError:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
81
vendor/github.com/Microsoft/hcsshim/hcn/hcnglobals.go
generated
vendored
Normal file
81
vendor/github.com/Microsoft/hcsshim/hcn/hcnglobals.go
generated
vendored
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
package hcn
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/Microsoft/hcsshim/internal/hcserror"
|
||||||
|
"github.com/Microsoft/hcsshim/internal/interop"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Globals are all global properties of the HCN Service.
|
||||||
|
type Globals struct {
|
||||||
|
Version Version `json:"Version"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Version is the HCN Service version.
|
||||||
|
type Version struct {
|
||||||
|
Major int `json:"Major"`
|
||||||
|
Minor int `json:"Minor"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
// HNSVersion1803 added ACL functionality.
|
||||||
|
HNSVersion1803 = Version{Major: 7, Minor: 2}
|
||||||
|
// V2ApiSupport allows the use of V2 Api calls and V2 Schema.
|
||||||
|
V2ApiSupport = Version{Major: 9, Minor: 1}
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetGlobals returns the global properties of the HCN Service.
|
||||||
|
func GetGlobals() (*Globals, error) {
|
||||||
|
var version Version
|
||||||
|
err := hnsCall("GET", "/globals/version", "", &version)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
globals := &Globals{
|
||||||
|
Version: version,
|
||||||
|
}
|
||||||
|
|
||||||
|
return globals, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type hnsResponse struct {
|
||||||
|
Success bool
|
||||||
|
Error string
|
||||||
|
Output json.RawMessage
|
||||||
|
}
|
||||||
|
|
||||||
|
func hnsCall(method, path, request string, returnResponse interface{}) error {
|
||||||
|
var responseBuffer *uint16
|
||||||
|
logrus.Debugf("[%s]=>[%s] Request : %s", method, path, request)
|
||||||
|
|
||||||
|
err := _hnsCall(method, path, request, &responseBuffer)
|
||||||
|
if err != nil {
|
||||||
|
return hcserror.New(err, "hnsCall ", "")
|
||||||
|
}
|
||||||
|
response := interop.ConvertAndFreeCoTaskMemString(responseBuffer)
|
||||||
|
|
||||||
|
hnsresponse := &hnsResponse{}
|
||||||
|
if err = json.Unmarshal([]byte(response), &hnsresponse); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !hnsresponse.Success {
|
||||||
|
return fmt.Errorf("HNS failed with error : %s", hnsresponse.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(hnsresponse.Output) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.Debugf("Network Response : %s", hnsresponse.Output)
|
||||||
|
err = json.Unmarshal(hnsresponse.Output, returnResponse)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
321
vendor/github.com/Microsoft/hcsshim/hcn/hcnloadbalancer.go
generated
vendored
Normal file
321
vendor/github.com/Microsoft/hcsshim/hcn/hcnloadbalancer.go
generated
vendored
Normal file
@ -0,0 +1,321 @@
|
|||||||
|
package hcn
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/Microsoft/hcsshim/internal/guid"
|
||||||
|
"github.com/Microsoft/hcsshim/internal/interop"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// LoadBalancerPortMapping is associated with HostComputeLoadBalancer
|
||||||
|
type LoadBalancerPortMapping struct {
|
||||||
|
Protocol uint32 `json:",omitempty"` // EX: TCP = 6, UDP = 17
|
||||||
|
InternalPort uint16 `json:",omitempty"`
|
||||||
|
ExternalPort uint16 `json:",omitempty"`
|
||||||
|
Flags uint32 `json:",omitempty"` // 0: None, 1: EnableILB, 2: LocalRoutedVip
|
||||||
|
}
|
||||||
|
|
||||||
|
// HostComputeLoadBalancer represents software load balancer.
|
||||||
|
type HostComputeLoadBalancer struct {
|
||||||
|
Id string `json:"ID,omitempty"`
|
||||||
|
HostComputeEndpoints []string `json:",omitempty"`
|
||||||
|
SourceVIP string `json:",omitempty"`
|
||||||
|
FrontendVIPs []string `json:",omitempty"`
|
||||||
|
PortMappings []LoadBalancerPortMapping `json:",omitempty"`
|
||||||
|
SchemaVersion SchemaVersion `json:",omitempty"`
|
||||||
|
Flags uint32 `json:",omitempty"` // 0: None, 1: EnableDirectServerReturn
|
||||||
|
}
|
||||||
|
|
||||||
|
func getLoadBalancer(loadBalancerGuid guid.GUID, query string) (*HostComputeLoadBalancer, error) {
|
||||||
|
// Open loadBalancer.
|
||||||
|
var (
|
||||||
|
loadBalancerHandle hcnLoadBalancer
|
||||||
|
resultBuffer *uint16
|
||||||
|
propertiesBuffer *uint16
|
||||||
|
)
|
||||||
|
hr := hcnOpenLoadBalancer(&loadBalancerGuid, &loadBalancerHandle, &resultBuffer)
|
||||||
|
if err := checkForErrors("hcnOpenLoadBalancer", hr, resultBuffer); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Query loadBalancer.
|
||||||
|
hr = hcnQueryLoadBalancerProperties(loadBalancerHandle, query, &propertiesBuffer, &resultBuffer)
|
||||||
|
if err := checkForErrors("hcnQueryLoadBalancerProperties", hr, resultBuffer); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
properties := interop.ConvertAndFreeCoTaskMemString(propertiesBuffer)
|
||||||
|
// Close loadBalancer.
|
||||||
|
hr = hcnCloseLoadBalancer(loadBalancerHandle)
|
||||||
|
if err := checkForErrors("hcnCloseLoadBalancer", hr, nil); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Convert output to HostComputeLoadBalancer
|
||||||
|
var outputLoadBalancer HostComputeLoadBalancer
|
||||||
|
if err := json.Unmarshal([]byte(properties), &outputLoadBalancer); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &outputLoadBalancer, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func enumerateLoadBalancers(query string) ([]HostComputeLoadBalancer, error) {
|
||||||
|
// Enumerate all LoadBalancer Guids
|
||||||
|
var (
|
||||||
|
resultBuffer *uint16
|
||||||
|
loadBalancerBuffer *uint16
|
||||||
|
)
|
||||||
|
hr := hcnEnumerateLoadBalancers(query, &loadBalancerBuffer, &resultBuffer)
|
||||||
|
if err := checkForErrors("hcnEnumerateLoadBalancers", hr, resultBuffer); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
loadBalancers := interop.ConvertAndFreeCoTaskMemString(loadBalancerBuffer)
|
||||||
|
var loadBalancerIds []guid.GUID
|
||||||
|
if err := json.Unmarshal([]byte(loadBalancers), &loadBalancerIds); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var outputLoadBalancers []HostComputeLoadBalancer
|
||||||
|
for _, loadBalancerGuid := range loadBalancerIds {
|
||||||
|
loadBalancer, err := getLoadBalancer(loadBalancerGuid, query)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
outputLoadBalancers = append(outputLoadBalancers, *loadBalancer)
|
||||||
|
}
|
||||||
|
return outputLoadBalancers, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func createLoadBalancer(settings string) (*HostComputeLoadBalancer, error) {
|
||||||
|
// Create new loadBalancer.
|
||||||
|
var (
|
||||||
|
loadBalancerHandle hcnLoadBalancer
|
||||||
|
resultBuffer *uint16
|
||||||
|
propertiesBuffer *uint16
|
||||||
|
)
|
||||||
|
loadBalancerGuid := guid.GUID{}
|
||||||
|
hr := hcnCreateLoadBalancer(&loadBalancerGuid, settings, &loadBalancerHandle, &resultBuffer)
|
||||||
|
if err := checkForErrors("hcnCreateLoadBalancer", hr, resultBuffer); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Query loadBalancer.
|
||||||
|
hcnQuery := defaultQuery()
|
||||||
|
query, err := json.Marshal(hcnQuery)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
hr = hcnQueryLoadBalancerProperties(loadBalancerHandle, string(query), &propertiesBuffer, &resultBuffer)
|
||||||
|
if err := checkForErrors("hcnQueryLoadBalancerProperties", hr, resultBuffer); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
properties := interop.ConvertAndFreeCoTaskMemString(propertiesBuffer)
|
||||||
|
// Close loadBalancer.
|
||||||
|
hr = hcnCloseLoadBalancer(loadBalancerHandle)
|
||||||
|
if err := checkForErrors("hcnCloseLoadBalancer", hr, nil); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Convert output to HostComputeLoadBalancer
|
||||||
|
var outputLoadBalancer HostComputeLoadBalancer
|
||||||
|
if err := json.Unmarshal([]byte(properties), &outputLoadBalancer); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &outputLoadBalancer, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func modifyLoadBalancer(loadBalancerId string, settings string) (*HostComputeLoadBalancer, error) {
|
||||||
|
loadBalancerGuid := guid.FromString(loadBalancerId)
|
||||||
|
// Open loadBalancer.
|
||||||
|
var (
|
||||||
|
loadBalancerHandle hcnLoadBalancer
|
||||||
|
resultBuffer *uint16
|
||||||
|
propertiesBuffer *uint16
|
||||||
|
)
|
||||||
|
hr := hcnOpenLoadBalancer(&loadBalancerGuid, &loadBalancerHandle, &resultBuffer)
|
||||||
|
if err := checkForErrors("hcnOpenLoadBalancer", hr, resultBuffer); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Modify loadBalancer.
|
||||||
|
hr = hcnModifyLoadBalancer(loadBalancerHandle, settings, &resultBuffer)
|
||||||
|
if err := checkForErrors("hcnModifyLoadBalancer", hr, resultBuffer); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Query loadBalancer.
|
||||||
|
hcnQuery := defaultQuery()
|
||||||
|
query, err := json.Marshal(hcnQuery)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
hr = hcnQueryLoadBalancerProperties(loadBalancerHandle, string(query), &propertiesBuffer, &resultBuffer)
|
||||||
|
if err := checkForErrors("hcnQueryLoadBalancerProperties", hr, resultBuffer); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
properties := interop.ConvertAndFreeCoTaskMemString(propertiesBuffer)
|
||||||
|
// Close loadBalancer.
|
||||||
|
hr = hcnCloseLoadBalancer(loadBalancerHandle)
|
||||||
|
if err := checkForErrors("hcnCloseLoadBalancer", hr, nil); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Convert output to LoadBalancer
|
||||||
|
var outputLoadBalancer HostComputeLoadBalancer
|
||||||
|
if err := json.Unmarshal([]byte(properties), &outputLoadBalancer); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &outputLoadBalancer, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteLoadBalancer(loadBalancerId string) error {
|
||||||
|
loadBalancerGuid := guid.FromString(loadBalancerId)
|
||||||
|
var resultBuffer *uint16
|
||||||
|
hr := hcnDeleteLoadBalancer(&loadBalancerGuid, &resultBuffer)
|
||||||
|
if err := checkForErrors("hcnDeleteLoadBalancer", hr, resultBuffer); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListLoadBalancers makes a call to list all available loadBalancers.
|
||||||
|
func ListLoadBalancers() ([]HostComputeLoadBalancer, error) {
|
||||||
|
hcnQuery := defaultQuery()
|
||||||
|
loadBalancers, err := ListLoadBalancersQuery(hcnQuery)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return loadBalancers, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListLoadBalancersQuery makes a call to query the list of available loadBalancers.
|
||||||
|
func ListLoadBalancersQuery(query HostComputeQuery) ([]HostComputeLoadBalancer, error) {
|
||||||
|
queryJson, err := json.Marshal(query)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
loadBalancers, err := enumerateLoadBalancers(string(queryJson))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return loadBalancers, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetLoadBalancerByID returns the LoadBalancer specified by Id.
|
||||||
|
func GetLoadBalancerByID(loadBalancerId string) (*HostComputeLoadBalancer, error) {
|
||||||
|
hcnQuery := defaultQuery()
|
||||||
|
mapA := map[string]string{"ID": loadBalancerId}
|
||||||
|
filter, err := json.Marshal(mapA)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
hcnQuery.Filter = string(filter)
|
||||||
|
|
||||||
|
loadBalancers, err := ListLoadBalancersQuery(hcnQuery)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(loadBalancers) == 0 {
|
||||||
|
return nil, LoadBalancerNotFoundError{LoadBalancerId: loadBalancerId}
|
||||||
|
}
|
||||||
|
return &loadBalancers[0], err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create LoadBalancer.
|
||||||
|
func (loadBalancer *HostComputeLoadBalancer) Create() (*HostComputeLoadBalancer, error) {
|
||||||
|
logrus.Debugf("hcn::HostComputeLoadBalancer::Create id=%s", loadBalancer.Id)
|
||||||
|
|
||||||
|
jsonString, err := json.Marshal(loadBalancer)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.Debugf("hcn::HostComputeLoadBalancer::Create JSON: %s", jsonString)
|
||||||
|
loadBalancer, hcnErr := createLoadBalancer(string(jsonString))
|
||||||
|
if hcnErr != nil {
|
||||||
|
return nil, hcnErr
|
||||||
|
}
|
||||||
|
return loadBalancer, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete LoadBalancer.
|
||||||
|
func (loadBalancer *HostComputeLoadBalancer) Delete() (*HostComputeLoadBalancer, error) {
|
||||||
|
logrus.Debugf("hcn::HostComputeLoadBalancer::Delete id=%s", loadBalancer.Id)
|
||||||
|
|
||||||
|
if err := deleteLoadBalancer(loadBalancer.Id); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddEndpoint add an endpoint to a LoadBalancer
|
||||||
|
func (loadBalancer *HostComputeLoadBalancer) AddEndpoint(endpoint *HostComputeEndpoint) (*HostComputeLoadBalancer, error) {
|
||||||
|
logrus.Debugf("hcn::HostComputeLoadBalancer::AddEndpoint loadBalancer=%s endpoint=%s", loadBalancer.Id, endpoint.Id)
|
||||||
|
|
||||||
|
_, err := loadBalancer.Delete()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add Endpoint to the Existing List
|
||||||
|
loadBalancer.HostComputeEndpoints = append(loadBalancer.HostComputeEndpoints, endpoint.Id)
|
||||||
|
|
||||||
|
return loadBalancer.Create()
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveEndpoint removes an endpoint from a LoadBalancer
|
||||||
|
func (loadBalancer *HostComputeLoadBalancer) RemoveEndpoint(endpoint *HostComputeEndpoint) (*HostComputeLoadBalancer, error) {
|
||||||
|
logrus.Debugf("hcn::HostComputeLoadBalancer::RemoveEndpoint loadBalancer=%s endpoint=%s", loadBalancer.Id, endpoint.Id)
|
||||||
|
|
||||||
|
_, err := loadBalancer.Delete()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a list of all the endpoints besides the one being removed
|
||||||
|
var endpoints []string
|
||||||
|
for _, endpointReference := range loadBalancer.HostComputeEndpoints {
|
||||||
|
if endpointReference == endpoint.Id {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
endpoints = append(endpoints, endpointReference)
|
||||||
|
}
|
||||||
|
loadBalancer.HostComputeEndpoints = endpoints
|
||||||
|
return loadBalancer.Create()
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddLoadBalancer for the specified endpoints
|
||||||
|
func AddLoadBalancer(endpoints []HostComputeEndpoint, isILB bool, isDSR bool, sourceVIP string, frontendVIPs []string, protocol uint16, internalPort uint16, externalPort uint16) (*HostComputeLoadBalancer, error) {
|
||||||
|
logrus.Debugf("hcn::HostComputeLoadBalancer::AddLoadBalancer endpointId=%v, isILB=%v, sourceVIP=%s, frontendVIPs=%v, protocol=%v, internalPort=%v, externalPort=%v", endpoints, isILB, sourceVIP, frontendVIPs, protocol, internalPort, externalPort)
|
||||||
|
|
||||||
|
var portMappingFlags uint32
|
||||||
|
portMappingFlags = 0
|
||||||
|
if isILB {
|
||||||
|
portMappingFlags = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
var lbFlags uint32
|
||||||
|
lbFlags = 0
|
||||||
|
if isDSR {
|
||||||
|
lbFlags = 1 // EnableDirectServerReturn
|
||||||
|
}
|
||||||
|
|
||||||
|
loadBalancer := &HostComputeLoadBalancer{
|
||||||
|
SourceVIP: sourceVIP,
|
||||||
|
PortMappings: []LoadBalancerPortMapping{
|
||||||
|
{
|
||||||
|
Protocol: uint32(protocol),
|
||||||
|
InternalPort: internalPort,
|
||||||
|
ExternalPort: externalPort,
|
||||||
|
Flags: portMappingFlags,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
FrontendVIPs: frontendVIPs,
|
||||||
|
SchemaVersion: SchemaVersion{
|
||||||
|
Major: 2,
|
||||||
|
Minor: 0,
|
||||||
|
},
|
||||||
|
Flags: lbFlags,
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, endpoint := range endpoints {
|
||||||
|
loadBalancer.HostComputeEndpoints = append(loadBalancer.HostComputeEndpoints, endpoint.Id)
|
||||||
|
}
|
||||||
|
|
||||||
|
return loadBalancer.Create()
|
||||||
|
}
|
424
vendor/github.com/Microsoft/hcsshim/hcn/hcnnamespace.go
generated
vendored
Normal file
424
vendor/github.com/Microsoft/hcsshim/hcn/hcnnamespace.go
generated
vendored
Normal file
@ -0,0 +1,424 @@
|
|||||||
|
package hcn
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"os"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
icni "github.com/Microsoft/hcsshim/internal/cni"
|
||||||
|
"github.com/Microsoft/hcsshim/internal/guid"
|
||||||
|
"github.com/Microsoft/hcsshim/internal/interop"
|
||||||
|
"github.com/Microsoft/hcsshim/internal/regstate"
|
||||||
|
"github.com/Microsoft/hcsshim/internal/runhcs"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NamespaceResourceEndpoint represents an Endpoint attached to a Namespace.
|
||||||
|
type NamespaceResourceEndpoint struct {
|
||||||
|
Id string `json:"ID,"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NamespaceResourceContainer represents a Container attached to a Namespace.
|
||||||
|
type NamespaceResourceContainer struct {
|
||||||
|
Id string `json:"ID,"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NamespaceResourceType determines whether the Namespace resource is a Container or Endpoint.
|
||||||
|
type NamespaceResourceType string
|
||||||
|
|
||||||
|
var (
|
||||||
|
// NamespaceResourceTypeContainer are contianers associated with a Namespace.
|
||||||
|
NamespaceResourceTypeContainer NamespaceResourceType = "Container"
|
||||||
|
// NamespaceResourceTypeEndpoint are endpoints associated with a Namespace.
|
||||||
|
NamespaceResourceTypeEndpoint NamespaceResourceType = "Endpoint"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NamespaceResource is associated with a namespace
|
||||||
|
type NamespaceResource struct {
|
||||||
|
Type NamespaceResourceType `json:","` // Container, Endpoint
|
||||||
|
Data json.RawMessage `json:","`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NamespaceType determines whether the Namespace is for a Host or Guest
|
||||||
|
type NamespaceType string
|
||||||
|
|
||||||
|
var (
|
||||||
|
// NamespaceTypeHost are host namespaces.
|
||||||
|
NamespaceTypeHost NamespaceType = "Host"
|
||||||
|
// NamespaceTypeHostDefault are host namespaces in the default compartment.
|
||||||
|
NamespaceTypeHostDefault NamespaceType = "HostDefault"
|
||||||
|
// NamespaceTypeGuest are guest namespaces.
|
||||||
|
NamespaceTypeGuest NamespaceType = "Guest"
|
||||||
|
// NamespaceTypeGuestDefault are guest namespaces in the default compartment.
|
||||||
|
NamespaceTypeGuestDefault NamespaceType = "GuestDefault"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HostComputeNamespace represents a namespace (AKA compartment) in
|
||||||
|
type HostComputeNamespace struct {
|
||||||
|
Id string `json:"ID,omitempty"`
|
||||||
|
NamespaceId uint32 `json:",omitempty"`
|
||||||
|
Type NamespaceType `json:",omitempty"` // Host, HostDefault, Guest, GuestDefault
|
||||||
|
Resources []NamespaceResource `json:",omitempty"`
|
||||||
|
SchemaVersion SchemaVersion `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ModifyNamespaceSettingRequest is the structure used to send request to modify a namespace.
|
||||||
|
// Used to Add/Remove an endpoints and containers to/from a namespace.
|
||||||
|
type ModifyNamespaceSettingRequest struct {
|
||||||
|
ResourceType NamespaceResourceType `json:",omitempty"` // Container, Endpoint
|
||||||
|
RequestType RequestType `json:",omitempty"` // Add, Remove, Update, Refresh
|
||||||
|
Settings json.RawMessage `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func getNamespace(namespaceGuid guid.GUID, query string) (*HostComputeNamespace, error) {
|
||||||
|
// Open namespace.
|
||||||
|
var (
|
||||||
|
namespaceHandle hcnNamespace
|
||||||
|
resultBuffer *uint16
|
||||||
|
propertiesBuffer *uint16
|
||||||
|
)
|
||||||
|
hr := hcnOpenNamespace(&namespaceGuid, &namespaceHandle, &resultBuffer)
|
||||||
|
if err := checkForErrors("hcnOpenNamespace", hr, resultBuffer); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Query namespace.
|
||||||
|
hr = hcnQueryNamespaceProperties(namespaceHandle, query, &propertiesBuffer, &resultBuffer)
|
||||||
|
if err := checkForErrors("hcnQueryNamespaceProperties", hr, resultBuffer); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
properties := interop.ConvertAndFreeCoTaskMemString(propertiesBuffer)
|
||||||
|
// Close namespace.
|
||||||
|
hr = hcnCloseNamespace(namespaceHandle)
|
||||||
|
if err := checkForErrors("hcnCloseNamespace", hr, nil); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Convert output to HostComputeNamespace
|
||||||
|
var outputNamespace HostComputeNamespace
|
||||||
|
if err := json.Unmarshal([]byte(properties), &outputNamespace); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &outputNamespace, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func enumerateNamespaces(query string) ([]HostComputeNamespace, error) {
|
||||||
|
// Enumerate all Namespace Guids
|
||||||
|
var (
|
||||||
|
resultBuffer *uint16
|
||||||
|
namespaceBuffer *uint16
|
||||||
|
)
|
||||||
|
hr := hcnEnumerateNamespaces(query, &namespaceBuffer, &resultBuffer)
|
||||||
|
if err := checkForErrors("hcnEnumerateNamespaces", hr, resultBuffer); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
namespaces := interop.ConvertAndFreeCoTaskMemString(namespaceBuffer)
|
||||||
|
var namespaceIds []guid.GUID
|
||||||
|
if err := json.Unmarshal([]byte(namespaces), &namespaceIds); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var outputNamespaces []HostComputeNamespace
|
||||||
|
for _, namespaceGuid := range namespaceIds {
|
||||||
|
namespace, err := getNamespace(namespaceGuid, query)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
outputNamespaces = append(outputNamespaces, *namespace)
|
||||||
|
}
|
||||||
|
return outputNamespaces, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func createNamespace(settings string) (*HostComputeNamespace, error) {
|
||||||
|
// Create new namespace.
|
||||||
|
var (
|
||||||
|
namespaceHandle hcnNamespace
|
||||||
|
resultBuffer *uint16
|
||||||
|
propertiesBuffer *uint16
|
||||||
|
)
|
||||||
|
namespaceGuid := guid.GUID{}
|
||||||
|
hr := hcnCreateNamespace(&namespaceGuid, settings, &namespaceHandle, &resultBuffer)
|
||||||
|
if err := checkForErrors("hcnCreateNamespace", hr, resultBuffer); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Query namespace.
|
||||||
|
hcnQuery := defaultQuery()
|
||||||
|
query, err := json.Marshal(hcnQuery)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
hr = hcnQueryNamespaceProperties(namespaceHandle, string(query), &propertiesBuffer, &resultBuffer)
|
||||||
|
if err := checkForErrors("hcnQueryNamespaceProperties", hr, resultBuffer); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
properties := interop.ConvertAndFreeCoTaskMemString(propertiesBuffer)
|
||||||
|
// Close namespace.
|
||||||
|
hr = hcnCloseNamespace(namespaceHandle)
|
||||||
|
if err := checkForErrors("hcnCloseNamespace", hr, nil); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Convert output to HostComputeNamespace
|
||||||
|
var outputNamespace HostComputeNamespace
|
||||||
|
if err := json.Unmarshal([]byte(properties), &outputNamespace); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &outputNamespace, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func modifyNamespace(namespaceId string, settings string) (*HostComputeNamespace, error) {
|
||||||
|
namespaceGuid := guid.FromString(namespaceId)
|
||||||
|
// Open namespace.
|
||||||
|
var (
|
||||||
|
namespaceHandle hcnNamespace
|
||||||
|
resultBuffer *uint16
|
||||||
|
propertiesBuffer *uint16
|
||||||
|
)
|
||||||
|
hr := hcnOpenNamespace(&namespaceGuid, &namespaceHandle, &resultBuffer)
|
||||||
|
if err := checkForErrors("hcnOpenNamespace", hr, resultBuffer); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Modify namespace.
|
||||||
|
hr = hcnModifyNamespace(namespaceHandle, settings, &resultBuffer)
|
||||||
|
if err := checkForErrors("hcnModifyNamespace", hr, resultBuffer); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Query namespace.
|
||||||
|
hcnQuery := defaultQuery()
|
||||||
|
query, err := json.Marshal(hcnQuery)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
hr = hcnQueryNamespaceProperties(namespaceHandle, string(query), &propertiesBuffer, &resultBuffer)
|
||||||
|
if err := checkForErrors("hcnQueryNamespaceProperties", hr, resultBuffer); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
properties := interop.ConvertAndFreeCoTaskMemString(propertiesBuffer)
|
||||||
|
// Close namespace.
|
||||||
|
hr = hcnCloseNamespace(namespaceHandle)
|
||||||
|
if err := checkForErrors("hcnCloseNamespace", hr, nil); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Convert output to Namespace
|
||||||
|
var outputNamespace HostComputeNamespace
|
||||||
|
if err := json.Unmarshal([]byte(properties), &outputNamespace); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &outputNamespace, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteNamespace(namespaceId string) error {
|
||||||
|
namespaceGuid := guid.FromString(namespaceId)
|
||||||
|
var resultBuffer *uint16
|
||||||
|
hr := hcnDeleteNamespace(&namespaceGuid, &resultBuffer)
|
||||||
|
if err := checkForErrors("hcnDeleteNamespace", hr, resultBuffer); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListNamespaces makes a call to list all available namespaces.
|
||||||
|
func ListNamespaces() ([]HostComputeNamespace, error) {
|
||||||
|
hcnQuery := defaultQuery()
|
||||||
|
namespaces, err := ListNamespacesQuery(hcnQuery)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return namespaces, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListNamespacesQuery makes a call to query the list of available namespaces.
|
||||||
|
func ListNamespacesQuery(query HostComputeQuery) ([]HostComputeNamespace, error) {
|
||||||
|
queryJson, err := json.Marshal(query)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
namespaces, err := enumerateNamespaces(string(queryJson))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return namespaces, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetNamespaceByID returns the Namespace specified by Id.
|
||||||
|
func GetNamespaceByID(namespaceId string) (*HostComputeNamespace, error) {
|
||||||
|
return getNamespace(guid.FromString(namespaceId), defaultQueryJson())
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetNamespaceEndpointIds returns the endpoints of the Namespace specified by Id.
|
||||||
|
func GetNamespaceEndpointIds(namespaceId string) ([]string, error) {
|
||||||
|
namespace, err := GetNamespaceByID(namespaceId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var endpointsIds []string
|
||||||
|
for _, resource := range namespace.Resources {
|
||||||
|
if resource.Type == "Endpoint" {
|
||||||
|
var endpointResource NamespaceResourceEndpoint
|
||||||
|
if err := json.Unmarshal([]byte(resource.Data), &endpointResource); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
endpointsIds = append(endpointsIds, endpointResource.Id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return endpointsIds, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetNamespaceContainerIds returns the containers of the Namespace specified by Id.
|
||||||
|
func GetNamespaceContainerIds(namespaceId string) ([]string, error) {
|
||||||
|
namespace, err := GetNamespaceByID(namespaceId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var containerIds []string
|
||||||
|
for _, resource := range namespace.Resources {
|
||||||
|
if resource.Type == "Container" {
|
||||||
|
var contaienrResource NamespaceResourceContainer
|
||||||
|
if err := json.Unmarshal([]byte(resource.Data), &contaienrResource); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
containerIds = append(containerIds, contaienrResource.Id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return containerIds, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewNamespace creates a new Namespace object
|
||||||
|
func NewNamespace(nsType NamespaceType) *HostComputeNamespace {
|
||||||
|
return &HostComputeNamespace{
|
||||||
|
Type: nsType,
|
||||||
|
SchemaVersion: V2SchemaVersion(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create Namespace.
|
||||||
|
func (namespace *HostComputeNamespace) Create() (*HostComputeNamespace, error) {
|
||||||
|
logrus.Debugf("hcn::HostComputeNamespace::Create id=%s", namespace.Id)
|
||||||
|
|
||||||
|
jsonString, err := json.Marshal(namespace)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.Debugf("hcn::HostComputeNamespace::Create JSON: %s", jsonString)
|
||||||
|
namespace, hcnErr := createNamespace(string(jsonString))
|
||||||
|
if hcnErr != nil {
|
||||||
|
return nil, hcnErr
|
||||||
|
}
|
||||||
|
return namespace, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete Namespace.
|
||||||
|
func (namespace *HostComputeNamespace) Delete() (*HostComputeNamespace, error) {
|
||||||
|
logrus.Debugf("hcn::HostComputeNamespace::Delete id=%s", namespace.Id)
|
||||||
|
|
||||||
|
if err := deleteNamespace(namespace.Id); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sync Namespace endpoints with the appropriate sandbox container holding the
|
||||||
|
// network namespace open. If no sandbox container is found for this namespace
|
||||||
|
// this method is determined to be a success and will not return an error in
|
||||||
|
// this case. If the sandbox container is found and a sync is initiated any
|
||||||
|
// failures will be returned via this method.
|
||||||
|
//
|
||||||
|
// This call initiates a sync between endpoints and the matching UtilityVM
|
||||||
|
// hosting those endpoints. It is safe to call for any `NamespaceType` but
|
||||||
|
// `NamespaceTypeGuest` is the only case when a sync will actually occur. For
|
||||||
|
// `NamespaceTypeHost` the process container will be automatically synchronized
|
||||||
|
// when the the endpoint is added via `AddNamespaceEndpoint`.
|
||||||
|
//
|
||||||
|
// Note: This method sync's both additions and removals of endpoints from a
|
||||||
|
// `NamespaceTypeGuest` namespace.
|
||||||
|
func (namespace *HostComputeNamespace) Sync() error {
|
||||||
|
logrus.WithField("id", namespace.Id).Debugf("hcs::HostComputeNamespace::Sync")
|
||||||
|
|
||||||
|
// We only attempt a sync for namespace guest.
|
||||||
|
if namespace.Type != NamespaceTypeGuest {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look in the registry for the key to map from namespace id to pod-id
|
||||||
|
cfg, err := icni.LoadPersistedNamespaceConfig(namespace.Id)
|
||||||
|
if err != nil {
|
||||||
|
if regstate.IsNotFoundError(err) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
req := runhcs.VMRequest{
|
||||||
|
ID: cfg.ContainerID,
|
||||||
|
Op: runhcs.OpSyncNamespace,
|
||||||
|
}
|
||||||
|
shimPath := runhcs.VMPipePath(cfg.HostUniqueID)
|
||||||
|
if err := runhcs.IssueVMRequest(shimPath, &req); err != nil {
|
||||||
|
// The shim is likey gone. Simply ignore the sync as if it didn't exist.
|
||||||
|
if perr, ok := err.(*os.PathError); ok && perr.Err == syscall.ERROR_FILE_NOT_FOUND {
|
||||||
|
// Remove the reg key there is no point to try again
|
||||||
|
cfg.Remove()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
f := map[string]interface{}{
|
||||||
|
"id": namespace.Id,
|
||||||
|
"container-id": cfg.ContainerID,
|
||||||
|
}
|
||||||
|
logrus.WithFields(f).
|
||||||
|
WithError(err).
|
||||||
|
Debugf("hcs::HostComputeNamespace::Sync failed to connect to shim pipe: '%s'", shimPath)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ModifyNamespaceSettings updates the Endpoints/Containers of a Namespace.
|
||||||
|
func ModifyNamespaceSettings(namespaceId string, request *ModifyNamespaceSettingRequest) error {
|
||||||
|
logrus.Debugf("hcn::HostComputeNamespace::ModifyNamespaceSettings id=%s", namespaceId)
|
||||||
|
|
||||||
|
namespaceSettings, err := json.Marshal(request)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = modifyNamespace(namespaceId, string(namespaceSettings))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddNamespaceEndpoint adds an endpoint to a Namespace.
|
||||||
|
func AddNamespaceEndpoint(namespaceId string, endpointId string) error {
|
||||||
|
logrus.Debugf("hcn::HostComputeEndpoint::AddNamespaceEndpoint id=%s", endpointId)
|
||||||
|
|
||||||
|
mapA := map[string]string{"EndpointId": endpointId}
|
||||||
|
settingsJson, err := json.Marshal(mapA)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
requestMessage := &ModifyNamespaceSettingRequest{
|
||||||
|
ResourceType: NamespaceResourceTypeEndpoint,
|
||||||
|
RequestType: RequestTypeAdd,
|
||||||
|
Settings: settingsJson,
|
||||||
|
}
|
||||||
|
|
||||||
|
return ModifyNamespaceSettings(namespaceId, requestMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveNamespaceEndpoint removes an endpoint from a Namespace.
|
||||||
|
func RemoveNamespaceEndpoint(namespaceId string, endpointId string) error {
|
||||||
|
logrus.Debugf("hcn::HostComputeNamespace::RemoveNamespaceEndpoint id=%s", endpointId)
|
||||||
|
|
||||||
|
mapA := map[string]string{"EndpointId": endpointId}
|
||||||
|
settingsJson, err := json.Marshal(mapA)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
requestMessage := &ModifyNamespaceSettingRequest{
|
||||||
|
ResourceType: NamespaceResourceTypeEndpoint,
|
||||||
|
RequestType: RequestTypeRemove,
|
||||||
|
Settings: settingsJson,
|
||||||
|
}
|
||||||
|
|
||||||
|
return ModifyNamespaceSettings(namespaceId, requestMessage)
|
||||||
|
}
|
409
vendor/github.com/Microsoft/hcsshim/hcn/hcnnetwork.go
generated
vendored
Normal file
409
vendor/github.com/Microsoft/hcsshim/hcn/hcnnetwork.go
generated
vendored
Normal file
@ -0,0 +1,409 @@
|
|||||||
|
package hcn
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/Microsoft/hcsshim/internal/guid"
|
||||||
|
"github.com/Microsoft/hcsshim/internal/interop"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Route is assoicated with a subnet.
|
||||||
|
type Route struct {
|
||||||
|
NextHop string `json:",omitempty"`
|
||||||
|
DestinationPrefix string `json:",omitempty"`
|
||||||
|
Metric uint16 `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Subnet is assoicated with a Ipam.
|
||||||
|
type Subnet struct {
|
||||||
|
IpAddressPrefix string `json:",omitempty"`
|
||||||
|
Policies []json.RawMessage `json:",omitempty"`
|
||||||
|
Routes []Route `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ipam (Internet Protocol Addres Management) is assoicated with a network
|
||||||
|
// and represents the address space(s) of a network.
|
||||||
|
type Ipam struct {
|
||||||
|
Type string `json:",omitempty"` // Ex: Static, DHCP
|
||||||
|
Subnets []Subnet `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// MacRange is associated with MacPool and respresents the start and end addresses.
|
||||||
|
type MacRange struct {
|
||||||
|
StartMacAddress string `json:",omitempty"`
|
||||||
|
EndMacAddress string `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// MacPool is assoicated with a network and represents pool of MacRanges.
|
||||||
|
type MacPool struct {
|
||||||
|
Ranges []MacRange `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dns (Domain Name System is associated with a network.
|
||||||
|
type Dns struct {
|
||||||
|
Suffix string `json:",omitempty"`
|
||||||
|
Search []string `json:",omitempty"`
|
||||||
|
ServerList []string `json:",omitempty"`
|
||||||
|
Options []string `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NetworkType are various networks.
|
||||||
|
type NetworkType string
|
||||||
|
|
||||||
|
// NetworkType const
|
||||||
|
const (
|
||||||
|
NAT NetworkType = "NAT"
|
||||||
|
Transparent NetworkType = "Transparent"
|
||||||
|
L2Bridge NetworkType = "L2Bridge"
|
||||||
|
L2Tunnel NetworkType = "L2Tunnel"
|
||||||
|
ICS NetworkType = "ICS"
|
||||||
|
Private NetworkType = "Private"
|
||||||
|
Overlay NetworkType = "Overlay"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HostComputeNetwork represents a network
|
||||||
|
type HostComputeNetwork struct {
|
||||||
|
Id string `json:"ID,omitempty"`
|
||||||
|
Name string `json:",omitempty"`
|
||||||
|
Type NetworkType `json:",omitempty"`
|
||||||
|
Policies []NetworkPolicy `json:",omitempty"`
|
||||||
|
MacPool MacPool `json:",omitempty"`
|
||||||
|
Dns Dns `json:",omitempty"`
|
||||||
|
Ipams []Ipam `json:",omitempty"`
|
||||||
|
Flags uint32 `json:",omitempty"` // 0: None
|
||||||
|
SchemaVersion SchemaVersion `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NetworkResourceType are the 3 different Network settings resources.
|
||||||
|
type NetworkResourceType string
|
||||||
|
|
||||||
|
var (
|
||||||
|
// NetworkResourceTypePolicy is for Network's policies. Ex: RemoteSubnet
|
||||||
|
NetworkResourceTypePolicy NetworkResourceType = "Policy"
|
||||||
|
// NetworkResourceTypeDNS is for Network's DNS settings.
|
||||||
|
NetworkResourceTypeDNS NetworkResourceType = "DNS"
|
||||||
|
// NetworkResourceTypeExtension is for Network's extension settings.
|
||||||
|
NetworkResourceTypeExtension NetworkResourceType = "Extension"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ModifyNetworkSettingRequest is the structure used to send request to modify an network.
|
||||||
|
// Used to update DNS/extension/policy on an network.
|
||||||
|
type ModifyNetworkSettingRequest struct {
|
||||||
|
ResourceType NetworkResourceType `json:",omitempty"` // Policy, DNS, Extension
|
||||||
|
RequestType RequestType `json:",omitempty"` // Add, Remove, Update, Refresh
|
||||||
|
Settings json.RawMessage `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PolicyNetworkRequest struct {
|
||||||
|
Policies []NetworkPolicy `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func getNetwork(networkGuid guid.GUID, query string) (*HostComputeNetwork, error) {
|
||||||
|
// Open network.
|
||||||
|
var (
|
||||||
|
networkHandle hcnNetwork
|
||||||
|
resultBuffer *uint16
|
||||||
|
propertiesBuffer *uint16
|
||||||
|
)
|
||||||
|
hr := hcnOpenNetwork(&networkGuid, &networkHandle, &resultBuffer)
|
||||||
|
if err := checkForErrors("hcnOpenNetwork", hr, resultBuffer); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Query network.
|
||||||
|
hr = hcnQueryNetworkProperties(networkHandle, query, &propertiesBuffer, &resultBuffer)
|
||||||
|
if err := checkForErrors("hcnQueryNetworkProperties", hr, resultBuffer); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
properties := interop.ConvertAndFreeCoTaskMemString(propertiesBuffer)
|
||||||
|
// Close network.
|
||||||
|
hr = hcnCloseNetwork(networkHandle)
|
||||||
|
if err := checkForErrors("hcnCloseNetwork", hr, nil); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Convert output to HostComputeNetwork
|
||||||
|
var outputNetwork HostComputeNetwork
|
||||||
|
if err := json.Unmarshal([]byte(properties), &outputNetwork); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &outputNetwork, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func enumerateNetworks(query string) ([]HostComputeNetwork, error) {
|
||||||
|
// Enumerate all Network Guids
|
||||||
|
var (
|
||||||
|
resultBuffer *uint16
|
||||||
|
networkBuffer *uint16
|
||||||
|
)
|
||||||
|
hr := hcnEnumerateNetworks(query, &networkBuffer, &resultBuffer)
|
||||||
|
if err := checkForErrors("hcnEnumerateNetworks", hr, resultBuffer); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
networks := interop.ConvertAndFreeCoTaskMemString(networkBuffer)
|
||||||
|
var networkIds []guid.GUID
|
||||||
|
if err := json.Unmarshal([]byte(networks), &networkIds); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var outputNetworks []HostComputeNetwork
|
||||||
|
for _, networkGuid := range networkIds {
|
||||||
|
network, err := getNetwork(networkGuid, query)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
outputNetworks = append(outputNetworks, *network)
|
||||||
|
}
|
||||||
|
return outputNetworks, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func createNetwork(settings string) (*HostComputeNetwork, error) {
|
||||||
|
// Create new network.
|
||||||
|
var (
|
||||||
|
networkHandle hcnNetwork
|
||||||
|
resultBuffer *uint16
|
||||||
|
propertiesBuffer *uint16
|
||||||
|
)
|
||||||
|
networkGuid := guid.GUID{}
|
||||||
|
hr := hcnCreateNetwork(&networkGuid, settings, &networkHandle, &resultBuffer)
|
||||||
|
if err := checkForErrors("hcnCreateNetwork", hr, resultBuffer); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Query network.
|
||||||
|
hcnQuery := defaultQuery()
|
||||||
|
query, err := json.Marshal(hcnQuery)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
hr = hcnQueryNetworkProperties(networkHandle, string(query), &propertiesBuffer, &resultBuffer)
|
||||||
|
if err := checkForErrors("hcnQueryNetworkProperties", hr, resultBuffer); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
properties := interop.ConvertAndFreeCoTaskMemString(propertiesBuffer)
|
||||||
|
// Close network.
|
||||||
|
hr = hcnCloseNetwork(networkHandle)
|
||||||
|
if err := checkForErrors("hcnCloseNetwork", hr, nil); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Convert output to HostComputeNetwork
|
||||||
|
var outputNetwork HostComputeNetwork
|
||||||
|
if err := json.Unmarshal([]byte(properties), &outputNetwork); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &outputNetwork, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func modifyNetwork(networkId string, settings string) (*HostComputeNetwork, error) {
|
||||||
|
networkGuid := guid.FromString(networkId)
|
||||||
|
// Open Network
|
||||||
|
var (
|
||||||
|
networkHandle hcnNetwork
|
||||||
|
resultBuffer *uint16
|
||||||
|
propertiesBuffer *uint16
|
||||||
|
)
|
||||||
|
hr := hcnOpenNetwork(&networkGuid, &networkHandle, &resultBuffer)
|
||||||
|
if err := checkForErrors("hcnOpenNetwork", hr, resultBuffer); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Modify Network
|
||||||
|
hr = hcnModifyNetwork(networkHandle, settings, &resultBuffer)
|
||||||
|
if err := checkForErrors("hcnModifyNetwork", hr, resultBuffer); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Query network.
|
||||||
|
hcnQuery := defaultQuery()
|
||||||
|
query, err := json.Marshal(hcnQuery)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
hr = hcnQueryNetworkProperties(networkHandle, string(query), &propertiesBuffer, &resultBuffer)
|
||||||
|
if err := checkForErrors("hcnQueryNetworkProperties", hr, resultBuffer); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
properties := interop.ConvertAndFreeCoTaskMemString(propertiesBuffer)
|
||||||
|
// Close network.
|
||||||
|
hr = hcnCloseNetwork(networkHandle)
|
||||||
|
if err := checkForErrors("hcnCloseNetwork", hr, nil); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Convert output to HostComputeNetwork
|
||||||
|
var outputNetwork HostComputeNetwork
|
||||||
|
if err := json.Unmarshal([]byte(properties), &outputNetwork); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &outputNetwork, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteNetwork(networkId string) error {
|
||||||
|
networkGuid := guid.FromString(networkId)
|
||||||
|
var resultBuffer *uint16
|
||||||
|
hr := hcnDeleteNetwork(&networkGuid, &resultBuffer)
|
||||||
|
if err := checkForErrors("hcnDeleteNetwork", hr, resultBuffer); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListNetworks makes a call to list all available networks.
|
||||||
|
func ListNetworks() ([]HostComputeNetwork, error) {
|
||||||
|
hcnQuery := defaultQuery()
|
||||||
|
networks, err := ListNetworksQuery(hcnQuery)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return networks, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListNetworksQuery makes a call to query the list of available networks.
|
||||||
|
func ListNetworksQuery(query HostComputeQuery) ([]HostComputeNetwork, error) {
|
||||||
|
queryJson, err := json.Marshal(query)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
networks, err := enumerateNetworks(string(queryJson))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return networks, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetNetworkByID returns the network specified by Id.
|
||||||
|
func GetNetworkByID(networkID string) (*HostComputeNetwork, error) {
|
||||||
|
hcnQuery := defaultQuery()
|
||||||
|
mapA := map[string]string{"ID": networkID}
|
||||||
|
filter, err := json.Marshal(mapA)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
hcnQuery.Filter = string(filter)
|
||||||
|
|
||||||
|
networks, err := ListNetworksQuery(hcnQuery)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(networks) == 0 {
|
||||||
|
return nil, NetworkNotFoundError{NetworkID: networkID}
|
||||||
|
}
|
||||||
|
return &networks[0], err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetNetworkByName returns the network specified by Name.
|
||||||
|
func GetNetworkByName(networkName string) (*HostComputeNetwork, error) {
|
||||||
|
hcnQuery := defaultQuery()
|
||||||
|
mapA := map[string]string{"Name": networkName}
|
||||||
|
filter, err := json.Marshal(mapA)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
hcnQuery.Filter = string(filter)
|
||||||
|
|
||||||
|
networks, err := ListNetworksQuery(hcnQuery)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(networks) == 0 {
|
||||||
|
return nil, NetworkNotFoundError{NetworkName: networkName}
|
||||||
|
}
|
||||||
|
return &networks[0], err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create Network.
|
||||||
|
func (network *HostComputeNetwork) Create() (*HostComputeNetwork, error) {
|
||||||
|
logrus.Debugf("hcn::HostComputeNetwork::Create id=%s", network.Id)
|
||||||
|
|
||||||
|
jsonString, err := json.Marshal(network)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.Debugf("hcn::HostComputeNetwork::Create JSON: %s", jsonString)
|
||||||
|
network, hcnErr := createNetwork(string(jsonString))
|
||||||
|
if hcnErr != nil {
|
||||||
|
return nil, hcnErr
|
||||||
|
}
|
||||||
|
return network, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete Network.
|
||||||
|
func (network *HostComputeNetwork) Delete() (*HostComputeNetwork, error) {
|
||||||
|
logrus.Debugf("hcn::HostComputeNetwork::Delete id=%s", network.Id)
|
||||||
|
|
||||||
|
if err := deleteNetwork(network.Id); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ModifyNetworkSettings updates the Policy for a network.
|
||||||
|
func (network *HostComputeNetwork) ModifyNetworkSettings(request *ModifyNetworkSettingRequest) error {
|
||||||
|
logrus.Debugf("hcn::HostComputeNetwork::ModifyNetworkSettings id=%s", network.Id)
|
||||||
|
|
||||||
|
networkSettingsRequest, err := json.Marshal(request)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = modifyNetwork(network.Id, string(networkSettingsRequest))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddPolicy applies a Policy (ex: RemoteSubnet) on the Network.
|
||||||
|
func (network *HostComputeNetwork) AddPolicy(networkPolicy PolicyNetworkRequest) error {
|
||||||
|
logrus.Debugf("hcn::HostComputeNetwork::AddPolicy id=%s", network.Id)
|
||||||
|
|
||||||
|
settingsJson, err := json.Marshal(networkPolicy)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
requestMessage := &ModifyNetworkSettingRequest{
|
||||||
|
ResourceType: NetworkResourceTypePolicy,
|
||||||
|
RequestType: RequestTypeAdd,
|
||||||
|
Settings: settingsJson,
|
||||||
|
}
|
||||||
|
|
||||||
|
return network.ModifyNetworkSettings(requestMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemovePolicy removes a Policy (ex: RemoteSubnet) from the Network.
|
||||||
|
func (network *HostComputeNetwork) RemovePolicy(networkPolicy PolicyNetworkRequest) error {
|
||||||
|
logrus.Debugf("hcn::HostComputeNetwork::RemovePolicy id=%s", network.Id)
|
||||||
|
|
||||||
|
settingsJson, err := json.Marshal(networkPolicy)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
requestMessage := &ModifyNetworkSettingRequest{
|
||||||
|
ResourceType: NetworkResourceTypePolicy,
|
||||||
|
RequestType: RequestTypeRemove,
|
||||||
|
Settings: settingsJson,
|
||||||
|
}
|
||||||
|
|
||||||
|
return network.ModifyNetworkSettings(requestMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateEndpoint creates an endpoint on the Network.
|
||||||
|
func (network *HostComputeNetwork) CreateEndpoint(endpoint *HostComputeEndpoint) (*HostComputeEndpoint, error) {
|
||||||
|
isRemote := endpoint.Flags&EndpointFlagsRemoteEndpoint != 0
|
||||||
|
logrus.Debugf("hcn::HostComputeNetwork::CreatEndpoint, networkId=%s remote=%t", network.Id, isRemote)
|
||||||
|
|
||||||
|
endpoint.HostComputeNetwork = network.Id
|
||||||
|
endpointSettings, err := json.Marshal(endpoint)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
newEndpoint, err := createEndpoint(network.Id, string(endpointSettings))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return newEndpoint, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateRemoteEndpoint creates a remote endpoint on the Network.
|
||||||
|
func (network *HostComputeNetwork) CreateRemoteEndpoint(endpoint *HostComputeEndpoint) (*HostComputeEndpoint, error) {
|
||||||
|
endpoint.Flags = EndpointFlagsRemoteEndpoint | endpoint.Flags
|
||||||
|
return network.CreateEndpoint(endpoint)
|
||||||
|
}
|
216
vendor/github.com/Microsoft/hcsshim/hcn/hcnpolicy.go
generated
vendored
Normal file
216
vendor/github.com/Microsoft/hcsshim/hcn/hcnpolicy.go
generated
vendored
Normal file
@ -0,0 +1,216 @@
|
|||||||
|
package hcn
|
||||||
|
|
||||||
|
import "encoding/json"
|
||||||
|
|
||||||
|
// EndpointPolicyType are the potential Policies that apply to Endpoints.
|
||||||
|
type EndpointPolicyType string
|
||||||
|
|
||||||
|
// EndpointPolicyType const
|
||||||
|
const (
|
||||||
|
PortMapping EndpointPolicyType = "PortMapping"
|
||||||
|
ACL EndpointPolicyType = "ACL"
|
||||||
|
QOS EndpointPolicyType = "QOS"
|
||||||
|
L2Driver EndpointPolicyType = "L2Driver"
|
||||||
|
OutBoundNAT EndpointPolicyType = "OutBoundNAT"
|
||||||
|
SDNRoute EndpointPolicyType = "SDNRoute"
|
||||||
|
L4Proxy EndpointPolicyType = "L4Proxy"
|
||||||
|
PortName EndpointPolicyType = "PortName"
|
||||||
|
EncapOverhead EndpointPolicyType = "EncapOverhead"
|
||||||
|
// Endpoint and Network have InterfaceConstraint and ProviderAddress
|
||||||
|
NetworkProviderAddress EndpointPolicyType = "ProviderAddress"
|
||||||
|
NetworkInterfaceConstraint EndpointPolicyType = "InterfaceConstraint"
|
||||||
|
)
|
||||||
|
|
||||||
|
// EndpointPolicy is a collection of Policy settings for an Endpoint.
|
||||||
|
type EndpointPolicy struct {
|
||||||
|
Type EndpointPolicyType `json:""`
|
||||||
|
Settings json.RawMessage `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NetworkPolicyType are the potential Policies that apply to Networks.
|
||||||
|
type NetworkPolicyType string
|
||||||
|
|
||||||
|
// NetworkPolicyType const
|
||||||
|
const (
|
||||||
|
SourceMacAddress NetworkPolicyType = "SourceMacAddress"
|
||||||
|
NetAdapterName NetworkPolicyType = "NetAdapterName"
|
||||||
|
VSwitchExtension NetworkPolicyType = "VSwitchExtension"
|
||||||
|
DrMacAddress NetworkPolicyType = "DrMacAddress"
|
||||||
|
AutomaticDNS NetworkPolicyType = "AutomaticDNS"
|
||||||
|
InterfaceConstraint NetworkPolicyType = "InterfaceConstraint"
|
||||||
|
ProviderAddress NetworkPolicyType = "ProviderAddress"
|
||||||
|
RemoteSubnetRoute NetworkPolicyType = "RemoteSubnetRoute"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NetworkPolicy is a collection of Policy settings for a Network.
|
||||||
|
type NetworkPolicy struct {
|
||||||
|
Type NetworkPolicyType `json:""`
|
||||||
|
Settings json.RawMessage `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SubnetPolicyType are the potential Policies that apply to Subnets.
|
||||||
|
type SubnetPolicyType string
|
||||||
|
|
||||||
|
// SubnetPolicyType const
|
||||||
|
const (
|
||||||
|
VLAN SubnetPolicyType = "VLAN"
|
||||||
|
VSID SubnetPolicyType = "VSID"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SubnetPolicy is a collection of Policy settings for a Subnet.
|
||||||
|
type SubnetPolicy struct {
|
||||||
|
Type SubnetPolicyType `json:""`
|
||||||
|
Settings json.RawMessage `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Endpoint Policy objects
|
||||||
|
|
||||||
|
// PortMappingPolicySetting defines Port Mapping (NAT)
|
||||||
|
type PortMappingPolicySetting struct {
|
||||||
|
Protocol uint32 `json:",omitempty"` // EX: TCP = 6, UDP = 17
|
||||||
|
InternalPort uint16 `json:",omitempty"`
|
||||||
|
ExternalPort uint16 `json:",omitempty"`
|
||||||
|
VIP string `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ActionType associated with ACLs. Value is either Allow or Block.
|
||||||
|
type ActionType string
|
||||||
|
|
||||||
|
// DirectionType associated with ACLs. Value is either In or Out.
|
||||||
|
type DirectionType string
|
||||||
|
|
||||||
|
// RuleType associated with ACLs. Value is either Host (WFP) or Switch (VFP).
|
||||||
|
type RuleType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Allow traffic
|
||||||
|
ActionTypeAllow ActionType = "Allow"
|
||||||
|
// Block traffic
|
||||||
|
ActionTypeBlock ActionType = "Block"
|
||||||
|
|
||||||
|
// In is traffic coming to the Endpoint
|
||||||
|
DirectionTypeIn DirectionType = "In"
|
||||||
|
// Out is traffic leaving the Endpoint
|
||||||
|
DirectionTypeOut DirectionType = "Out"
|
||||||
|
|
||||||
|
// Host creates WFP (Windows Firewall) rules
|
||||||
|
RuleTypeHost RuleType = "Host"
|
||||||
|
// Switch creates VFP (Virtual Filter Platform) rules
|
||||||
|
RuleTypeSwitch RuleType = "Switch"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AclPolicySetting creates firewall rules on an endpoint
|
||||||
|
type AclPolicySetting struct {
|
||||||
|
Protocols string `json:",omitempty"` // EX: 6 (TCP), 17 (UDP), 1 (ICMPv4), 58 (ICMPv6), 2 (IGMP)
|
||||||
|
Action ActionType `json:","`
|
||||||
|
Direction DirectionType `json:","`
|
||||||
|
LocalAddresses string `json:",omitempty"`
|
||||||
|
RemoteAddresses string `json:",omitempty"`
|
||||||
|
LocalPorts string `json:",omitempty"`
|
||||||
|
RemotePorts string `json:",omitempty"`
|
||||||
|
RuleType RuleType `json:",omitempty"`
|
||||||
|
Priority uint16 `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// QosPolicySetting sets Quality of Service bandwidth caps on an Endpoint.
|
||||||
|
type QosPolicySetting struct {
|
||||||
|
MaximumOutgoingBandwidthInBytes uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
// OutboundNatPolicySetting sets outbound Network Address Translation on an Endpoint.
|
||||||
|
type OutboundNatPolicySetting struct {
|
||||||
|
VirtualIP string `json:",omitempty"`
|
||||||
|
Exceptions []string `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SDNRoutePolicySetting sets SDN Route on an Endpoint.
|
||||||
|
type SDNRoutePolicySetting struct {
|
||||||
|
DestinationPrefix string `json:",omitempty"`
|
||||||
|
NextHop string `json:",omitempty"`
|
||||||
|
NeedEncap bool `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// L4ProxyPolicySetting sets Layer-4 Proxy on an endpoint.
|
||||||
|
type L4ProxyPolicySetting struct {
|
||||||
|
IP string `json:",omitempty"`
|
||||||
|
Port string `json:",omitempty"`
|
||||||
|
Protocol uint32 `json:",omitempty"` // EX: TCP = 6, UDP = 17
|
||||||
|
ExceptionList []string `json:",omitempty"`
|
||||||
|
Destination string `json:","`
|
||||||
|
OutboundNat bool `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PortnameEndpointPolicySetting sets the port name for an endpoint.
|
||||||
|
type PortnameEndpointPolicySetting struct {
|
||||||
|
Name string `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncapOverheadEndpointPolicySetting sets the encap overhead for an endpoint.
|
||||||
|
type EncapOverheadEndpointPolicySetting struct {
|
||||||
|
Overhead uint16 `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Endpoint and Network Policy objects
|
||||||
|
|
||||||
|
// ProviderAddressEndpointPolicySetting sets the PA for an endpoint.
|
||||||
|
type ProviderAddressEndpointPolicySetting struct {
|
||||||
|
ProviderAddress string `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// InterfaceConstraintPolicySetting limits an Endpoint or Network to a specific Nic.
|
||||||
|
type InterfaceConstraintPolicySetting struct {
|
||||||
|
InterfaceGuid string `json:",omitempty"`
|
||||||
|
InterfaceLuid uint64 `json:",omitempty"`
|
||||||
|
InterfaceIndex uint32 `json:",omitempty"`
|
||||||
|
InterfaceMediaType uint32 `json:",omitempty"`
|
||||||
|
InterfaceAlias string `json:",omitempty"`
|
||||||
|
InterfaceDescription string `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Network Policy objects
|
||||||
|
|
||||||
|
// SourceMacAddressNetworkPolicySetting sets source MAC for a network.
|
||||||
|
type SourceMacAddressNetworkPolicySetting struct {
|
||||||
|
SourceMacAddress string `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NetAdapterNameNetworkPolicySetting sets network adapter of a network.
|
||||||
|
type NetAdapterNameNetworkPolicySetting struct {
|
||||||
|
NetworkAdapterName string `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// VSwitchExtensionNetworkPolicySetting enables/disabled VSwitch extensions for a network.
|
||||||
|
type VSwitchExtensionNetworkPolicySetting struct {
|
||||||
|
ExtensionID string `json:",omitempty"`
|
||||||
|
Enable bool `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DrMacAddressNetworkPolicySetting sets the DR MAC for a network.
|
||||||
|
type DrMacAddressNetworkPolicySetting struct {
|
||||||
|
Address string `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AutomaticDNSNetworkPolicySetting enables/disables automatic DNS on a network.
|
||||||
|
type AutomaticDNSNetworkPolicySetting struct {
|
||||||
|
Enable bool `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Subnet Policy objects
|
||||||
|
|
||||||
|
// VlanPolicySetting isolates a subnet with VLAN tagging.
|
||||||
|
type VlanPolicySetting struct {
|
||||||
|
IsolationId uint32 `json:","`
|
||||||
|
}
|
||||||
|
|
||||||
|
// VsidPolicySetting isolates a subnet with VSID tagging.
|
||||||
|
type VsidPolicySetting struct {
|
||||||
|
IsolationId uint32 `json:","`
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoteSubnetRoutePolicySetting creates remote subnet route rules on a network
|
||||||
|
type RemoteSubnetRoutePolicySetting struct {
|
||||||
|
DestinationPrefix string
|
||||||
|
IsolationId uint16
|
||||||
|
ProviderAddress string
|
||||||
|
DistributedRouterMacAddress string
|
||||||
|
}
|
64
vendor/github.com/Microsoft/hcsshim/hcn/hcnsupport.go
generated
vendored
Normal file
64
vendor/github.com/Microsoft/hcsshim/hcn/hcnsupport.go
generated
vendored
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
package hcn
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SupportedFeatures are the features provided by the Service.
|
||||||
|
type SupportedFeatures struct {
|
||||||
|
Acl AclFeatures `json:"ACL"`
|
||||||
|
Api ApiSupport `json:"API"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AclFeatures are the supported ACL possibilities.
|
||||||
|
type AclFeatures struct {
|
||||||
|
AclAddressLists bool `json:"AclAddressLists"`
|
||||||
|
AclNoHostRulePriority bool `json:"AclHostRulePriority"`
|
||||||
|
AclPortRanges bool `json:"AclPortRanges"`
|
||||||
|
AclRuleId bool `json:"AclRuleId"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApiSupport lists the supported API versions.
|
||||||
|
type ApiSupport struct {
|
||||||
|
V1 bool `json:"V1"`
|
||||||
|
V2 bool `json:"V2"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSupportedFeatures returns the features supported by the Service.
|
||||||
|
func GetSupportedFeatures() SupportedFeatures {
|
||||||
|
var features SupportedFeatures
|
||||||
|
|
||||||
|
globals, err := GetGlobals()
|
||||||
|
if err != nil {
|
||||||
|
// Expected on pre-1803 builds, all features will be false/unsupported
|
||||||
|
logrus.Debugf("Unable to obtain globals: %s", err)
|
||||||
|
return features
|
||||||
|
}
|
||||||
|
|
||||||
|
features.Acl = AclFeatures{
|
||||||
|
AclAddressLists: isFeatureSupported(globals.Version, HNSVersion1803),
|
||||||
|
AclNoHostRulePriority: isFeatureSupported(globals.Version, HNSVersion1803),
|
||||||
|
AclPortRanges: isFeatureSupported(globals.Version, HNSVersion1803),
|
||||||
|
AclRuleId: isFeatureSupported(globals.Version, HNSVersion1803),
|
||||||
|
}
|
||||||
|
|
||||||
|
features.Api = ApiSupport{
|
||||||
|
V2: isFeatureSupported(globals.Version, V2ApiSupport),
|
||||||
|
V1: true, // HNSCall is still available.
|
||||||
|
}
|
||||||
|
|
||||||
|
return features
|
||||||
|
}
|
||||||
|
|
||||||
|
func isFeatureSupported(currentVersion Version, minVersionSupported Version) bool {
|
||||||
|
if currentVersion.Major < minVersionSupported.Major {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if currentVersion.Major > minVersionSupported.Major {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if currentVersion.Minor < minVersionSupported.Minor {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
613
vendor/github.com/Microsoft/hcsshim/hcn/zsyscall_windows.go
generated
vendored
Normal file
613
vendor/github.com/Microsoft/hcsshim/hcn/zsyscall_windows.go
generated
vendored
Normal file
@ -0,0 +1,613 @@
|
|||||||
|
// Code generated mksyscall_windows.exe DO NOT EDIT
|
||||||
|
|
||||||
|
package hcn
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/Microsoft/hcsshim/internal/interop"
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ unsafe.Pointer
|
||||||
|
|
||||||
|
// Do the interface allocations only once for common
|
||||||
|
// Errno values.
|
||||||
|
const (
|
||||||
|
errnoERROR_IO_PENDING = 997
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
|
||||||
|
)
|
||||||
|
|
||||||
|
// errnoErr returns common boxed Errno values, to prevent
|
||||||
|
// allocations at runtime.
|
||||||
|
func errnoErr(e syscall.Errno) error {
|
||||||
|
switch e {
|
||||||
|
case 0:
|
||||||
|
return nil
|
||||||
|
case errnoERROR_IO_PENDING:
|
||||||
|
return errERROR_IO_PENDING
|
||||||
|
}
|
||||||
|
// TODO: add more here, after collecting data on the common
|
||||||
|
// error values see on Windows. (perhaps when running
|
||||||
|
// all.bat?)
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
modiphlpapi = windows.NewLazySystemDLL("iphlpapi.dll")
|
||||||
|
modvmcompute = windows.NewLazySystemDLL("vmcompute.dll")
|
||||||
|
modcomputenetwork = windows.NewLazySystemDLL("computenetwork.dll")
|
||||||
|
|
||||||
|
procSetCurrentThreadCompartmentId = modiphlpapi.NewProc("SetCurrentThreadCompartmentId")
|
||||||
|
procHNSCall = modvmcompute.NewProc("HNSCall")
|
||||||
|
procHcnEnumerateNetworks = modcomputenetwork.NewProc("HcnEnumerateNetworks")
|
||||||
|
procHcnCreateNetwork = modcomputenetwork.NewProc("HcnCreateNetwork")
|
||||||
|
procHcnOpenNetwork = modcomputenetwork.NewProc("HcnOpenNetwork")
|
||||||
|
procHcnModifyNetwork = modcomputenetwork.NewProc("HcnModifyNetwork")
|
||||||
|
procHcnQueryNetworkProperties = modcomputenetwork.NewProc("HcnQueryNetworkProperties")
|
||||||
|
procHcnDeleteNetwork = modcomputenetwork.NewProc("HcnDeleteNetwork")
|
||||||
|
procHcnCloseNetwork = modcomputenetwork.NewProc("HcnCloseNetwork")
|
||||||
|
procHcnEnumerateEndpoints = modcomputenetwork.NewProc("HcnEnumerateEndpoints")
|
||||||
|
procHcnCreateEndpoint = modcomputenetwork.NewProc("HcnCreateEndpoint")
|
||||||
|
procHcnOpenEndpoint = modcomputenetwork.NewProc("HcnOpenEndpoint")
|
||||||
|
procHcnModifyEndpoint = modcomputenetwork.NewProc("HcnModifyEndpoint")
|
||||||
|
procHcnQueryEndpointProperties = modcomputenetwork.NewProc("HcnQueryEndpointProperties")
|
||||||
|
procHcnDeleteEndpoint = modcomputenetwork.NewProc("HcnDeleteEndpoint")
|
||||||
|
procHcnCloseEndpoint = modcomputenetwork.NewProc("HcnCloseEndpoint")
|
||||||
|
procHcnEnumerateNamespaces = modcomputenetwork.NewProc("HcnEnumerateNamespaces")
|
||||||
|
procHcnCreateNamespace = modcomputenetwork.NewProc("HcnCreateNamespace")
|
||||||
|
procHcnOpenNamespace = modcomputenetwork.NewProc("HcnOpenNamespace")
|
||||||
|
procHcnModifyNamespace = modcomputenetwork.NewProc("HcnModifyNamespace")
|
||||||
|
procHcnQueryNamespaceProperties = modcomputenetwork.NewProc("HcnQueryNamespaceProperties")
|
||||||
|
procHcnDeleteNamespace = modcomputenetwork.NewProc("HcnDeleteNamespace")
|
||||||
|
procHcnCloseNamespace = modcomputenetwork.NewProc("HcnCloseNamespace")
|
||||||
|
procHcnEnumerateLoadBalancers = modcomputenetwork.NewProc("HcnEnumerateLoadBalancers")
|
||||||
|
procHcnCreateLoadBalancer = modcomputenetwork.NewProc("HcnCreateLoadBalancer")
|
||||||
|
procHcnOpenLoadBalancer = modcomputenetwork.NewProc("HcnOpenLoadBalancer")
|
||||||
|
procHcnModifyLoadBalancer = modcomputenetwork.NewProc("HcnModifyLoadBalancer")
|
||||||
|
procHcnQueryLoadBalancerProperties = modcomputenetwork.NewProc("HcnQueryLoadBalancerProperties")
|
||||||
|
procHcnDeleteLoadBalancer = modcomputenetwork.NewProc("HcnDeleteLoadBalancer")
|
||||||
|
procHcnCloseLoadBalancer = modcomputenetwork.NewProc("HcnCloseLoadBalancer")
|
||||||
|
procHcnOpenService = modcomputenetwork.NewProc("HcnOpenService")
|
||||||
|
procHcnRegisterServiceCallback = modcomputenetwork.NewProc("HcnRegisterServiceCallback")
|
||||||
|
procHcnUnregisterServiceCallback = modcomputenetwork.NewProc("HcnUnregisterServiceCallback")
|
||||||
|
procHcnCloseService = modcomputenetwork.NewProc("HcnCloseService")
|
||||||
|
)
|
||||||
|
|
||||||
|
func SetCurrentThreadCompartmentId(compartmentId uint32) (hr error) {
|
||||||
|
r0, _, _ := syscall.Syscall(procSetCurrentThreadCompartmentId.Addr(), 1, uintptr(compartmentId), 0, 0)
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func _hnsCall(method string, path string, object string, response **uint16) (hr error) {
|
||||||
|
var _p0 *uint16
|
||||||
|
_p0, hr = syscall.UTF16PtrFromString(method)
|
||||||
|
if hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var _p1 *uint16
|
||||||
|
_p1, hr = syscall.UTF16PtrFromString(path)
|
||||||
|
if hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var _p2 *uint16
|
||||||
|
_p2, hr = syscall.UTF16PtrFromString(object)
|
||||||
|
if hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return __hnsCall(_p0, _p1, _p2, response)
|
||||||
|
}
|
||||||
|
|
||||||
|
func __hnsCall(method *uint16, path *uint16, object *uint16, response **uint16) (hr error) {
|
||||||
|
if hr = procHNSCall.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall6(procHNSCall.Addr(), 4, uintptr(unsafe.Pointer(method)), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(object)), uintptr(unsafe.Pointer(response)), 0, 0)
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func hcnEnumerateNetworks(query string, networks **uint16, result **uint16) (hr error) {
|
||||||
|
var _p0 *uint16
|
||||||
|
_p0, hr = syscall.UTF16PtrFromString(query)
|
||||||
|
if hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return _hcnEnumerateNetworks(_p0, networks, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _hcnEnumerateNetworks(query *uint16, networks **uint16, result **uint16) (hr error) {
|
||||||
|
if hr = procHcnEnumerateNetworks.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall(procHcnEnumerateNetworks.Addr(), 3, uintptr(unsafe.Pointer(query)), uintptr(unsafe.Pointer(networks)), uintptr(unsafe.Pointer(result)))
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func hcnCreateNetwork(id *_guid, settings string, network *hcnNetwork, result **uint16) (hr error) {
|
||||||
|
var _p0 *uint16
|
||||||
|
_p0, hr = syscall.UTF16PtrFromString(settings)
|
||||||
|
if hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return _hcnCreateNetwork(id, _p0, network, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _hcnCreateNetwork(id *_guid, settings *uint16, network *hcnNetwork, result **uint16) (hr error) {
|
||||||
|
if hr = procHcnCreateNetwork.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall6(procHcnCreateNetwork.Addr(), 4, uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(settings)), uintptr(unsafe.Pointer(network)), uintptr(unsafe.Pointer(result)), 0, 0)
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func hcnOpenNetwork(id *_guid, network *hcnNetwork, result **uint16) (hr error) {
|
||||||
|
if hr = procHcnOpenNetwork.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall(procHcnOpenNetwork.Addr(), 3, uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(network)), uintptr(unsafe.Pointer(result)))
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func hcnModifyNetwork(network hcnNetwork, settings string, result **uint16) (hr error) {
|
||||||
|
var _p0 *uint16
|
||||||
|
_p0, hr = syscall.UTF16PtrFromString(settings)
|
||||||
|
if hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return _hcnModifyNetwork(network, _p0, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _hcnModifyNetwork(network hcnNetwork, settings *uint16, result **uint16) (hr error) {
|
||||||
|
if hr = procHcnModifyNetwork.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall(procHcnModifyNetwork.Addr(), 3, uintptr(network), uintptr(unsafe.Pointer(settings)), uintptr(unsafe.Pointer(result)))
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func hcnQueryNetworkProperties(network hcnNetwork, query string, properties **uint16, result **uint16) (hr error) {
|
||||||
|
var _p0 *uint16
|
||||||
|
_p0, hr = syscall.UTF16PtrFromString(query)
|
||||||
|
if hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return _hcnQueryNetworkProperties(network, _p0, properties, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _hcnQueryNetworkProperties(network hcnNetwork, query *uint16, properties **uint16, result **uint16) (hr error) {
|
||||||
|
if hr = procHcnQueryNetworkProperties.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall6(procHcnQueryNetworkProperties.Addr(), 4, uintptr(network), uintptr(unsafe.Pointer(query)), uintptr(unsafe.Pointer(properties)), uintptr(unsafe.Pointer(result)), 0, 0)
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func hcnDeleteNetwork(id *_guid, result **uint16) (hr error) {
|
||||||
|
if hr = procHcnDeleteNetwork.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall(procHcnDeleteNetwork.Addr(), 2, uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(result)), 0)
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func hcnCloseNetwork(network hcnNetwork) (hr error) {
|
||||||
|
if hr = procHcnCloseNetwork.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall(procHcnCloseNetwork.Addr(), 1, uintptr(network), 0, 0)
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func hcnEnumerateEndpoints(query string, endpoints **uint16, result **uint16) (hr error) {
|
||||||
|
var _p0 *uint16
|
||||||
|
_p0, hr = syscall.UTF16PtrFromString(query)
|
||||||
|
if hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return _hcnEnumerateEndpoints(_p0, endpoints, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _hcnEnumerateEndpoints(query *uint16, endpoints **uint16, result **uint16) (hr error) {
|
||||||
|
if hr = procHcnEnumerateEndpoints.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall(procHcnEnumerateEndpoints.Addr(), 3, uintptr(unsafe.Pointer(query)), uintptr(unsafe.Pointer(endpoints)), uintptr(unsafe.Pointer(result)))
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func hcnCreateEndpoint(network hcnNetwork, id *_guid, settings string, endpoint *hcnEndpoint, result **uint16) (hr error) {
|
||||||
|
var _p0 *uint16
|
||||||
|
_p0, hr = syscall.UTF16PtrFromString(settings)
|
||||||
|
if hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return _hcnCreateEndpoint(network, id, _p0, endpoint, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _hcnCreateEndpoint(network hcnNetwork, id *_guid, settings *uint16, endpoint *hcnEndpoint, result **uint16) (hr error) {
|
||||||
|
if hr = procHcnCreateEndpoint.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall6(procHcnCreateEndpoint.Addr(), 5, uintptr(network), uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(settings)), uintptr(unsafe.Pointer(endpoint)), uintptr(unsafe.Pointer(result)), 0)
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func hcnOpenEndpoint(id *_guid, endpoint *hcnEndpoint, result **uint16) (hr error) {
|
||||||
|
if hr = procHcnOpenEndpoint.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall(procHcnOpenEndpoint.Addr(), 3, uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(endpoint)), uintptr(unsafe.Pointer(result)))
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func hcnModifyEndpoint(endpoint hcnEndpoint, settings string, result **uint16) (hr error) {
|
||||||
|
var _p0 *uint16
|
||||||
|
_p0, hr = syscall.UTF16PtrFromString(settings)
|
||||||
|
if hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return _hcnModifyEndpoint(endpoint, _p0, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _hcnModifyEndpoint(endpoint hcnEndpoint, settings *uint16, result **uint16) (hr error) {
|
||||||
|
if hr = procHcnModifyEndpoint.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall(procHcnModifyEndpoint.Addr(), 3, uintptr(endpoint), uintptr(unsafe.Pointer(settings)), uintptr(unsafe.Pointer(result)))
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func hcnQueryEndpointProperties(endpoint hcnEndpoint, query string, properties **uint16, result **uint16) (hr error) {
|
||||||
|
var _p0 *uint16
|
||||||
|
_p0, hr = syscall.UTF16PtrFromString(query)
|
||||||
|
if hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return _hcnQueryEndpointProperties(endpoint, _p0, properties, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _hcnQueryEndpointProperties(endpoint hcnEndpoint, query *uint16, properties **uint16, result **uint16) (hr error) {
|
||||||
|
if hr = procHcnQueryEndpointProperties.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall6(procHcnQueryEndpointProperties.Addr(), 4, uintptr(endpoint), uintptr(unsafe.Pointer(query)), uintptr(unsafe.Pointer(properties)), uintptr(unsafe.Pointer(result)), 0, 0)
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func hcnDeleteEndpoint(id *_guid, result **uint16) (hr error) {
|
||||||
|
if hr = procHcnDeleteEndpoint.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall(procHcnDeleteEndpoint.Addr(), 2, uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(result)), 0)
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func hcnCloseEndpoint(endpoint hcnEndpoint) (hr error) {
|
||||||
|
if hr = procHcnCloseEndpoint.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall(procHcnCloseEndpoint.Addr(), 1, uintptr(endpoint), 0, 0)
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func hcnEnumerateNamespaces(query string, namespaces **uint16, result **uint16) (hr error) {
|
||||||
|
var _p0 *uint16
|
||||||
|
_p0, hr = syscall.UTF16PtrFromString(query)
|
||||||
|
if hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return _hcnEnumerateNamespaces(_p0, namespaces, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _hcnEnumerateNamespaces(query *uint16, namespaces **uint16, result **uint16) (hr error) {
|
||||||
|
if hr = procHcnEnumerateNamespaces.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall(procHcnEnumerateNamespaces.Addr(), 3, uintptr(unsafe.Pointer(query)), uintptr(unsafe.Pointer(namespaces)), uintptr(unsafe.Pointer(result)))
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func hcnCreateNamespace(id *_guid, settings string, namespace *hcnNamespace, result **uint16) (hr error) {
|
||||||
|
var _p0 *uint16
|
||||||
|
_p0, hr = syscall.UTF16PtrFromString(settings)
|
||||||
|
if hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return _hcnCreateNamespace(id, _p0, namespace, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _hcnCreateNamespace(id *_guid, settings *uint16, namespace *hcnNamespace, result **uint16) (hr error) {
|
||||||
|
if hr = procHcnCreateNamespace.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall6(procHcnCreateNamespace.Addr(), 4, uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(settings)), uintptr(unsafe.Pointer(namespace)), uintptr(unsafe.Pointer(result)), 0, 0)
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func hcnOpenNamespace(id *_guid, namespace *hcnNamespace, result **uint16) (hr error) {
|
||||||
|
if hr = procHcnOpenNamespace.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall(procHcnOpenNamespace.Addr(), 3, uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(namespace)), uintptr(unsafe.Pointer(result)))
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func hcnModifyNamespace(namespace hcnNamespace, settings string, result **uint16) (hr error) {
|
||||||
|
var _p0 *uint16
|
||||||
|
_p0, hr = syscall.UTF16PtrFromString(settings)
|
||||||
|
if hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return _hcnModifyNamespace(namespace, _p0, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _hcnModifyNamespace(namespace hcnNamespace, settings *uint16, result **uint16) (hr error) {
|
||||||
|
if hr = procHcnModifyNamespace.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall(procHcnModifyNamespace.Addr(), 3, uintptr(namespace), uintptr(unsafe.Pointer(settings)), uintptr(unsafe.Pointer(result)))
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func hcnQueryNamespaceProperties(namespace hcnNamespace, query string, properties **uint16, result **uint16) (hr error) {
|
||||||
|
var _p0 *uint16
|
||||||
|
_p0, hr = syscall.UTF16PtrFromString(query)
|
||||||
|
if hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return _hcnQueryNamespaceProperties(namespace, _p0, properties, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _hcnQueryNamespaceProperties(namespace hcnNamespace, query *uint16, properties **uint16, result **uint16) (hr error) {
|
||||||
|
if hr = procHcnQueryNamespaceProperties.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall6(procHcnQueryNamespaceProperties.Addr(), 4, uintptr(namespace), uintptr(unsafe.Pointer(query)), uintptr(unsafe.Pointer(properties)), uintptr(unsafe.Pointer(result)), 0, 0)
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func hcnDeleteNamespace(id *_guid, result **uint16) (hr error) {
|
||||||
|
if hr = procHcnDeleteNamespace.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall(procHcnDeleteNamespace.Addr(), 2, uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(result)), 0)
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func hcnCloseNamespace(namespace hcnNamespace) (hr error) {
|
||||||
|
if hr = procHcnCloseNamespace.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall(procHcnCloseNamespace.Addr(), 1, uintptr(namespace), 0, 0)
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func hcnEnumerateLoadBalancers(query string, loadBalancers **uint16, result **uint16) (hr error) {
|
||||||
|
var _p0 *uint16
|
||||||
|
_p0, hr = syscall.UTF16PtrFromString(query)
|
||||||
|
if hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return _hcnEnumerateLoadBalancers(_p0, loadBalancers, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _hcnEnumerateLoadBalancers(query *uint16, loadBalancers **uint16, result **uint16) (hr error) {
|
||||||
|
if hr = procHcnEnumerateLoadBalancers.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall(procHcnEnumerateLoadBalancers.Addr(), 3, uintptr(unsafe.Pointer(query)), uintptr(unsafe.Pointer(loadBalancers)), uintptr(unsafe.Pointer(result)))
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func hcnCreateLoadBalancer(id *_guid, settings string, loadBalancer *hcnLoadBalancer, result **uint16) (hr error) {
|
||||||
|
var _p0 *uint16
|
||||||
|
_p0, hr = syscall.UTF16PtrFromString(settings)
|
||||||
|
if hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return _hcnCreateLoadBalancer(id, _p0, loadBalancer, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _hcnCreateLoadBalancer(id *_guid, settings *uint16, loadBalancer *hcnLoadBalancer, result **uint16) (hr error) {
|
||||||
|
if hr = procHcnCreateLoadBalancer.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall6(procHcnCreateLoadBalancer.Addr(), 4, uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(settings)), uintptr(unsafe.Pointer(loadBalancer)), uintptr(unsafe.Pointer(result)), 0, 0)
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func hcnOpenLoadBalancer(id *_guid, loadBalancer *hcnLoadBalancer, result **uint16) (hr error) {
|
||||||
|
if hr = procHcnOpenLoadBalancer.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall(procHcnOpenLoadBalancer.Addr(), 3, uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(loadBalancer)), uintptr(unsafe.Pointer(result)))
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func hcnModifyLoadBalancer(loadBalancer hcnLoadBalancer, settings string, result **uint16) (hr error) {
|
||||||
|
var _p0 *uint16
|
||||||
|
_p0, hr = syscall.UTF16PtrFromString(settings)
|
||||||
|
if hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return _hcnModifyLoadBalancer(loadBalancer, _p0, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _hcnModifyLoadBalancer(loadBalancer hcnLoadBalancer, settings *uint16, result **uint16) (hr error) {
|
||||||
|
if hr = procHcnModifyLoadBalancer.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall(procHcnModifyLoadBalancer.Addr(), 3, uintptr(loadBalancer), uintptr(unsafe.Pointer(settings)), uintptr(unsafe.Pointer(result)))
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func hcnQueryLoadBalancerProperties(loadBalancer hcnLoadBalancer, query string, properties **uint16, result **uint16) (hr error) {
|
||||||
|
var _p0 *uint16
|
||||||
|
_p0, hr = syscall.UTF16PtrFromString(query)
|
||||||
|
if hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return _hcnQueryLoadBalancerProperties(loadBalancer, _p0, properties, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _hcnQueryLoadBalancerProperties(loadBalancer hcnLoadBalancer, query *uint16, properties **uint16, result **uint16) (hr error) {
|
||||||
|
if hr = procHcnQueryLoadBalancerProperties.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall6(procHcnQueryLoadBalancerProperties.Addr(), 4, uintptr(loadBalancer), uintptr(unsafe.Pointer(query)), uintptr(unsafe.Pointer(properties)), uintptr(unsafe.Pointer(result)), 0, 0)
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func hcnDeleteLoadBalancer(id *_guid, result **uint16) (hr error) {
|
||||||
|
if hr = procHcnDeleteLoadBalancer.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall(procHcnDeleteLoadBalancer.Addr(), 2, uintptr(unsafe.Pointer(id)), uintptr(unsafe.Pointer(result)), 0)
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func hcnCloseLoadBalancer(loadBalancer hcnLoadBalancer) (hr error) {
|
||||||
|
if hr = procHcnCloseLoadBalancer.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall(procHcnCloseLoadBalancer.Addr(), 1, uintptr(loadBalancer), 0, 0)
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func hcnOpenService(service *hcnService, result **uint16) (hr error) {
|
||||||
|
if hr = procHcnOpenService.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall(procHcnOpenService.Addr(), 2, uintptr(unsafe.Pointer(service)), uintptr(unsafe.Pointer(result)), 0)
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func hcnRegisterServiceCallback(service hcnService, callback int32, context int32, callbackHandle *hcnCallbackHandle) (hr error) {
|
||||||
|
if hr = procHcnRegisterServiceCallback.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall6(procHcnRegisterServiceCallback.Addr(), 4, uintptr(service), uintptr(callback), uintptr(context), uintptr(unsafe.Pointer(callbackHandle)), 0, 0)
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func hcnUnregisterServiceCallback(callbackHandle hcnCallbackHandle) (hr error) {
|
||||||
|
if hr = procHcnUnregisterServiceCallback.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall(procHcnUnregisterServiceCallback.Addr(), 1, uintptr(callbackHandle), 0, 0)
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func hcnCloseService(service hcnService) (hr error) {
|
||||||
|
if hr = procHcnCloseService.Find(); hr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r0, _, _ := syscall.Syscall(procHcnCloseService.Addr(), 1, uintptr(service), 0, 0)
|
||||||
|
if int32(r0) < 0 {
|
||||||
|
hr = interop.Win32FromHresult(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
28
vendor/github.com/Microsoft/hcsshim/hcsshim.go
generated
vendored
Normal file
28
vendor/github.com/Microsoft/hcsshim/hcsshim.go
generated
vendored
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
// Shim for the Host Compute Service (HCS) to manage Windows Server
|
||||||
|
// containers and Hyper-V containers.
|
||||||
|
|
||||||
|
package hcsshim
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/Microsoft/hcsshim/internal/hcserror"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:generate go run mksyscall_windows.go -output zsyscall_windows.go hcsshim.go
|
||||||
|
|
||||||
|
//sys SetCurrentThreadCompartmentId(compartmentId uint32) (hr error) = iphlpapi.SetCurrentThreadCompartmentId
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Specific user-visible exit codes
|
||||||
|
WaitErrExecFailed = 32767
|
||||||
|
|
||||||
|
ERROR_GEN_FAILURE = hcserror.ERROR_GEN_FAILURE
|
||||||
|
ERROR_SHUTDOWN_IN_PROGRESS = syscall.Errno(1115)
|
||||||
|
WSAEINVAL = syscall.Errno(10022)
|
||||||
|
|
||||||
|
// Timeout on wait calls
|
||||||
|
TimeoutInfinite = 0xFFFFFFFF
|
||||||
|
)
|
||||||
|
|
||||||
|
type HcsError = hcserror.HcsError
|
94
vendor/github.com/Microsoft/hcsshim/hnsendpoint.go
generated
vendored
Normal file
94
vendor/github.com/Microsoft/hcsshim/hnsendpoint.go
generated
vendored
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
package hcsshim
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/Microsoft/hcsshim/internal/hns"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HNSEndpoint represents a network endpoint in HNS
|
||||||
|
type HNSEndpoint = hns.HNSEndpoint
|
||||||
|
|
||||||
|
// Namespace represents a Compartment.
|
||||||
|
type Namespace = hns.Namespace
|
||||||
|
|
||||||
|
//SystemType represents the type of the system on which actions are done
|
||||||
|
type SystemType string
|
||||||
|
|
||||||
|
// SystemType const
|
||||||
|
const (
|
||||||
|
ContainerType SystemType = "Container"
|
||||||
|
VirtualMachineType SystemType = "VirtualMachine"
|
||||||
|
HostType SystemType = "Host"
|
||||||
|
)
|
||||||
|
|
||||||
|
// EndpointAttachDetachRequest is the structure used to send request to the container to modify the system
|
||||||
|
// Supported resource types are Network and Request Types are Add/Remove
|
||||||
|
type EndpointAttachDetachRequest = hns.EndpointAttachDetachRequest
|
||||||
|
|
||||||
|
// EndpointResquestResponse is object to get the endpoint request response
|
||||||
|
type EndpointResquestResponse = hns.EndpointResquestResponse
|
||||||
|
|
||||||
|
// HNSEndpointRequest makes a HNS call to modify/query a network endpoint
|
||||||
|
func HNSEndpointRequest(method, path, request string) (*HNSEndpoint, error) {
|
||||||
|
return hns.HNSEndpointRequest(method, path, request)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HNSListEndpointRequest makes a HNS call to query the list of available endpoints
|
||||||
|
func HNSListEndpointRequest() ([]HNSEndpoint, error) {
|
||||||
|
return hns.HNSListEndpointRequest()
|
||||||
|
}
|
||||||
|
|
||||||
|
// HotAttachEndpoint makes a HCS Call to attach the endpoint to the container
|
||||||
|
func HotAttachEndpoint(containerID string, endpointID string) error {
|
||||||
|
return modifyNetworkEndpoint(containerID, endpointID, Add)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HotDetachEndpoint makes a HCS Call to detach the endpoint from the container
|
||||||
|
func HotDetachEndpoint(containerID string, endpointID string) error {
|
||||||
|
return modifyNetworkEndpoint(containerID, endpointID, Remove)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ModifyContainer corresponding to the container id, by sending a request
|
||||||
|
func modifyContainer(id string, request *ResourceModificationRequestResponse) error {
|
||||||
|
container, err := OpenContainer(id)
|
||||||
|
if err != nil {
|
||||||
|
if IsNotExist(err) {
|
||||||
|
return ErrComputeSystemDoesNotExist
|
||||||
|
}
|
||||||
|
return getInnerError(err)
|
||||||
|
}
|
||||||
|
defer container.Close()
|
||||||
|
err = container.Modify(request)
|
||||||
|
if err != nil {
|
||||||
|
if IsNotSupported(err) {
|
||||||
|
return ErrPlatformNotSupported
|
||||||
|
}
|
||||||
|
return getInnerError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func modifyNetworkEndpoint(containerID string, endpointID string, request RequestType) error {
|
||||||
|
requestMessage := &ResourceModificationRequestResponse{
|
||||||
|
Resource: Network,
|
||||||
|
Request: request,
|
||||||
|
Data: endpointID,
|
||||||
|
}
|
||||||
|
err := modifyContainer(containerID, requestMessage)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHNSEndpointByID get the Endpoint by ID
|
||||||
|
func GetHNSEndpointByID(endpointID string) (*HNSEndpoint, error) {
|
||||||
|
return hns.GetHNSEndpointByID(endpointID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHNSEndpointByName gets the endpoint filtered by Name
|
||||||
|
func GetHNSEndpointByName(endpointName string) (*HNSEndpoint, error) {
|
||||||
|
return hns.GetHNSEndpointByName(endpointName)
|
||||||
|
}
|
16
vendor/github.com/Microsoft/hcsshim/hnsglobals.go
generated
vendored
Normal file
16
vendor/github.com/Microsoft/hcsshim/hnsglobals.go
generated
vendored
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package hcsshim
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/Microsoft/hcsshim/internal/hns"
|
||||||
|
)
|
||||||
|
|
||||||
|
type HNSGlobals = hns.HNSGlobals
|
||||||
|
type HNSVersion = hns.HNSVersion
|
||||||
|
|
||||||
|
var (
|
||||||
|
HNSVersion1803 = hns.HNSVersion1803
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetHNSGlobals() (*HNSGlobals, error) {
|
||||||
|
return hns.GetHNSGlobals()
|
||||||
|
}
|
36
vendor/github.com/Microsoft/hcsshim/hnsnetwork.go
generated
vendored
Normal file
36
vendor/github.com/Microsoft/hcsshim/hnsnetwork.go
generated
vendored
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
package hcsshim
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/Microsoft/hcsshim/internal/hns"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Subnet is assoicated with a network and represents a list
|
||||||
|
// of subnets available to the network
|
||||||
|
type Subnet = hns.Subnet
|
||||||
|
|
||||||
|
// MacPool is assoicated with a network and represents a list
|
||||||
|
// of macaddresses available to the network
|
||||||
|
type MacPool = hns.MacPool
|
||||||
|
|
||||||
|
// HNSNetwork represents a network in HNS
|
||||||
|
type HNSNetwork = hns.HNSNetwork
|
||||||
|
|
||||||
|
// HNSNetworkRequest makes a call into HNS to update/query a single network
|
||||||
|
func HNSNetworkRequest(method, path, request string) (*HNSNetwork, error) {
|
||||||
|
return hns.HNSNetworkRequest(method, path, request)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HNSListNetworkRequest makes a HNS call to query the list of available networks
|
||||||
|
func HNSListNetworkRequest(method, path, request string) ([]HNSNetwork, error) {
|
||||||
|
return hns.HNSListNetworkRequest(method, path, request)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHNSNetworkByID
|
||||||
|
func GetHNSNetworkByID(networkID string) (*HNSNetwork, error) {
|
||||||
|
return hns.GetHNSNetworkByID(networkID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHNSNetworkName filtered by Name
|
||||||
|
func GetHNSNetworkByName(networkName string) (*HNSNetwork, error) {
|
||||||
|
return hns.GetHNSNetworkByName(networkName)
|
||||||
|
}
|
57
vendor/github.com/Microsoft/hcsshim/hnspolicy.go
generated
vendored
Normal file
57
vendor/github.com/Microsoft/hcsshim/hnspolicy.go
generated
vendored
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
package hcsshim
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/Microsoft/hcsshim/internal/hns"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Type of Request Support in ModifySystem
|
||||||
|
type PolicyType = hns.PolicyType
|
||||||
|
|
||||||
|
// RequestType const
|
||||||
|
const (
|
||||||
|
Nat = hns.Nat
|
||||||
|
ACL = hns.ACL
|
||||||
|
PA = hns.PA
|
||||||
|
VLAN = hns.VLAN
|
||||||
|
VSID = hns.VSID
|
||||||
|
VNet = hns.VNet
|
||||||
|
L2Driver = hns.L2Driver
|
||||||
|
Isolation = hns.Isolation
|
||||||
|
QOS = hns.QOS
|
||||||
|
OutboundNat = hns.OutboundNat
|
||||||
|
ExternalLoadBalancer = hns.ExternalLoadBalancer
|
||||||
|
Route = hns.Route
|
||||||
|
)
|
||||||
|
|
||||||
|
type NatPolicy = hns.NatPolicy
|
||||||
|
|
||||||
|
type QosPolicy = hns.QosPolicy
|
||||||
|
|
||||||
|
type IsolationPolicy = hns.IsolationPolicy
|
||||||
|
|
||||||
|
type VlanPolicy = hns.VlanPolicy
|
||||||
|
|
||||||
|
type VsidPolicy = hns.VsidPolicy
|
||||||
|
|
||||||
|
type PaPolicy = hns.PaPolicy
|
||||||
|
|
||||||
|
type OutboundNatPolicy = hns.OutboundNatPolicy
|
||||||
|
|
||||||
|
type ActionType = hns.ActionType
|
||||||
|
type DirectionType = hns.DirectionType
|
||||||
|
type RuleType = hns.RuleType
|
||||||
|
|
||||||
|
const (
|
||||||
|
Allow = hns.Allow
|
||||||
|
Block = hns.Block
|
||||||
|
|
||||||
|
In = hns.In
|
||||||
|
Out = hns.Out
|
||||||
|
|
||||||
|
Host = hns.Host
|
||||||
|
Switch = hns.Switch
|
||||||
|
)
|
||||||
|
|
||||||
|
type ACLPolicy = hns.ACLPolicy
|
||||||
|
|
||||||
|
type Policy = hns.Policy
|
47
vendor/github.com/Microsoft/hcsshim/hnspolicylist.go
generated
vendored
Normal file
47
vendor/github.com/Microsoft/hcsshim/hnspolicylist.go
generated
vendored
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
package hcsshim
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/Microsoft/hcsshim/internal/hns"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RoutePolicy is a structure defining schema for Route based Policy
|
||||||
|
type RoutePolicy = hns.RoutePolicy
|
||||||
|
|
||||||
|
// ELBPolicy is a structure defining schema for ELB LoadBalancing based Policy
|
||||||
|
type ELBPolicy = hns.ELBPolicy
|
||||||
|
|
||||||
|
// LBPolicy is a structure defining schema for LoadBalancing based Policy
|
||||||
|
type LBPolicy = hns.LBPolicy
|
||||||
|
|
||||||
|
// PolicyList is a structure defining schema for Policy list request
|
||||||
|
type PolicyList = hns.PolicyList
|
||||||
|
|
||||||
|
// HNSPolicyListRequest makes a call into HNS to update/query a single network
|
||||||
|
func HNSPolicyListRequest(method, path, request string) (*PolicyList, error) {
|
||||||
|
return hns.HNSPolicyListRequest(method, path, request)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HNSListPolicyListRequest gets all the policy list
|
||||||
|
func HNSListPolicyListRequest() ([]PolicyList, error) {
|
||||||
|
return hns.HNSListPolicyListRequest()
|
||||||
|
}
|
||||||
|
|
||||||
|
// PolicyListRequest makes a HNS call to modify/query a network policy list
|
||||||
|
func PolicyListRequest(method, path, request string) (*PolicyList, error) {
|
||||||
|
return hns.PolicyListRequest(method, path, request)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPolicyListByID get the policy list by ID
|
||||||
|
func GetPolicyListByID(policyListID string) (*PolicyList, error) {
|
||||||
|
return hns.GetPolicyListByID(policyListID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddLoadBalancer policy list for the specified endpoints
|
||||||
|
func AddLoadBalancer(endpoints []HNSEndpoint, isILB bool, sourceVIP, vip string, protocol uint16, internalPort uint16, externalPort uint16) (*PolicyList, error) {
|
||||||
|
return hns.AddLoadBalancer(endpoints, isILB, sourceVIP, vip, protocol, internalPort, externalPort)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddRoute adds route policy list for the specified endpoints
|
||||||
|
func AddRoute(endpoints []HNSEndpoint, destinationPrefix string, nextHop string, encapEnabled bool) (*PolicyList, error) {
|
||||||
|
return hns.AddRoute(endpoints, destinationPrefix, nextHop, encapEnabled)
|
||||||
|
}
|
13
vendor/github.com/Microsoft/hcsshim/hnssupport.go
generated
vendored
Normal file
13
vendor/github.com/Microsoft/hcsshim/hnssupport.go
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package hcsshim
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/Microsoft/hcsshim/internal/hns"
|
||||||
|
)
|
||||||
|
|
||||||
|
type HNSSupportedFeatures = hns.HNSSupportedFeatures
|
||||||
|
|
||||||
|
type HNSAclFeatures = hns.HNSAclFeatures
|
||||||
|
|
||||||
|
func GetHNSSupportedFeatures() HNSSupportedFeatures {
|
||||||
|
return hns.GetHNSSupportedFeatures()
|
||||||
|
}
|
114
vendor/github.com/Microsoft/hcsshim/interface.go
generated
vendored
Normal file
114
vendor/github.com/Microsoft/hcsshim/interface.go
generated
vendored
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
package hcsshim
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/Microsoft/hcsshim/internal/schema1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ProcessConfig is used as both the input of Container.CreateProcess
|
||||||
|
// and to convert the parameters to JSON for passing onto the HCS
|
||||||
|
type ProcessConfig = schema1.ProcessConfig
|
||||||
|
|
||||||
|
type Layer = schema1.Layer
|
||||||
|
type MappedDir = schema1.MappedDir
|
||||||
|
type MappedPipe = schema1.MappedPipe
|
||||||
|
type HvRuntime = schema1.HvRuntime
|
||||||
|
type MappedVirtualDisk = schema1.MappedVirtualDisk
|
||||||
|
|
||||||
|
// AssignedDevice represents a device that has been directly assigned to a container
|
||||||
|
//
|
||||||
|
// NOTE: Support added in RS5
|
||||||
|
type AssignedDevice = schema1.AssignedDevice
|
||||||
|
|
||||||
|
// ContainerConfig is used as both the input of CreateContainer
|
||||||
|
// and to convert the parameters to JSON for passing onto the HCS
|
||||||
|
type ContainerConfig = schema1.ContainerConfig
|
||||||
|
|
||||||
|
type ComputeSystemQuery = schema1.ComputeSystemQuery
|
||||||
|
|
||||||
|
// Container represents a created (but not necessarily running) container.
|
||||||
|
type Container interface {
|
||||||
|
// Start synchronously starts the container.
|
||||||
|
Start() error
|
||||||
|
|
||||||
|
// Shutdown requests a container shutdown, but it may not actually be shutdown until Wait() succeeds.
|
||||||
|
Shutdown() error
|
||||||
|
|
||||||
|
// Terminate requests a container terminate, but it may not actually be terminated until Wait() succeeds.
|
||||||
|
Terminate() error
|
||||||
|
|
||||||
|
// Waits synchronously waits for the container to shutdown or terminate.
|
||||||
|
Wait() error
|
||||||
|
|
||||||
|
// WaitTimeout synchronously waits for the container to terminate or the duration to elapse. It
|
||||||
|
// returns false if timeout occurs.
|
||||||
|
WaitTimeout(time.Duration) error
|
||||||
|
|
||||||
|
// Pause pauses the execution of a container.
|
||||||
|
Pause() error
|
||||||
|
|
||||||
|
// Resume resumes the execution of a container.
|
||||||
|
Resume() error
|
||||||
|
|
||||||
|
// HasPendingUpdates returns true if the container has updates pending to install.
|
||||||
|
HasPendingUpdates() (bool, error)
|
||||||
|
|
||||||
|
// Statistics returns statistics for a container.
|
||||||
|
Statistics() (Statistics, error)
|
||||||
|
|
||||||
|
// ProcessList returns details for the processes in a container.
|
||||||
|
ProcessList() ([]ProcessListItem, error)
|
||||||
|
|
||||||
|
// MappedVirtualDisks returns virtual disks mapped to a utility VM, indexed by controller
|
||||||
|
MappedVirtualDisks() (map[int]MappedVirtualDiskController, error)
|
||||||
|
|
||||||
|
// CreateProcess launches a new process within the container.
|
||||||
|
CreateProcess(c *ProcessConfig) (Process, error)
|
||||||
|
|
||||||
|
// OpenProcess gets an interface to an existing process within the container.
|
||||||
|
OpenProcess(pid int) (Process, error)
|
||||||
|
|
||||||
|
// Close cleans up any state associated with the container but does not terminate or wait for it.
|
||||||
|
Close() error
|
||||||
|
|
||||||
|
// Modify the System
|
||||||
|
Modify(config *ResourceModificationRequestResponse) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process represents a running or exited process.
|
||||||
|
type Process interface {
|
||||||
|
// Pid returns the process ID of the process within the container.
|
||||||
|
Pid() int
|
||||||
|
|
||||||
|
// Kill signals the process to terminate but does not wait for it to finish terminating.
|
||||||
|
Kill() error
|
||||||
|
|
||||||
|
// Wait waits for the process to exit.
|
||||||
|
Wait() error
|
||||||
|
|
||||||
|
// WaitTimeout waits for the process to exit or the duration to elapse. It returns
|
||||||
|
// false if timeout occurs.
|
||||||
|
WaitTimeout(time.Duration) error
|
||||||
|
|
||||||
|
// ExitCode returns the exit code of the process. The process must have
|
||||||
|
// already terminated.
|
||||||
|
ExitCode() (int, error)
|
||||||
|
|
||||||
|
// ResizeConsole resizes the console of the process.
|
||||||
|
ResizeConsole(width, height uint16) error
|
||||||
|
|
||||||
|
// Stdio returns the stdin, stdout, and stderr pipes, respectively. Closing
|
||||||
|
// these pipes does not close the underlying pipes; it should be possible to
|
||||||
|
// call this multiple times to get multiple interfaces.
|
||||||
|
Stdio() (io.WriteCloser, io.ReadCloser, io.ReadCloser, error)
|
||||||
|
|
||||||
|
// CloseStdin closes the write side of the stdin pipe so that the process is
|
||||||
|
// notified on the read side that there is no more data in stdin.
|
||||||
|
CloseStdin() error
|
||||||
|
|
||||||
|
// Close cleans up any state associated with the process but does not kill
|
||||||
|
// or wait on it.
|
||||||
|
Close() error
|
||||||
|
}
|
110
vendor/github.com/Microsoft/hcsshim/internal/cni/registry.go
generated
vendored
Normal file
110
vendor/github.com/Microsoft/hcsshim/internal/cni/registry.go
generated
vendored
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
package cni
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/Microsoft/hcsshim/internal/guid"
|
||||||
|
"github.com/Microsoft/hcsshim/internal/regstate"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
cniRoot = "cni"
|
||||||
|
cniKey = "cfg"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PersistedNamespaceConfig is the registry version of the `NamespaceID` to UVM
|
||||||
|
// map.
|
||||||
|
type PersistedNamespaceConfig struct {
|
||||||
|
namespaceID string
|
||||||
|
stored bool
|
||||||
|
|
||||||
|
ContainerID string
|
||||||
|
HostUniqueID guid.GUID
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewPersistedNamespaceConfig creates an in-memory namespace config that can be
|
||||||
|
// persisted to the registry.
|
||||||
|
func NewPersistedNamespaceConfig(namespaceID, containerID string, containerHostUniqueID guid.GUID) *PersistedNamespaceConfig {
|
||||||
|
return &PersistedNamespaceConfig{
|
||||||
|
namespaceID: namespaceID,
|
||||||
|
ContainerID: containerID,
|
||||||
|
HostUniqueID: containerHostUniqueID,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadPersistedNamespaceConfig loads a persisted config from the registry that matches
|
||||||
|
// `namespaceID`. If not found returns `regstate.NotFoundError`
|
||||||
|
func LoadPersistedNamespaceConfig(namespaceID string) (*PersistedNamespaceConfig, error) {
|
||||||
|
sk, err := regstate.Open(cniRoot, false)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer sk.Close()
|
||||||
|
|
||||||
|
pnc := PersistedNamespaceConfig{
|
||||||
|
namespaceID: namespaceID,
|
||||||
|
stored: true,
|
||||||
|
}
|
||||||
|
if err := sk.Get(namespaceID, cniKey, &pnc); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &pnc, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store stores or updates the in-memory config to its registry state. If the
|
||||||
|
// store failes returns the store error.
|
||||||
|
func (pnc *PersistedNamespaceConfig) Store() error {
|
||||||
|
if pnc.namespaceID == "" {
|
||||||
|
return errors.New("invalid namespaceID ''")
|
||||||
|
}
|
||||||
|
if pnc.ContainerID == "" {
|
||||||
|
return errors.New("invalid containerID ''")
|
||||||
|
}
|
||||||
|
empty := guid.GUID{}
|
||||||
|
if pnc.HostUniqueID == empty {
|
||||||
|
return errors.New("invalid containerHostUniqueID 'empy'")
|
||||||
|
}
|
||||||
|
sk, err := regstate.Open(cniRoot, false)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer sk.Close()
|
||||||
|
|
||||||
|
if pnc.stored {
|
||||||
|
if err := sk.Set(pnc.namespaceID, cniKey, pnc); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err := sk.Create(pnc.namespaceID, cniKey, pnc); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pnc.stored = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove removes any persisted state associated with this config. If the config
|
||||||
|
// is not found in the registery `Remove` returns no error.
|
||||||
|
func (pnc *PersistedNamespaceConfig) Remove() error {
|
||||||
|
if pnc.stored {
|
||||||
|
sk, err := regstate.Open(cniRoot, false)
|
||||||
|
if err != nil {
|
||||||
|
if regstate.IsNotFoundError(err) {
|
||||||
|
pnc.stored = false
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer sk.Close()
|
||||||
|
|
||||||
|
if err := sk.Remove(pnc.namespaceID); err != nil {
|
||||||
|
if regstate.IsNotFoundError(err) {
|
||||||
|
pnc.stored = false
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pnc.stored = false
|
||||||
|
return nil
|
||||||
|
}
|
85
vendor/github.com/Microsoft/hcsshim/internal/guestrequest/types.go
generated
vendored
Normal file
85
vendor/github.com/Microsoft/hcsshim/internal/guestrequest/types.go
generated
vendored
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
package guestrequest
|
||||||
|
|
||||||
|
import "github.com/Microsoft/hcsshim/internal/schema2"
|
||||||
|
|
||||||
|
// Arguably, many of these (at least CombinedLayers) should have been generated
|
||||||
|
// by swagger.
|
||||||
|
//
|
||||||
|
// This will also change package name due to an inbound breaking change.
|
||||||
|
|
||||||
|
// This class is used by a modify request to add or remove a combined layers
|
||||||
|
// structure in the guest. For windows, the GCS applies a filter in ContainerRootPath
|
||||||
|
// using the specified layers as the parent content. Ignores property ScratchPath
|
||||||
|
// since the container path is already the scratch path. For linux, the GCS unions
|
||||||
|
// the specified layers and ScratchPath together, placing the resulting union
|
||||||
|
// filesystem at ContainerRootPath.
|
||||||
|
type CombinedLayers struct {
|
||||||
|
ContainerRootPath string `json:"ContainerRootPath,omitempty"`
|
||||||
|
Layers []hcsschema.Layer `json:"Layers,omitempty"`
|
||||||
|
ScratchPath string `json:"ScratchPath,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defines the schema for hosted settings passed to GCS and/or OpenGCS
|
||||||
|
|
||||||
|
// SCSI. Scratch space for remote file-system commands, or R/W layer for containers
|
||||||
|
type LCOWMappedVirtualDisk struct {
|
||||||
|
MountPath string `json:"MountPath,omitempty"` // /tmp/scratch for an LCOW utility VM being used as a service VM
|
||||||
|
Lun uint8 `json:"Lun,omitempty"`
|
||||||
|
Controller uint8 `json:"Controller,omitempty"`
|
||||||
|
ReadOnly bool `json:"ReadOnly,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type WCOWMappedVirtualDisk struct {
|
||||||
|
ContainerPath string `json:"ContainerPath,omitempty"`
|
||||||
|
Lun int32 `json:"Lun,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type LCOWMappedDirectory struct {
|
||||||
|
MountPath string `json:"MountPath,omitempty"`
|
||||||
|
Port int32 `json:"Port,omitempty"`
|
||||||
|
ShareName string `json:"ShareName,omitempty"` // If empty not using ANames (not currently supported)
|
||||||
|
ReadOnly bool `json:"ReadOnly,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read-only layers over VPMem
|
||||||
|
type LCOWMappedVPMemDevice struct {
|
||||||
|
DeviceNumber uint32 `json:"DeviceNumber,omitempty"`
|
||||||
|
MountPath string `json:"MountPath,omitempty"` // /tmp/pN
|
||||||
|
}
|
||||||
|
|
||||||
|
type ResourceType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
// These are constants for v2 schema modify guest requests.
|
||||||
|
ResourceTypeMappedDirectory ResourceType = "MappedDirectory"
|
||||||
|
ResourceTypeMappedVirtualDisk ResourceType = "MappedVirtualDisk"
|
||||||
|
ResourceTypeNetwork ResourceType = "Network"
|
||||||
|
ResourceTypeNetworkNamespace ResourceType = "NetworkNamespace"
|
||||||
|
ResourceTypeCombinedLayers ResourceType = "CombinedLayers"
|
||||||
|
ResourceTypeVPMemDevice ResourceType = "VPMemDevice"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GuestRequest is for modify commands passed to the guest.
|
||||||
|
type GuestRequest struct {
|
||||||
|
RequestType string `json:"RequestType,omitempty"`
|
||||||
|
ResourceType ResourceType `json:"ResourceType,omitempty"`
|
||||||
|
Settings interface{} `json:"Settings,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type NetworkModifyRequest struct {
|
||||||
|
AdapterId string `json:"AdapterId,omitempty"`
|
||||||
|
RequestType string `json:"RequestType,omitempty"`
|
||||||
|
Settings interface{} `json:"Settings,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type RS4NetworkModifyRequest struct {
|
||||||
|
AdapterInstanceId string `json:"AdapterInstanceId,omitempty"`
|
||||||
|
RequestType string `json:"RequestType,omitempty"`
|
||||||
|
Settings interface{} `json:"Settings,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignalProcessOptions is the options passed to either WCOW or LCOW
|
||||||
|
// to signal a given process.
|
||||||
|
type SignalProcessOptions struct {
|
||||||
|
Signal int `json:,omitempty`
|
||||||
|
}
|
69
vendor/github.com/Microsoft/hcsshim/internal/guid/guid.go
generated
vendored
Normal file
69
vendor/github.com/Microsoft/hcsshim/internal/guid/guid.go
generated
vendored
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
package guid
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = (json.Marshaler)(&GUID{})
|
||||||
|
var _ = (json.Unmarshaler)(&GUID{})
|
||||||
|
|
||||||
|
type GUID [16]byte
|
||||||
|
|
||||||
|
func New() GUID {
|
||||||
|
g := GUID{}
|
||||||
|
_, err := io.ReadFull(rand.Reader, g[:])
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return g
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g GUID) String() string {
|
||||||
|
return fmt.Sprintf("%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x-%02x", g[3], g[2], g[1], g[0], g[5], g[4], g[7], g[6], g[8:10], g[10:])
|
||||||
|
}
|
||||||
|
|
||||||
|
func FromString(s string) GUID {
|
||||||
|
if len(s) != 36 {
|
||||||
|
panic(fmt.Sprintf("invalid GUID length: %d", len(s)))
|
||||||
|
}
|
||||||
|
if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' {
|
||||||
|
panic("invalid GUID format")
|
||||||
|
}
|
||||||
|
indexOrder := [16]int{
|
||||||
|
0, 2, 4, 6,
|
||||||
|
9, 11,
|
||||||
|
14, 16,
|
||||||
|
19, 21,
|
||||||
|
24, 26, 28, 30, 32, 34,
|
||||||
|
}
|
||||||
|
byteOrder := [16]int{
|
||||||
|
3, 2, 1, 0,
|
||||||
|
5, 4,
|
||||||
|
7, 6,
|
||||||
|
8, 9,
|
||||||
|
10, 11, 12, 13, 14, 15,
|
||||||
|
}
|
||||||
|
var g GUID
|
||||||
|
for i, x := range indexOrder {
|
||||||
|
b, err := strconv.ParseInt(s[x:x+2], 16, 16)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
g[byteOrder[i]] = byte(b)
|
||||||
|
}
|
||||||
|
return g
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g GUID) MarshalJSON() ([]byte, error) {
|
||||||
|
return json.Marshal(g.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *GUID) UnmarshalJSON(data []byte) error {
|
||||||
|
*g = FromString(strings.Trim(string(data), "\""))
|
||||||
|
return nil
|
||||||
|
}
|
88
vendor/github.com/Microsoft/hcsshim/internal/hcs/callback.go
generated
vendored
Normal file
88
vendor/github.com/Microsoft/hcsshim/internal/hcs/callback.go
generated
vendored
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
package hcs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/Microsoft/hcsshim/internal/interop"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
nextCallback uintptr
|
||||||
|
callbackMap = map[uintptr]*notifcationWatcherContext{}
|
||||||
|
callbackMapLock = sync.RWMutex{}
|
||||||
|
|
||||||
|
notificationWatcherCallback = syscall.NewCallback(notificationWatcher)
|
||||||
|
|
||||||
|
// Notifications for HCS_SYSTEM handles
|
||||||
|
hcsNotificationSystemExited hcsNotification = 0x00000001
|
||||||
|
hcsNotificationSystemCreateCompleted hcsNotification = 0x00000002
|
||||||
|
hcsNotificationSystemStartCompleted hcsNotification = 0x00000003
|
||||||
|
hcsNotificationSystemPauseCompleted hcsNotification = 0x00000004
|
||||||
|
hcsNotificationSystemResumeCompleted hcsNotification = 0x00000005
|
||||||
|
|
||||||
|
// Notifications for HCS_PROCESS handles
|
||||||
|
hcsNotificationProcessExited hcsNotification = 0x00010000
|
||||||
|
|
||||||
|
// Common notifications
|
||||||
|
hcsNotificationInvalid hcsNotification = 0x00000000
|
||||||
|
hcsNotificationServiceDisconnect hcsNotification = 0x01000000
|
||||||
|
)
|
||||||
|
|
||||||
|
type hcsNotification uint32
|
||||||
|
type notificationChannel chan error
|
||||||
|
|
||||||
|
type notifcationWatcherContext struct {
|
||||||
|
channels notificationChannels
|
||||||
|
handle hcsCallback
|
||||||
|
}
|
||||||
|
|
||||||
|
type notificationChannels map[hcsNotification]notificationChannel
|
||||||
|
|
||||||
|
func newChannels() notificationChannels {
|
||||||
|
channels := make(notificationChannels)
|
||||||
|
|
||||||
|
channels[hcsNotificationSystemExited] = make(notificationChannel, 1)
|
||||||
|
channels[hcsNotificationSystemCreateCompleted] = make(notificationChannel, 1)
|
||||||
|
channels[hcsNotificationSystemStartCompleted] = make(notificationChannel, 1)
|
||||||
|
channels[hcsNotificationSystemPauseCompleted] = make(notificationChannel, 1)
|
||||||
|
channels[hcsNotificationSystemResumeCompleted] = make(notificationChannel, 1)
|
||||||
|
channels[hcsNotificationProcessExited] = make(notificationChannel, 1)
|
||||||
|
channels[hcsNotificationServiceDisconnect] = make(notificationChannel, 1)
|
||||||
|
return channels
|
||||||
|
}
|
||||||
|
func closeChannels(channels notificationChannels) {
|
||||||
|
close(channels[hcsNotificationSystemExited])
|
||||||
|
close(channels[hcsNotificationSystemCreateCompleted])
|
||||||
|
close(channels[hcsNotificationSystemStartCompleted])
|
||||||
|
close(channels[hcsNotificationSystemPauseCompleted])
|
||||||
|
close(channels[hcsNotificationSystemResumeCompleted])
|
||||||
|
close(channels[hcsNotificationProcessExited])
|
||||||
|
close(channels[hcsNotificationServiceDisconnect])
|
||||||
|
}
|
||||||
|
|
||||||
|
func notificationWatcher(notificationType hcsNotification, callbackNumber uintptr, notificationStatus uintptr, notificationData *uint16) uintptr {
|
||||||
|
var result error
|
||||||
|
if int32(notificationStatus) < 0 {
|
||||||
|
result = interop.Win32FromHresult(notificationStatus)
|
||||||
|
}
|
||||||
|
|
||||||
|
callbackMapLock.RLock()
|
||||||
|
context := callbackMap[callbackNumber]
|
||||||
|
callbackMapLock.RUnlock()
|
||||||
|
|
||||||
|
if context == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if channel, ok := context.channels[notificationType]; ok {
|
||||||
|
channel <- result
|
||||||
|
} else {
|
||||||
|
logrus.WithFields(logrus.Fields{
|
||||||
|
"notification-type": notificationType,
|
||||||
|
}).Warn("Received a callback of an unsupported type")
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
7
vendor/github.com/Microsoft/hcsshim/internal/hcs/cgo.go
generated
vendored
Normal file
7
vendor/github.com/Microsoft/hcsshim/internal/hcs/cgo.go
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package hcs
|
||||||
|
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
// This import is needed to make the library compile as CGO because HCSSHIM
|
||||||
|
// only works with CGO due to callbacks from HCS comming back from a C thread
|
||||||
|
// which is not supported without CGO. See https://github.com/golang/go/issues/10973
|
284
vendor/github.com/Microsoft/hcsshim/internal/hcs/errors.go
generated
vendored
Normal file
284
vendor/github.com/Microsoft/hcsshim/internal/hcs/errors.go
generated
vendored
Normal file
@ -0,0 +1,284 @@
|
|||||||
|
package hcs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/Microsoft/hcsshim/internal/interop"
|
||||||
|
"github.com/Microsoft/hcsshim/internal/logfields"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// ErrComputeSystemDoesNotExist is an error encountered when the container being operated on no longer exists
|
||||||
|
ErrComputeSystemDoesNotExist = syscall.Errno(0xc037010e)
|
||||||
|
|
||||||
|
// ErrElementNotFound is an error encountered when the object being referenced does not exist
|
||||||
|
ErrElementNotFound = syscall.Errno(0x490)
|
||||||
|
|
||||||
|
// ErrElementNotFound is an error encountered when the object being referenced does not exist
|
||||||
|
ErrNotSupported = syscall.Errno(0x32)
|
||||||
|
|
||||||
|
// ErrInvalidData is an error encountered when the request being sent to hcs is invalid/unsupported
|
||||||
|
// decimal -2147024883 / hex 0x8007000d
|
||||||
|
ErrInvalidData = syscall.Errno(0xd)
|
||||||
|
|
||||||
|
// ErrHandleClose is an error encountered when the handle generating the notification being waited on has been closed
|
||||||
|
ErrHandleClose = errors.New("hcsshim: the handle generating this notification has been closed")
|
||||||
|
|
||||||
|
// ErrAlreadyClosed is an error encountered when using a handle that has been closed by the Close method
|
||||||
|
ErrAlreadyClosed = errors.New("hcsshim: the handle has already been closed")
|
||||||
|
|
||||||
|
// ErrInvalidNotificationType is an error encountered when an invalid notification type is used
|
||||||
|
ErrInvalidNotificationType = errors.New("hcsshim: invalid notification type")
|
||||||
|
|
||||||
|
// ErrInvalidProcessState is an error encountered when the process is not in a valid state for the requested operation
|
||||||
|
ErrInvalidProcessState = errors.New("the process is in an invalid state for the attempted operation")
|
||||||
|
|
||||||
|
// ErrTimeout is an error encountered when waiting on a notification times out
|
||||||
|
ErrTimeout = errors.New("hcsshim: timeout waiting for notification")
|
||||||
|
|
||||||
|
// ErrUnexpectedContainerExit is the error encountered when a container exits while waiting for
|
||||||
|
// a different expected notification
|
||||||
|
ErrUnexpectedContainerExit = errors.New("unexpected container exit")
|
||||||
|
|
||||||
|
// ErrUnexpectedProcessAbort is the error encountered when communication with the compute service
|
||||||
|
// is lost while waiting for a notification
|
||||||
|
ErrUnexpectedProcessAbort = errors.New("lost communication with compute service")
|
||||||
|
|
||||||
|
// ErrUnexpectedValue is an error encountered when hcs returns an invalid value
|
||||||
|
ErrUnexpectedValue = errors.New("unexpected value returned from hcs")
|
||||||
|
|
||||||
|
// ErrVmcomputeAlreadyStopped is an error encountered when a shutdown or terminate request is made on a stopped container
|
||||||
|
ErrVmcomputeAlreadyStopped = syscall.Errno(0xc0370110)
|
||||||
|
|
||||||
|
// ErrVmcomputeOperationPending is an error encountered when the operation is being completed asynchronously
|
||||||
|
ErrVmcomputeOperationPending = syscall.Errno(0xC0370103)
|
||||||
|
|
||||||
|
// ErrVmcomputeOperationInvalidState is an error encountered when the compute system is not in a valid state for the requested operation
|
||||||
|
ErrVmcomputeOperationInvalidState = syscall.Errno(0xc0370105)
|
||||||
|
|
||||||
|
// ErrProcNotFound is an error encountered when the the process cannot be found
|
||||||
|
ErrProcNotFound = syscall.Errno(0x7f)
|
||||||
|
|
||||||
|
// ErrVmcomputeOperationAccessIsDenied is an error which can be encountered when enumerating compute systems in RS1/RS2
|
||||||
|
// builds when the underlying silo might be in the process of terminating. HCS was fixed in RS3.
|
||||||
|
ErrVmcomputeOperationAccessIsDenied = syscall.Errno(0x5)
|
||||||
|
|
||||||
|
// ErrVmcomputeInvalidJSON is an error encountered when the compute system does not support/understand the messages sent by management
|
||||||
|
ErrVmcomputeInvalidJSON = syscall.Errno(0xc037010d)
|
||||||
|
|
||||||
|
// ErrVmcomputeUnknownMessage is an error encountered guest compute system doesn't support the message
|
||||||
|
ErrVmcomputeUnknownMessage = syscall.Errno(0xc037010b)
|
||||||
|
|
||||||
|
// ErrNotSupported is an error encountered when hcs doesn't support the request
|
||||||
|
ErrPlatformNotSupported = errors.New("unsupported platform request")
|
||||||
|
)
|
||||||
|
|
||||||
|
type ErrorEvent struct {
|
||||||
|
Message string `json:"Message,omitempty"` // Fully formated error message
|
||||||
|
StackTrace string `json:"StackTrace,omitempty"` // Stack trace in string form
|
||||||
|
Provider string `json:"Provider,omitempty"`
|
||||||
|
EventID uint16 `json:"EventId,omitempty"`
|
||||||
|
Flags uint32 `json:"Flags,omitempty"`
|
||||||
|
Source string `json:"Source,omitempty"`
|
||||||
|
//Data []EventData `json:"Data,omitempty"` // Omit this as HCS doesn't encode this well. It's more confusing to include. It is however logged in debug mode (see processHcsResult function)
|
||||||
|
}
|
||||||
|
|
||||||
|
type hcsResult struct {
|
||||||
|
Error int32
|
||||||
|
ErrorMessage string
|
||||||
|
ErrorEvents []ErrorEvent `json:"ErrorEvents,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ev *ErrorEvent) String() string {
|
||||||
|
evs := "[Event Detail: " + ev.Message
|
||||||
|
if ev.StackTrace != "" {
|
||||||
|
evs += " Stack Trace: " + ev.StackTrace
|
||||||
|
}
|
||||||
|
if ev.Provider != "" {
|
||||||
|
evs += " Provider: " + ev.Provider
|
||||||
|
}
|
||||||
|
if ev.EventID != 0 {
|
||||||
|
evs = fmt.Sprintf("%s EventID: %d", evs, ev.EventID)
|
||||||
|
}
|
||||||
|
if ev.Flags != 0 {
|
||||||
|
evs = fmt.Sprintf("%s flags: %d", evs, ev.Flags)
|
||||||
|
}
|
||||||
|
if ev.Source != "" {
|
||||||
|
evs += " Source: " + ev.Source
|
||||||
|
}
|
||||||
|
evs += "]"
|
||||||
|
return evs
|
||||||
|
}
|
||||||
|
|
||||||
|
func processHcsResult(resultp *uint16) []ErrorEvent {
|
||||||
|
if resultp != nil {
|
||||||
|
resultj := interop.ConvertAndFreeCoTaskMemString(resultp)
|
||||||
|
logrus.WithField(logfields.JSON, resultj).
|
||||||
|
Debug("HCS Result")
|
||||||
|
result := &hcsResult{}
|
||||||
|
if err := json.Unmarshal([]byte(resultj), result); err != nil {
|
||||||
|
logrus.WithFields(logrus.Fields{
|
||||||
|
logfields.JSON: resultj,
|
||||||
|
logrus.ErrorKey: err,
|
||||||
|
}).Warning("Could not unmarshal HCS result")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return result.ErrorEvents
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type HcsError struct {
|
||||||
|
Op string
|
||||||
|
Err error
|
||||||
|
Events []ErrorEvent
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *HcsError) Error() string {
|
||||||
|
s := e.Op + ": " + e.Err.Error()
|
||||||
|
for _, ev := range e.Events {
|
||||||
|
s += "\n" + ev.String()
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProcessError is an error encountered in HCS during an operation on a Process object
|
||||||
|
type ProcessError struct {
|
||||||
|
SystemID string
|
||||||
|
Pid int
|
||||||
|
Op string
|
||||||
|
Err error
|
||||||
|
Events []ErrorEvent
|
||||||
|
}
|
||||||
|
|
||||||
|
// SystemError is an error encountered in HCS during an operation on a Container object
|
||||||
|
type SystemError struct {
|
||||||
|
ID string
|
||||||
|
Op string
|
||||||
|
Err error
|
||||||
|
Extra string
|
||||||
|
Events []ErrorEvent
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *SystemError) Error() string {
|
||||||
|
s := e.Op + " " + e.ID + ": " + e.Err.Error()
|
||||||
|
for _, ev := range e.Events {
|
||||||
|
s += "\n" + ev.String()
|
||||||
|
}
|
||||||
|
if e.Extra != "" {
|
||||||
|
s += "\n(extra info: " + e.Extra + ")"
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeSystemError(system *System, op string, extra string, err error, events []ErrorEvent) error {
|
||||||
|
// Don't double wrap errors
|
||||||
|
if _, ok := err.(*SystemError); ok {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return &SystemError{
|
||||||
|
ID: system.ID(),
|
||||||
|
Op: op,
|
||||||
|
Extra: extra,
|
||||||
|
Err: err,
|
||||||
|
Events: events,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *ProcessError) Error() string {
|
||||||
|
s := fmt.Sprintf("%s %s:%d: %s", e.Op, e.SystemID, e.Pid, e.Err.Error())
|
||||||
|
for _, ev := range e.Events {
|
||||||
|
s += "\n" + ev.String()
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeProcessError(process *Process, op string, err error, events []ErrorEvent) error {
|
||||||
|
// Don't double wrap errors
|
||||||
|
if _, ok := err.(*ProcessError); ok {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return &ProcessError{
|
||||||
|
Pid: process.Pid(),
|
||||||
|
SystemID: process.SystemID(),
|
||||||
|
Op: op,
|
||||||
|
Err: err,
|
||||||
|
Events: events,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsNotExist checks if an error is caused by the Container or Process not existing.
|
||||||
|
// Note: Currently, ErrElementNotFound can mean that a Process has either
|
||||||
|
// already exited, or does not exist. Both IsAlreadyStopped and IsNotExist
|
||||||
|
// will currently return true when the error is ErrElementNotFound or ErrProcNotFound.
|
||||||
|
func IsNotExist(err error) bool {
|
||||||
|
err = getInnerError(err)
|
||||||
|
return err == ErrComputeSystemDoesNotExist ||
|
||||||
|
err == ErrElementNotFound ||
|
||||||
|
err == ErrProcNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsAlreadyClosed checks if an error is caused by the Container or Process having been
|
||||||
|
// already closed by a call to the Close() method.
|
||||||
|
func IsAlreadyClosed(err error) bool {
|
||||||
|
err = getInnerError(err)
|
||||||
|
return err == ErrAlreadyClosed
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsPending returns a boolean indicating whether the error is that
|
||||||
|
// the requested operation is being completed in the background.
|
||||||
|
func IsPending(err error) bool {
|
||||||
|
err = getInnerError(err)
|
||||||
|
return err == ErrVmcomputeOperationPending
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsTimeout returns a boolean indicating whether the error is caused by
|
||||||
|
// a timeout waiting for the operation to complete.
|
||||||
|
func IsTimeout(err error) bool {
|
||||||
|
err = getInnerError(err)
|
||||||
|
return err == ErrTimeout
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsAlreadyStopped returns a boolean indicating whether the error is caused by
|
||||||
|
// a Container or Process being already stopped.
|
||||||
|
// Note: Currently, ErrElementNotFound can mean that a Process has either
|
||||||
|
// already exited, or does not exist. Both IsAlreadyStopped and IsNotExist
|
||||||
|
// will currently return true when the error is ErrElementNotFound or ErrProcNotFound.
|
||||||
|
func IsAlreadyStopped(err error) bool {
|
||||||
|
err = getInnerError(err)
|
||||||
|
return err == ErrVmcomputeAlreadyStopped ||
|
||||||
|
err == ErrElementNotFound ||
|
||||||
|
err == ErrProcNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsNotSupported returns a boolean indicating whether the error is caused by
|
||||||
|
// unsupported platform requests
|
||||||
|
// Note: Currently Unsupported platform requests can be mean either
|
||||||
|
// ErrVmcomputeInvalidJSON, ErrInvalidData, ErrNotSupported or ErrVmcomputeUnknownMessage
|
||||||
|
// is thrown from the Platform
|
||||||
|
func IsNotSupported(err error) bool {
|
||||||
|
err = getInnerError(err)
|
||||||
|
// If Platform doesn't recognize or support the request sent, below errors are seen
|
||||||
|
return err == ErrVmcomputeInvalidJSON ||
|
||||||
|
err == ErrInvalidData ||
|
||||||
|
err == ErrNotSupported ||
|
||||||
|
err == ErrVmcomputeUnknownMessage
|
||||||
|
}
|
||||||
|
|
||||||
|
func getInnerError(err error) error {
|
||||||
|
switch pe := err.(type) {
|
||||||
|
case nil:
|
||||||
|
return nil
|
||||||
|
case *HcsError:
|
||||||
|
err = pe.Err
|
||||||
|
case *SystemError:
|
||||||
|
err = pe.Err
|
||||||
|
case *ProcessError:
|
||||||
|
err = pe.Err
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
48
vendor/github.com/Microsoft/hcsshim/internal/hcs/hcs.go
generated
vendored
Normal file
48
vendor/github.com/Microsoft/hcsshim/internal/hcs/hcs.go
generated
vendored
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
// Shim for the Host Compute Service (HCS) to manage Windows Server
|
||||||
|
// containers and Hyper-V containers.
|
||||||
|
|
||||||
|
package hcs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:generate go run ../../mksyscall_windows.go -output zsyscall_windows.go hcs.go
|
||||||
|
|
||||||
|
//sys hcsEnumerateComputeSystems(query string, computeSystems **uint16, result **uint16) (hr error) = vmcompute.HcsEnumerateComputeSystems?
|
||||||
|
//sys hcsCreateComputeSystem(id string, configuration string, identity syscall.Handle, computeSystem *hcsSystem, result **uint16) (hr error) = vmcompute.HcsCreateComputeSystem?
|
||||||
|
//sys hcsOpenComputeSystem(id string, computeSystem *hcsSystem, result **uint16) (hr error) = vmcompute.HcsOpenComputeSystem?
|
||||||
|
//sys hcsCloseComputeSystem(computeSystem hcsSystem) (hr error) = vmcompute.HcsCloseComputeSystem?
|
||||||
|
//sys hcsStartComputeSystem(computeSystem hcsSystem, options string, result **uint16) (hr error) = vmcompute.HcsStartComputeSystem?
|
||||||
|
//sys hcsShutdownComputeSystem(computeSystem hcsSystem, options string, result **uint16) (hr error) = vmcompute.HcsShutdownComputeSystem?
|
||||||
|
//sys hcsTerminateComputeSystem(computeSystem hcsSystem, options string, result **uint16) (hr error) = vmcompute.HcsTerminateComputeSystem?
|
||||||
|
//sys hcsPauseComputeSystem(computeSystem hcsSystem, options string, result **uint16) (hr error) = vmcompute.HcsPauseComputeSystem?
|
||||||
|
//sys hcsResumeComputeSystem(computeSystem hcsSystem, options string, result **uint16) (hr error) = vmcompute.HcsResumeComputeSystem?
|
||||||
|
//sys hcsGetComputeSystemProperties(computeSystem hcsSystem, propertyQuery string, properties **uint16, result **uint16) (hr error) = vmcompute.HcsGetComputeSystemProperties?
|
||||||
|
//sys hcsModifyComputeSystem(computeSystem hcsSystem, configuration string, result **uint16) (hr error) = vmcompute.HcsModifyComputeSystem?
|
||||||
|
//sys hcsRegisterComputeSystemCallback(computeSystem hcsSystem, callback uintptr, context uintptr, callbackHandle *hcsCallback) (hr error) = vmcompute.HcsRegisterComputeSystemCallback?
|
||||||
|
//sys hcsUnregisterComputeSystemCallback(callbackHandle hcsCallback) (hr error) = vmcompute.HcsUnregisterComputeSystemCallback?
|
||||||
|
|
||||||
|
//sys hcsCreateProcess(computeSystem hcsSystem, processParameters string, processInformation *hcsProcessInformation, process *hcsProcess, result **uint16) (hr error) = vmcompute.HcsCreateProcess?
|
||||||
|
//sys hcsOpenProcess(computeSystem hcsSystem, pid uint32, process *hcsProcess, result **uint16) (hr error) = vmcompute.HcsOpenProcess?
|
||||||
|
//sys hcsCloseProcess(process hcsProcess) (hr error) = vmcompute.HcsCloseProcess?
|
||||||
|
//sys hcsTerminateProcess(process hcsProcess, result **uint16) (hr error) = vmcompute.HcsTerminateProcess?
|
||||||
|
//sys hcsSignalProcess(process hcsProcess, options string, result **uint16) (hr error) = vmcompute.HcsTerminateProcess?
|
||||||
|
//sys hcsGetProcessInfo(process hcsProcess, processInformation *hcsProcessInformation, result **uint16) (hr error) = vmcompute.HcsGetProcessInfo?
|
||||||
|
//sys hcsGetProcessProperties(process hcsProcess, processProperties **uint16, result **uint16) (hr error) = vmcompute.HcsGetProcessProperties?
|
||||||
|
//sys hcsModifyProcess(process hcsProcess, settings string, result **uint16) (hr error) = vmcompute.HcsModifyProcess?
|
||||||
|
//sys hcsGetServiceProperties(propertyQuery string, properties **uint16, result **uint16) (hr error) = vmcompute.HcsGetServiceProperties?
|
||||||
|
//sys hcsRegisterProcessCallback(process hcsProcess, callback uintptr, context uintptr, callbackHandle *hcsCallback) (hr error) = vmcompute.HcsRegisterProcessCallback?
|
||||||
|
//sys hcsUnregisterProcessCallback(callbackHandle hcsCallback) (hr error) = vmcompute.HcsUnregisterProcessCallback?
|
||||||
|
|
||||||
|
type hcsSystem syscall.Handle
|
||||||
|
type hcsProcess syscall.Handle
|
||||||
|
type hcsCallback syscall.Handle
|
||||||
|
|
||||||
|
type hcsProcessInformation struct {
|
||||||
|
ProcessId uint32
|
||||||
|
Reserved uint32
|
||||||
|
StdInput syscall.Handle
|
||||||
|
StdOutput syscall.Handle
|
||||||
|
StdError syscall.Handle
|
||||||
|
}
|
15
vendor/github.com/Microsoft/hcsshim/internal/hcs/log.go
generated
vendored
Normal file
15
vendor/github.com/Microsoft/hcsshim/internal/hcs/log.go
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package hcs
|
||||||
|
|
||||||
|
import "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
func logOperationBegin(ctx logrus.Fields, msg string) {
|
||||||
|
logrus.WithFields(ctx).Debug(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func logOperationEnd(ctx logrus.Fields, msg string, err error) {
|
||||||
|
if err == nil {
|
||||||
|
logrus.WithFields(ctx).Debug(msg)
|
||||||
|
} else {
|
||||||
|
logrus.WithFields(ctx).WithError(err).Error(msg)
|
||||||
|
}
|
||||||
|
}
|
465
vendor/github.com/Microsoft/hcsshim/internal/hcs/process.go
generated
vendored
Normal file
465
vendor/github.com/Microsoft/hcsshim/internal/hcs/process.go
generated
vendored
Normal file
@ -0,0 +1,465 @@
|
|||||||
|
package hcs
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
"sync"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/Microsoft/hcsshim/internal/guestrequest"
|
||||||
|
"github.com/Microsoft/hcsshim/internal/interop"
|
||||||
|
"github.com/Microsoft/hcsshim/internal/logfields"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ContainerError is an error encountered in HCS
|
||||||
|
type Process struct {
|
||||||
|
handleLock sync.RWMutex
|
||||||
|
handle hcsProcess
|
||||||
|
processID int
|
||||||
|
system *System
|
||||||
|
cachedPipes *cachedPipes
|
||||||
|
callbackNumber uintptr
|
||||||
|
|
||||||
|
logctx logrus.Fields
|
||||||
|
}
|
||||||
|
|
||||||
|
func newProcess(process hcsProcess, processID int, computeSystem *System) *Process {
|
||||||
|
return &Process{
|
||||||
|
handle: process,
|
||||||
|
processID: processID,
|
||||||
|
system: computeSystem,
|
||||||
|
logctx: logrus.Fields{
|
||||||
|
logfields.HCSOperation: "",
|
||||||
|
logfields.ContainerID: computeSystem.ID(),
|
||||||
|
logfields.ProcessID: processID,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type cachedPipes struct {
|
||||||
|
stdIn syscall.Handle
|
||||||
|
stdOut syscall.Handle
|
||||||
|
stdErr syscall.Handle
|
||||||
|
}
|
||||||
|
|
||||||
|
type processModifyRequest struct {
|
||||||
|
Operation string
|
||||||
|
ConsoleSize *consoleSize `json:",omitempty"`
|
||||||
|
CloseHandle *closeHandle `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type consoleSize struct {
|
||||||
|
Height uint16
|
||||||
|
Width uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
type closeHandle struct {
|
||||||
|
Handle string
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProcessStatus struct {
|
||||||
|
ProcessID uint32
|
||||||
|
Exited bool
|
||||||
|
ExitCode uint32
|
||||||
|
LastWaitResult int32
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
stdIn string = "StdIn"
|
||||||
|
stdOut string = "StdOut"
|
||||||
|
stdErr string = "StdErr"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
modifyConsoleSize string = "ConsoleSize"
|
||||||
|
modifyCloseHandle string = "CloseHandle"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Pid returns the process ID of the process within the container.
|
||||||
|
func (process *Process) Pid() int {
|
||||||
|
return process.processID
|
||||||
|
}
|
||||||
|
|
||||||
|
// SystemID returns the ID of the process's compute system.
|
||||||
|
func (process *Process) SystemID() string {
|
||||||
|
return process.system.ID()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (process *Process) logOperationBegin(operation string) {
|
||||||
|
process.logctx[logfields.HCSOperation] = operation
|
||||||
|
logOperationBegin(
|
||||||
|
process.logctx,
|
||||||
|
"hcsshim::Process - Begin Operation")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (process *Process) logOperationEnd(err error) {
|
||||||
|
var result string
|
||||||
|
if err == nil {
|
||||||
|
result = "Success"
|
||||||
|
} else {
|
||||||
|
result = "Error"
|
||||||
|
}
|
||||||
|
|
||||||
|
logOperationEnd(
|
||||||
|
process.logctx,
|
||||||
|
"hcsshim::Process - End Operation - "+result,
|
||||||
|
err)
|
||||||
|
process.logctx[logfields.HCSOperation] = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// Signal signals the process with `options`.
|
||||||
|
func (process *Process) Signal(options guestrequest.SignalProcessOptions) (err error) {
|
||||||
|
process.handleLock.RLock()
|
||||||
|
defer process.handleLock.RUnlock()
|
||||||
|
|
||||||
|
operation := "hcsshim::Process::Signal"
|
||||||
|
process.logOperationBegin(operation)
|
||||||
|
defer process.logOperationEnd(err)
|
||||||
|
|
||||||
|
if process.handle == 0 {
|
||||||
|
return makeProcessError(process, operation, ErrAlreadyClosed, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
optionsb, err := json.Marshal(options)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
optionsStr := string(optionsb)
|
||||||
|
|
||||||
|
var resultp *uint16
|
||||||
|
completed := false
|
||||||
|
go syscallWatcher(process.logctx, &completed)
|
||||||
|
err = hcsSignalProcess(process.handle, optionsStr, &resultp)
|
||||||
|
completed = true
|
||||||
|
events := processHcsResult(resultp)
|
||||||
|
if err != nil {
|
||||||
|
return makeProcessError(process, operation, err, events)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Kill signals the process to terminate but does not wait for it to finish terminating.
|
||||||
|
func (process *Process) Kill() (err error) {
|
||||||
|
process.handleLock.RLock()
|
||||||
|
defer process.handleLock.RUnlock()
|
||||||
|
|
||||||
|
operation := "hcsshim::Process::Kill"
|
||||||
|
process.logOperationBegin(operation)
|
||||||
|
defer process.logOperationEnd(err)
|
||||||
|
|
||||||
|
if process.handle == 0 {
|
||||||
|
return makeProcessError(process, operation, ErrAlreadyClosed, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
var resultp *uint16
|
||||||
|
completed := false
|
||||||
|
go syscallWatcher(process.logctx, &completed)
|
||||||
|
err = hcsTerminateProcess(process.handle, &resultp)
|
||||||
|
completed = true
|
||||||
|
events := processHcsResult(resultp)
|
||||||
|
if err != nil {
|
||||||
|
return makeProcessError(process, operation, err, events)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait waits for the process to exit.
|
||||||
|
func (process *Process) Wait() (err error) {
|
||||||
|
operation := "hcsshim::Process::Wait"
|
||||||
|
process.logOperationBegin(operation)
|
||||||
|
defer process.logOperationEnd(err)
|
||||||
|
|
||||||
|
err = waitForNotification(process.callbackNumber, hcsNotificationProcessExited, nil)
|
||||||
|
if err != nil {
|
||||||
|
return makeProcessError(process, operation, err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// WaitTimeout waits for the process to exit or the duration to elapse. It returns
|
||||||
|
// false if timeout occurs.
|
||||||
|
func (process *Process) WaitTimeout(timeout time.Duration) (err error) {
|
||||||
|
operation := "hcssshim::Process::WaitTimeout"
|
||||||
|
process.logOperationBegin(operation)
|
||||||
|
defer process.logOperationEnd(err)
|
||||||
|
|
||||||
|
err = waitForNotification(process.callbackNumber, hcsNotificationProcessExited, &timeout)
|
||||||
|
if err != nil {
|
||||||
|
return makeProcessError(process, operation, err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResizeConsole resizes the console of the process.
|
||||||
|
func (process *Process) ResizeConsole(width, height uint16) (err error) {
|
||||||
|
process.handleLock.RLock()
|
||||||
|
defer process.handleLock.RUnlock()
|
||||||
|
|
||||||
|
operation := "hcsshim::Process::ResizeConsole"
|
||||||
|
process.logOperationBegin(operation)
|
||||||
|
defer process.logOperationEnd(err)
|
||||||
|
|
||||||
|
if process.handle == 0 {
|
||||||
|
return makeProcessError(process, operation, ErrAlreadyClosed, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
modifyRequest := processModifyRequest{
|
||||||
|
Operation: modifyConsoleSize,
|
||||||
|
ConsoleSize: &consoleSize{
|
||||||
|
Height: height,
|
||||||
|
Width: width,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
modifyRequestb, err := json.Marshal(modifyRequest)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
modifyRequestStr := string(modifyRequestb)
|
||||||
|
|
||||||
|
var resultp *uint16
|
||||||
|
err = hcsModifyProcess(process.handle, modifyRequestStr, &resultp)
|
||||||
|
events := processHcsResult(resultp)
|
||||||
|
if err != nil {
|
||||||
|
return makeProcessError(process, operation, err, events)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (process *Process) Properties() (_ *ProcessStatus, err error) {
|
||||||
|
process.handleLock.RLock()
|
||||||
|
defer process.handleLock.RUnlock()
|
||||||
|
|
||||||
|
operation := "hcsshim::Process::Properties"
|
||||||
|
process.logOperationBegin(operation)
|
||||||
|
defer process.logOperationEnd(err)
|
||||||
|
|
||||||
|
if process.handle == 0 {
|
||||||
|
return nil, makeProcessError(process, operation, ErrAlreadyClosed, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
resultp *uint16
|
||||||
|
propertiesp *uint16
|
||||||
|
)
|
||||||
|
completed := false
|
||||||
|
go syscallWatcher(process.logctx, &completed)
|
||||||
|
err = hcsGetProcessProperties(process.handle, &propertiesp, &resultp)
|
||||||
|
completed = true
|
||||||
|
events := processHcsResult(resultp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, makeProcessError(process, operation, err, events)
|
||||||
|
}
|
||||||
|
|
||||||
|
if propertiesp == nil {
|
||||||
|
return nil, ErrUnexpectedValue
|
||||||
|
}
|
||||||
|
propertiesRaw := interop.ConvertAndFreeCoTaskMemBytes(propertiesp)
|
||||||
|
|
||||||
|
properties := &ProcessStatus{}
|
||||||
|
if err := json.Unmarshal(propertiesRaw, properties); err != nil {
|
||||||
|
return nil, makeProcessError(process, operation, err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
return properties, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExitCode returns the exit code of the process. The process must have
|
||||||
|
// already terminated.
|
||||||
|
func (process *Process) ExitCode() (_ int, err error) {
|
||||||
|
operation := "hcsshim::Process::ExitCode"
|
||||||
|
process.logOperationBegin(operation)
|
||||||
|
defer process.logOperationEnd(err)
|
||||||
|
|
||||||
|
properties, err := process.Properties()
|
||||||
|
if err != nil {
|
||||||
|
return 0, makeProcessError(process, operation, err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
if properties.Exited == false {
|
||||||
|
return 0, makeProcessError(process, operation, ErrInvalidProcessState, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
if properties.LastWaitResult != 0 {
|
||||||
|
return 0, makeProcessError(process, operation, syscall.Errno(properties.LastWaitResult), nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
return int(properties.ExitCode), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stdio returns the stdin, stdout, and stderr pipes, respectively. Closing
|
||||||
|
// these pipes does not close the underlying pipes; it should be possible to
|
||||||
|
// call this multiple times to get multiple interfaces.
|
||||||
|
func (process *Process) Stdio() (_ io.WriteCloser, _ io.ReadCloser, _ io.ReadCloser, err error) {
|
||||||
|
process.handleLock.RLock()
|
||||||
|
defer process.handleLock.RUnlock()
|
||||||
|
|
||||||
|
operation := "hcsshim::Process::Stdio"
|
||||||
|
process.logOperationBegin(operation)
|
||||||
|
defer process.logOperationEnd(err)
|
||||||
|
|
||||||
|
if process.handle == 0 {
|
||||||
|
return nil, nil, nil, makeProcessError(process, operation, ErrAlreadyClosed, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
var stdIn, stdOut, stdErr syscall.Handle
|
||||||
|
|
||||||
|
if process.cachedPipes == nil {
|
||||||
|
var (
|
||||||
|
processInfo hcsProcessInformation
|
||||||
|
resultp *uint16
|
||||||
|
)
|
||||||
|
err = hcsGetProcessInfo(process.handle, &processInfo, &resultp)
|
||||||
|
events := processHcsResult(resultp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, nil, makeProcessError(process, operation, err, events)
|
||||||
|
}
|
||||||
|
|
||||||
|
stdIn, stdOut, stdErr = processInfo.StdInput, processInfo.StdOutput, processInfo.StdError
|
||||||
|
} else {
|
||||||
|
// Use cached pipes
|
||||||
|
stdIn, stdOut, stdErr = process.cachedPipes.stdIn, process.cachedPipes.stdOut, process.cachedPipes.stdErr
|
||||||
|
|
||||||
|
// Invalidate the cache
|
||||||
|
process.cachedPipes = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
pipes, err := makeOpenFiles([]syscall.Handle{stdIn, stdOut, stdErr})
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, nil, makeProcessError(process, operation, err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
return pipes[0], pipes[1], pipes[2], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CloseStdin closes the write side of the stdin pipe so that the process is
|
||||||
|
// notified on the read side that there is no more data in stdin.
|
||||||
|
func (process *Process) CloseStdin() (err error) {
|
||||||
|
process.handleLock.RLock()
|
||||||
|
defer process.handleLock.RUnlock()
|
||||||
|
|
||||||
|
operation := "hcsshim::Process::CloseStdin"
|
||||||
|
process.logOperationBegin(operation)
|
||||||
|
defer process.logOperationEnd(err)
|
||||||
|
|
||||||
|
if process.handle == 0 {
|
||||||
|
return makeProcessError(process, operation, ErrAlreadyClosed, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
modifyRequest := processModifyRequest{
|
||||||
|
Operation: modifyCloseHandle,
|
||||||
|
CloseHandle: &closeHandle{
|
||||||
|
Handle: stdIn,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
modifyRequestb, err := json.Marshal(modifyRequest)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
modifyRequestStr := string(modifyRequestb)
|
||||||
|
|
||||||
|
var resultp *uint16
|
||||||
|
err = hcsModifyProcess(process.handle, modifyRequestStr, &resultp)
|
||||||
|
events := processHcsResult(resultp)
|
||||||
|
if err != nil {
|
||||||
|
return makeProcessError(process, operation, err, events)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close cleans up any state associated with the process but does not kill
|
||||||
|
// or wait on it.
|
||||||
|
func (process *Process) Close() (err error) {
|
||||||
|
process.handleLock.Lock()
|
||||||
|
defer process.handleLock.Unlock()
|
||||||
|
|
||||||
|
operation := "hcsshim::Process::Close"
|
||||||
|
process.logOperationBegin(operation)
|
||||||
|
defer process.logOperationEnd(err)
|
||||||
|
|
||||||
|
// Don't double free this
|
||||||
|
if process.handle == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = process.unregisterCallback(); err != nil {
|
||||||
|
return makeProcessError(process, operation, err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = hcsCloseProcess(process.handle); err != nil {
|
||||||
|
return makeProcessError(process, operation, err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
process.handle = 0
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (process *Process) registerCallback() error {
|
||||||
|
context := ¬ifcationWatcherContext{
|
||||||
|
channels: newChannels(),
|
||||||
|
}
|
||||||
|
|
||||||
|
callbackMapLock.Lock()
|
||||||
|
callbackNumber := nextCallback
|
||||||
|
nextCallback++
|
||||||
|
callbackMap[callbackNumber] = context
|
||||||
|
callbackMapLock.Unlock()
|
||||||
|
|
||||||
|
var callbackHandle hcsCallback
|
||||||
|
err := hcsRegisterProcessCallback(process.handle, notificationWatcherCallback, callbackNumber, &callbackHandle)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
context.handle = callbackHandle
|
||||||
|
process.callbackNumber = callbackNumber
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (process *Process) unregisterCallback() error {
|
||||||
|
callbackNumber := process.callbackNumber
|
||||||
|
|
||||||
|
callbackMapLock.RLock()
|
||||||
|
context := callbackMap[callbackNumber]
|
||||||
|
callbackMapLock.RUnlock()
|
||||||
|
|
||||||
|
if context == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
handle := context.handle
|
||||||
|
|
||||||
|
if handle == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// hcsUnregisterProcessCallback has its own syncronization
|
||||||
|
// to wait for all callbacks to complete. We must NOT hold the callbackMapLock.
|
||||||
|
err := hcsUnregisterProcessCallback(handle)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
closeChannels(context.channels)
|
||||||
|
|
||||||
|
callbackMapLock.Lock()
|
||||||
|
callbackMap[callbackNumber] = nil
|
||||||
|
callbackMapLock.Unlock()
|
||||||
|
|
||||||
|
handle = 0
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user