diff --git a/Gopkg.lock b/Gopkg.lock
new file mode 100644
index 00000000..12bf8f7e
--- /dev/null
+++ b/Gopkg.lock
@@ -0,0 +1,2205 @@
+# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
+
+
+[[projects]]
+ branch = "master"
+ digest = "1:94e9caf404409a2990cfd22aca37d758494c098eff3e2c37fda1abed862e74dd"
+ name = "bazil.org/fuse"
+ packages = [
+ ".",
+ "fs",
+ "fuseutil",
+ ]
+ pruneopts = "UT"
+ revision = "65cc252bf6691cb3c7014bcb2c8dc29de91e3a7e"
+
+[[projects]]
+ branch = "master"
+ digest = "1:482fe066e308f0058abdfa302b9b5ff0fa4e89f6c55f103a2ac5e0af329f72cd"
+ name = "github.com/Stebalien/go-bitfield"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "076a62f9ce6ea421ab74a91f2d8dc7124f0cfd64"
+
+[[projects]]
+ digest = "1:1156cfea0ff969858f6027df95c15ca5e802556b466aebeedaf53dde3b301db3"
+ name = "github.com/allegro/bigcache"
+ packages = [
+ ".",
+ "queue"
+ ]
+ pruneopts = "UT"
+ revision = "f31987a23e44c5121ef8c8b2f2ea2e8ffa37b068"
+ version = "v1.1.0"
+
+[[projects]]
+ branch = "master"
+ digest = "1:7d191fd0c54ff370eaf6116a14dafe2a328df487baea280699f597aae858d00d"
+ name = "github.com/aristanetworks/goarista"
+ packages = ["monotime"]
+ pruneopts = "UT"
+ revision = "ff33da284e760fcdb03c33d37a719e5ed30ba844"
+
+[[projects]]
+ branch = "master"
+ digest = "1:02796fed67c64543bfe3343b26cdc9a221bca2d83e8c7dcf35b5b70f6b5b9c56"
+ name = "github.com/bren2010/proquint"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "38337c27106d8f06e9b5cddc6df973ceece1c8ea"
+
+[[projects]]
+ branch = "master"
+ digest = "1:2c00f064ba355903866cbfbf3f7f4c0fe64af6638cc7d1b8bdcf3181bc67f1d8"
+ name = "github.com/btcsuite/btcd"
+ packages = ["btcec"]
+ pruneopts = "UT"
+ revision = "cff30e1d23fc9e800b2b5b4b41ef1817dda07e9f"
+
+[[projects]]
+ digest = "1:166438587ed45ac211dab8a3ecebf4fa0c186d0db63430fb9127bbc2e5fcdc67"
+ name = "github.com/cenkalti/backoff"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "1e4cf3da559842a91afcb6ea6141451e6c30c618"
+ version = "v2.1.1"
+
+[[projects]]
+ digest = "1:f438d91be142877c3ad83157992c91de787ddfbddcc2a7da1ef6ef61606cadc4"
+ name = "github.com/cheekybits/genny"
+ packages = ["generic"]
+ pruneopts = "UT"
+ revision = "d2cf3cdd35ce0d789056c4bc02a4d6349c947caf"
+ version = "v1.0.0"
+
+[[projects]]
+ digest = "1:05ffeeed3f0f05520de0679f6aa3219ffee69cfd6d9fb6c194879d4c818ad670"
+ name = "github.com/coreos/go-semver"
+ packages = ["semver"]
+ pruneopts = "UT"
+ revision = "e214231b295a8ea9479f11b70b35d5acf3556d9b"
+ version = "v0.3.0"
+
+[[projects]]
+ digest = "1:5bdd0581421e643e6c3163bb5da785600a2d7d0d73fec58acebaf2e693868e9d"
+ name = "github.com/cskr/pubsub"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "65166f5ae403cbf6dcdced31e1f8f8ad95485cb3"
+ version = "v1.0.2"
+
+[[projects]]
+ digest = "1:60abec4c812fc39cf7e66571da9e1758c586c258af815c4062b20d136542ff19"
+ name = "github.com/dave/jennifer"
+ packages = ["jen"]
+ pruneopts = "UT"
+ revision = "14e399b6b5e8456c66c45c955fc27b568bacb5c9"
+ version = "v1.3.0"
+
+[[projects]]
+ digest = "1:ffe9824d294da03b391f44e1ae8281281b4afc1bdaa9588c9097785e3af10cec"
+ name = "github.com/davecgh/go-spew"
+ packages = ["spew"]
+ pruneopts = "UT"
+ revision = "8991bc29aa16c548c550c7ff78260e27b9ab7c73"
+ version = "v1.1.1"
+
+[[projects]]
+ branch = "master"
+ digest = "1:ff0db56095c10bcdbf92ce2503f1d0d6e2ee0615184cfb96db2907fcb08d454e"
+ name = "github.com/davidlazar/go-crypto"
+ packages = ["salsa20"]
+ pruneopts = "UT"
+ revision = "dcfb0a7ac018a248366f96bcd8a2f8c805d7b268"
+
+[[projects]]
+ digest = "1:e47d51dab652d26c3fba6f8cba403f922d02757a82abdc77e90df7948daf296e"
+ name = "github.com/deckarep/golang-set"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "cbaa98ba5575e67703b32b4b19f73c91f3c4159e"
+ version = "v1.7.1"
+
+[[projects]]
+ digest = "1:edb569dd02419a41ddd98768cc0e7aec922ef19dae139731e5ca750afcf6f4c5"
+ name = "github.com/edsrzf/mmap-go"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "188cc3b666ba704534fa4f96e9e61f21f1e1ba7c"
+ version = "v1.0.0"
+
+[[projects]]
+ branch = "rpc_statediffs_at_head"
+ digest = "1:762bae8d82b8871999f15cb0694f55f99a56f764d68e00c49ee6eae479da5df6"
+ name = "github.com/ethereum/go-ethereum"
+ packages = [
+ ".",
+ "accounts",
+ "accounts/abi",
+ "accounts/abi/bind",
+ "accounts/external",
+ "accounts/keystore",
+ "accounts/scwallet",
+ "accounts/usbwallet",
+ "accounts/usbwallet/trezor",
+ "common",
+ "common/bitutil",
+ "common/hexutil",
+ "common/math",
+ "common/mclock",
+ "common/prque",
+ "consensus",
+ "consensus/clique",
+ "consensus/ethash",
+ "consensus/misc",
+ "core",
+ "core/rawdb",
+ "core/state",
+ "core/types",
+ "core/vm",
+ "crypto",
+ "crypto/bn256",
+ "crypto/bn256/cloudflare",
+ "crypto/bn256/google",
+ "crypto/ecies",
+ "crypto/secp256k1",
+ "eth/downloader",
+ "ethclient",
+ "ethdb",
+ "ethdb/leveldb",
+ "ethdb/memorydb",
+ "event",
+ "internal/debug",
+ "internal/ethapi",
+ "log",
+ "metrics",
+ "metrics/exp",
+ "metrics/prometheus",
+ "node",
+ "p2p",
+ "p2p/discover",
+ "p2p/discv5",
+ "p2p/enode",
+ "p2p/enr",
+ "p2p/nat",
+ "p2p/netutil",
+ "params",
+ "rlp",
+ "rpc",
+ "signer/core",
+ "signer/storage",
+ "statediff",
+ "trie",
+ ]
+ pruneopts = "UT"
+ revision = "edf001e1d2296951e7e592c55e66ce074bd62807"
+ source = "github.com/vulcanize/go-ethereum"
+
+[[projects]]
+ branch = "master"
+ digest = "1:c183111eaf02a9e6bb39c213bdfb5472b16f1955dd4c9dab82db83f114c64a63"
+ name = "github.com/facebookgo/atomicfile"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "2de1f203e7d5e386a6833233882782932729f27e"
+
+[[projects]]
+ branch = "master"
+ digest = "1:6071114d7c08ebdd6bc697113cfb1634c8c29d506457ef90e7fb703841cb2828"
+ name = "github.com/fjl/memsize"
+ packages = [
+ ".",
+ "memsizeui",
+ ]
+ pruneopts = "UT"
+ revision = "2a09253e352a56f419bd88effab0483f52da4c7d"
+
+[[projects]]
+ digest = "1:abeb38ade3f32a92943e5be54f55ed6d6e3b6602761d74b4aab4c9dd45c18abd"
+ name = "github.com/fsnotify/fsnotify"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "c2828203cd70a50dcccfb2761f8b1f8ceef9a8e9"
+ version = "v1.4.7"
+
+[[projects]]
+
+ branch = "master"
+ digest = "1:c52ac440c00e8b404a713a2de487b7b5e0e93a89a758832d9fc15b2817d6d5d6"
+ name = "github.com/gballet/go-libpcsclite"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "312b5175032f98274685a4dd81935a92ad2412a5"
+
+[[projects]]
+ digest = "1:586ea76dbd0374d6fb649a91d70d652b7fe0ccffb8910a77468e7702e7901f3d"
+ name = "github.com/go-stack/stack"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "2fee6af1a9795aafbe0253a0cfbdf668e1fb8a9a"
+ version = "v1.8.0"
+
+[[projects]]
+ digest = "1:d0e00c8ccabdfe678667d6be78c9d08a6a4efc36d9fb596f098706728b00ba6b"
+ name = "github.com/gogo/protobuf"
+ packages = [
+ "gogoproto",
+ "io",
+ "proto",
+ "protoc-gen-gogo/descriptor",
+ ]
+ pruneopts = "UT"
+ revision = "ba06b47c162d49f2af050fb4c75bcbc86a159d5c"
+ version = "v1.2.1"
+
+[[projects]]
+ digest = "1:4ee2c939f1ee5983ec75069bc51604a64657b37bc03adeccee8b60abecfe76cc"
+ name = "github.com/golang/protobuf"
+ packages = ["proto"]
+ packages = [
+ "proto",
+ "protoc-gen-go/descriptor",
+ ]
+ pruneopts = "UT"
+ revision = "aa810b61a9c79d51363740d207bb46cf8e620ed5"
+ version = "v1.2.0"
+
+[[projects]]
+ branch = "master"
+ digest = "1:4a0c6bb4805508a6287675fac876be2ac1182539ca8a32468d8128882e9d5009"
+ name = "github.com/golang/snappy"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "2e65f85255dbc3072edf28d6b5b8efc472979f5a"
+
+[[projects]]
+ digest = "1:3a26588bc48b96825977c1b3df964f8fd842cd6860cc26370588d3563433cf11"
+ name = "github.com/google/uuid"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "d460ce9f8df2e77fb1ba55ca87fafed96c607494"
+ version = "v1.0.0"
+
+[[projects]]
+ digest = "1:7b5c6e2eeaa9ae5907c391a91c132abfd5c9e8a784a341b5625e750c67e6825d"
+ name = "github.com/gorilla/websocket"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "66b9c49e59c6c48f0ffce28c2d8b8a5678502c6d"
+ version = "v1.4.0"
+
+[[projects]]
+ digest = "1:43c609cba7aa615eaae5aa8f2ddba65dc1b2d3af7bc434f738238df8d3797ddb"
+ name = "github.com/gxed/hashland"
+ packages = [
+ "keccakpg",
+ "murmur3",
+ ]
+ pruneopts = "UT"
+ revision = "a72cc0875a1e95edd309d3134bc7c11bf2d7360b"
+ version = "v0.0.1"
+
+[[projects]]
+ digest = "1:0ade334594e69404d80d9d323445d2297ff8161637f9b2d347cc6973d2d6f05b"
+ name = "github.com/hashicorp/errwrap"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "8a6fb523712970c966eefc6b39ed2c5e74880354"
+ version = "v1.0.0"
+
+[[projects]]
+ digest = "1:f668349b83f7d779567c880550534addeca7ebadfdcf44b0b9c39be61864b4b7"
+ name = "github.com/hashicorp/go-multierror"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "886a7fbe3eb1c874d46f623bfa70af45f425b3d1"
+ version = "v1.0.0"
+
+[[projects]]
+ branch = "master"
+ digest = "1:cf296baa185baae04a9a7004efee8511d08e2f5f51d4cbe5375da89722d681db"
+ name = "github.com/hashicorp/golang-lru"
+ packages = [
+ ".",
+ "simplelru"
+ ]
+ revision = "0fb14efe8c47ae851c0034ed7a448854d3d34cf3"
+
+[[projects]]
+ pruneopts = "UT"
+ revision = "0fb14efe8c47ae851c0034ed7a448854d3d34cf3"
+
+[[projects]]
+ digest = "1:c0d19ab64b32ce9fe5cf4ddceba78d5bc9807f0016db6b1183599da3dcc24d10"
+ name = "github.com/hashicorp/hcl"
+ packages = [
+ ".",
+ "hcl/ast",
+ "hcl/parser",
+ "hcl/printer",
+ "hcl/scanner",
+ "hcl/strconv",
+ "hcl/token",
+ "json/parser",
+ "json/scanner",
+ "json/token"
+ ]
+ pruneopts = "UT"
+ revision = "8cb6e5b959231cc1119e43259c4a608f9c51a241"
+ version = "v1.0.0"
+
+[[projects]]
+ digest = "1:a1038ef593beb4771c8f0f9c26e8b00410acd800af5c6864651d9bf160ea1813"
+ name = "github.com/hpcloud/tail"
+ packages = [
+ ".",
+ "ratelimiter",
+ "util",
+ "watch",
+ "winfile"
+ ]
+ pruneopts = "UT"
+ revision = "a30252cb686a21eb2d0b98132633053ec2f7f1e5"
+ version = "v1.0.0"
+
+[[projects]]
+ branch = "master"
+ digest = "1:3f5e7a4329f76e2617bf094eb5eec2ec2eff590d145c0beb32bac699628dea7d"
+ name = "github.com/huin/goupnp"
+ packages = [
+ ".",
+ "dcps/internetgateway1",
+ "dcps/internetgateway2",
+ "httpu",
+ "scpd",
+ "soap",
+ "ssdp"
+ ]
+ pruneopts = "UT"
+ revision = "1395d1447324cbea88d249fbfcfd70ea878fdfca"
+
+[[projects]]
+ name = "github.com/inconshreveable/mousetrap"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75"
+ version = "v1.0"
+
+[[projects]]
+ digest = "1:fe9aa4ac8c8d9bf5eaec1a8dd8c029f2cecd1c4ad91072b7ac99ecb44ff66910"
+ name = "github.com/ipfs/bbloom"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "4492942caf937893b9cf1ebba71c297beda904b2"
+ version = "v0.0.1"
+
+[[projects]]
+ digest = "1:052da1a7811a1db320501f2291f9b520a8f539fa6ec818079183913f0bcce0d0"
+ name = "github.com/ipfs/go-bitswap"
+ packages = [
+ ".",
+ "decision",
+ "getter",
+ "message",
+ "message/pb",
+ "messagequeue",
+ "network",
+ "notifications",
+ "peermanager",
+ "providerquerymanager",
+ "session",
+ "sessionmanager",
+ "sessionpeermanager",
+ "sessionrequestsplitter",
+ "testnet",
+ "wantlist",
+ "wantmanager",
+ ]
+ pruneopts = "UT"
+ revision = "2c47a554bca866a2ec50d54ccd192bf314c704f1"
+ version = "v0.0.4"
+
+[[projects]]
+ digest = "1:97b7b1549d94c885626167359549d9164bb35a9a584faa7c3a576909be0ea37f"
+ name = "github.com/ipfs/go-block-format"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "9e46c0dce5d9a041b8ea1eed8ca924b36355c61b"
+ version = "v0.0.2"
+
+[[projects]]
+ digest = "1:9447c73342cc8dc50457df133a4ea4a2bbac20358cf53cb1245879d4af4e05fb"
+ name = "github.com/ipfs/go-blockservice"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "6ca3282a724998a2d47165de34f200ec3bc89619"
+ version = "v0.0.3"
+
+[[projects]]
+ digest = "1:ff780041e005869242b2cf977f1d4fa3b8f9bdd302fd254b4a19f78502a6ee10"
+ name = "github.com/ipfs/go-cid"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "e7e67e08cfba888a4297224402e12832bdc15ea0"
+ version = "v0.0.1"
+
+[[projects]]
+ digest = "1:bc03440e1a50ae0610f3bfa6ebd8454ada47bcb1abcf75faf139d649c2598bfa"
+ name = "github.com/ipfs/go-cidutil"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "7a289d95efee00994339172286cc99120f87b3e9"
+ version = "v0.0.1"
+
+[[projects]]
+ digest = "1:072829d8ab9f41e523774b1a7cc1f5f214eb48c0a475667883c41d7d95bab1f1"
+ name = "github.com/ipfs/go-datastore"
+ packages = [
+ ".",
+ "autobatch",
+ "delayed",
+ "keytransform",
+ "mount",
+ "namespace",
+ "query",
+ "retrystore",
+ "sync",
+ ]
+ pruneopts = "UT"
+ revision = "aa9190c18f1576be98e974359fd08c64ca0b5a94"
+ version = "v0.0.5"
+
+[[projects]]
+ digest = "1:afbc88b3730097cd76ea72695941270547a5b3ed00d870ee0612897ac9943d79"
+ name = "github.com/ipfs/go-ds-measure"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "a74729db656decb31c9d0546aef893eaeb4247f7"
+ version = "v0.0.1"
+
+[[projects]]
+ digest = "1:bc3ed1378495622fd5eba7b63c86c10af1e5c4c1ae8642ab85b994ed89cf08bf"
+ name = "github.com/ipfs/go-fs-lock"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "66f8794e4aed94004486434cf8bf815e5991a0a4"
+ version = "v0.0.1"
+
+[[projects]]
+ digest = "1:15f5e953da8605b4edc4e2d5bae64680fe31a8c8da066bcfea4fb87112c8187c"
+ name = "github.com/ipfs/go-ipfs"
+ packages = [
+ ".",
+ "core",
+ "dagutils",
+ "exchange/reprovide",
+ "filestore",
+ "filestore/pb",
+ "fuse/mount",
+ "keystore",
+ "namesys",
+ "namesys/republisher",
+ "p2p",
+ "pin",
+ "pin/internal/pb",
+ "provider",
+ "repo",
+ "repo/common",
+ "repo/fsrepo",
+ "repo/fsrepo/migrations",
+ "thirdparty/cidv0v1",
+ "thirdparty/dir",
+ "thirdparty/math2",
+ "thirdparty/verifbs",
+ ]
+ pruneopts = "UT"
+ revision = "8efc82534f74916b3416b7f10e4daac8ff1e95c9"
+ version = "v0.4.20"
+
+[[projects]]
+ digest = "1:cfecb1f62c703a0b4651b4c98c2b9c7645f2f062038208ad25060a77c9ae7e5d"
+ name = "github.com/ipfs/go-ipfs-addr"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "ac4881d4db36effbbeebf93d9172fcb20ed04c15"
+ version = "v0.0.1"
+
+[[projects]]
+ digest = "1:429edc38cba9210059680d94ed67a8552632025635e666e112313986de135d74"
+ name = "github.com/ipfs/go-ipfs-blockstore"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "8d6a694a33d2729a94d848208c75d117b77c3492"
+ version = "v0.0.1"
+
+[[projects]]
+ digest = "1:cf743f8296553603264f68ae79fbd0ed9ce25636c28deedde111d6760b8b0c7d"
+ name = "github.com/ipfs/go-ipfs-chunker"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "ecef6090e78f549c5f48f18d398e7b7f97e8c32d"
+ version = "v0.0.1"
+
+[[projects]]
+ digest = "1:6a09c04984b8c581f3e7c765bc968a4bbfb6bc8ebf30f8bd6944dc73c43637b1"
+ name = "github.com/ipfs/go-ipfs-config"
+ packages = [
+ ".",
+ "serialize",
+ ]
+ pruneopts = "UT"
+ revision = "3a550f0da56c2527610b6db17aa2a9d65ae534fd"
+ version = "v0.0.2"
+
+[[projects]]
+ digest = "1:ae1ee4c628ee8ad66d9505bb2685902c93e0cd89089a17b8804463b5cc1b766b"
+ name = "github.com/ipfs/go-ipfs-delay"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "6482ad624d0b4f4053563439f8ca0bd619fbc737"
+ version = "v0.0.1"
+
+[[projects]]
+ digest = "1:0fcfbb9a7c8245d19d5a79c13ad702201c1d9cd8ca79619379a22845de723278"
+ name = "github.com/ipfs/go-ipfs-ds-help"
+ packages = ["."]
+ revision = "5c8c8bd35d3832f5d134ae1e1e375b69a4d25242"
+ version = "v1.0.1"
+
+[[projects]]
+ branch = "master"
+ name = "github.com/lib/pq"
+ packages = [
+ ".",
+ "oid"
+ ]
+ revision = "4ded0e9383f75c197b3a2aaa6d590ac52df6fd79"
+
+[[projects]]
+ name = "github.com/magiconair/properties"
+ packages = ["."]
+ revision = "c2353362d570a7bfa228149c62842019201cfb71"
+ version = "v1.8.0"
+ pruneopts = "UT"
+ revision = "4a69beb72c1b4e6e7ed62c5c5cbc1bd7a3d219b2"
+ version = "v0.0.1"
+
+[[projects]]
+ digest = "1:c8bc4cbd7b94d84784f6f99cca35ebedebb5f9ded2d561e4130d8c67cc5127b0"
+ name = "github.com/ipfs/go-ipfs-exchange-interface"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "b6e88260772433e18af18bb3f237d78678e65f0b"
+ version = "v0.0.1"
+
+[[projects]]
+ digest = "1:284cfd2a17692d0e628a263854b8acea34427b9aa2f4f923b91570f07ae65d2e"
+ name = "github.com/ipfs/go-ipfs-exchange-offline"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "e3705b31117ceccfa67820f84c1085f74f5e039b"
+ version = "v0.0.1"
+
+[[projects]]
+ digest = "1:ff3f10c0e0d9c679390b06966df7344a72c31c3bec45c191676ab03fa845123f"
+ name = "github.com/ipfs/go-ipfs-files"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "c68472a9b1ec45177ccf8fda607698c86ae0060f"
+ version = "v0.0.2"
+
+[[projects]]
+ digest = "1:f761e426f29519b6f4c7e419ed7aacb93c64fe0fe9db4835373b00034f15b959"
+ name = "github.com/ipfs/go-ipfs-flags"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "89d41d6d2542f7b3b25e01d7b4a3769885055454"
+ version = "v0.0.1"
+
+[[projects]]
+ digest = "1:990c3a92954ef12159a3564533e63edc53feeadcb513930250351b919c6756f5"
+ name = "github.com/ipfs/go-ipfs-posinfo"
+ packages = ["."]
+ revision = "ae18d6b8b3205b561c79e8e5f69bff09736185f4"
+ version = "v1.0.0"
+
+[[projects]]
+ name = "github.com/mitchellh/mapstructure"
+ packages = ["."]
+ revision = "fa473d140ef3c6adf42d6b391fe76707f1f243c8"
+ version = "v1.0.0"
+
+[[projects]]
+ name = "github.com/onsi/ginkgo"
+ packages = [
+ ".",
+ "config",
+ "internal/codelocation",
+ "internal/containernode",
+ "internal/failer",
+ "internal/leafnodes",
+ "internal/remote",
+ "internal/spec",
+ "internal/spec_iterator",
+ "internal/specrunner",
+ "internal/suite",
+ "internal/testingtproxy",
+ "internal/writer",
+ "reporters",
+ "reporters/stenographer",
+ "reporters/stenographer/support/go-colorable",
+ "reporters/stenographer/support/go-isatty",
+ "types"
+ ]
+ revision = "3774a09d95489ccaa16032e0770d08ea77ba6184"
+ version = "v1.6.0"
+
+[[projects]]
+ name = "github.com/onsi/gomega"
+ packages = [
+ ".",
+ "format",
+ "ghttp",
+ "internal/assertion",
+ "internal/asyncassertion",
+ "internal/oraclematcher",
+ "internal/testingtsupport",
+ "matchers",
+ "matchers/support/goraph/bipartitegraph",
+ "matchers/support/goraph/edge",
+ "matchers/support/goraph/node",
+ "matchers/support/goraph/util",
+ "types"
+ ]
+ revision = "7615b9433f86a8bdf29709bf288bc4fd0636a369"
+ version = "v1.4.2"
+
+[[projects]]
+ name = "github.com/pborman/uuid"
+ packages = ["."]
+ revision = "adf5a7427709b9deb95d29d3fa8a2bf9cfd388f1"
+ version = "v1.2"
+
+[[projects]]
+ name = "github.com/pelletier/go-toml"
+ packages = ["."]
+ revision = "c01d1270ff3e442a8a57cddc1c92dc1138598194"
+ version = "v1.2.0"
+
+[[projects]]
+ name = "github.com/pkg/errors"
+ packages = ["."]
+ digest = "1:1d7e1867c49a6dd9856598ef7c3123604ea3daabf5b83f303ff457bcbc410b1d"
+ name = "github.com/pkg/errors"
+ packages = ["."]
+ pruneopts = ""
+ revision = "ba968bfe8b2f7e042a574c888954fccecfa385b4"
+ version = "v0.8.1"
+
+[[projects]]
+ name = "github.com/pressly/goose"
+ packages = ["."]
+ revision = "e4b98955473e91a12fc7d8816c28d06376d1d92c"
+ version = "v2.6.0"
+
+[[projects]]
+ digest = "1:4ae201412922170629db9f034bc2e205e425a36a4b13a2494180f9dd485fb7b2"
+ name = "github.com/prometheus/tsdb"
+ packages = ["fileutil"]
+ pruneopts = ""
+ revision = "4b3a5ac5d36e5262d2656c8d149e137c2d1fab12"
+ version = "v0.7.0"
+ pruneopts = "UT"
+ revision = "19b0f52f6bd140be93fb568203586a165eb1aadf"
+ version = "v0.0.1"
+
+[[projects]]
+ digest = "1:3d6b825f2ac90788f3ac6bb7927d339ded21d02951d08b5bb66bf5326af45ea9"
+ name = "github.com/ipfs/go-ipfs-pq"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "63128f5dd36a6c20c0f2d1c65eb4390d2590a273"
+ version = "v0.0.1"
+
+[[projects]]
+ digest = "1:744d6471a84d76b6d82eb6e15a0349aebb8728298caa649762ffd1e05c4109ad"
+ name = "github.com/ipfs/go-ipfs-routing"
+ packages = [
+ "mock",
+ "none",
+ "offline",
+ ]
+ pruneopts = "UT"
+ revision = "29e4c89c60c510152e46033844194a62bc89b281"
+ version = "v0.0.1"
+
+[[projects]]
+ digest = "1:0b4439ae69776549e6489b261f66894a1390140dad53f1c3b1fbfc074478590d"
+ name = "github.com/ipfs/go-ipfs-util"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "a4bb5361e49427531f9a716ead2ce4bd9bdd7959"
+ version = "v0.0.1"
+
+[[projects]]
+ digest = "1:53f917e28732fbb5c1f24e368af2f03edbd3547dfe6e6a252b3727ce9f18f9cd"
+ name = "github.com/ipfs/go-ipld-cbor"
+ packages = [
+ ".",
+ "encoding",
+ ]
+ pruneopts = "UT"
+ revision = "e63450c54844e1bfe509b17cc73071c4ab150ef0"
+ version = "v0.0.1"
+
+[[projects]]
+ digest = "1:a64b5e2c43d7a8a9bbda0d8519dca1841cdd7e352ffd059cf2a8fa06978ec5d1"
+ name = "github.com/ipfs/go-ipld-format"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "e6e9ea4d16a85d09cafb4dace15b978e984fa672"
+ version = "v0.0.1"
+
+[[projects]]
+ digest = "1:4638b57014e4a204350087e3a2d5631f8aaa197bb6af688ca6e280457a7a46fa"
+ name = "github.com/ipfs/go-ipns"
+ packages = [
+ ".",
+ "pb",
+ ]
+ pruneopts = "UT"
+ revision = "a989b48e3b7d32af1c872cbf2f6e884a08a9b351"
+ version = "v0.0.1"
+
+[[projects]]
+ digest = "1:e8c78569402b8dcf846924dea6eb27b1de135c9a53d7adbd2629250ef66c021a"
+ name = "github.com/ipfs/go-log"
+ packages = [
+ ".",
+ "tracer",
+ "tracer/wire",
+ "writer",
+ ]
+ pruneopts = "UT"
+ revision = "91b837264c0f35dd4e2be341d711316b91d3573d"
+ version = "v0.0.1"
+
+[[projects]]
+ digest = "1:703455843c663f97b4bd2506f6ed7ac307f6f45203b2c2452df888c01325f6c3"
+ name = "github.com/ipfs/go-merkledag"
+ packages = [
+ ".",
+ "pb",
+ ]
+ pruneopts = "UT"
+ revision = "5e8e186e4d8f03514a43464e5b47310e71372ffc"
+ version = "v0.0.3"
+
+[[projects]]
+ digest = "1:2de37461901377cb21aae96aab4ca67ebbb6d77e5f140c8f376eb566b7805365"
+ name = "github.com/ipfs/go-metrics-interface"
+ packages = ["."]
+ revision = "0f065fa99b48b842c3fd3e2c8b194c6f2b69f6b8"
+ version = "v0.9.1"
+
+[[projects]]
+ name = "github.com/rs/cors"
+ packages = ["."]
+ revision = "3fb1b69b103a84de38a19c3c6ec073dd6caa4d3f"
+ version = "v1.5.0"
+
+[[projects]]
+ name = "github.com/sirupsen/logrus"
+ packages = ["."]
+ revision = "bcd833dfe83d3cebad139e4a29ed79cb2318bf95"
+ version = "v1.2.0"
+
+[[projects]]
+ name = "github.com/spf13/afero"
+ packages = [
+ ".",
+ "mem"
+ ]
+ revision = "d40851caa0d747393da1ffb28f7f9d8b4eeffebd"
+ version = "v1.1.2"
+
+[[projects]]
+ name = "github.com/spf13/cast"
+ packages = ["."]
+ revision = "8965335b8c7107321228e3e3702cab9832751bac"
+ version = "v1.2.0"
+
+[[projects]]
+ name = "github.com/spf13/cobra"
+ packages = ["."]
+ revision = "ef82de70bb3f60c65fb8eebacbb2d122ef517385"
+ version = "v0.0.3"
+
+[[projects]]
+ name = "github.com/spf13/jwalterweatherman"
+ packages = ["."]
+ revision = "4a4406e478ca629068e7768fc33f3f044173c0a6"
+ version = "v1.0.0"
+
+[[projects]]
+ name = "github.com/spf13/pflag"
+ packages = ["."]
+ revision = "9a97c102cda95a86cec2345a6f09f55a939babf5"
+ version = "v1.0.2"
+
+[[projects]]
+ name = "github.com/spf13/viper"
+ packages = ["."]
+ revision = "8fb642006536c8d3760c99d4fa2389f5e2205631"
+ version = "v1.2.0"
+ pruneopts = "UT"
+ revision = "87aa106f53272f064ca7956a6db83f17a553f254"
+ version = "v0.0.1"
+
+[[projects]]
+ digest = "1:eb5e3140e55e3410055e91df6538a8712a3c20b33a97c397ba4beba8a9515db8"
+ name = "github.com/ipfs/go-mfs"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "198fe2d22702d7d8102ba09900cddfd6981cabe1"
+ version = "v0.0.5"
+
+[[projects]]
+ digest = "1:ab4d5fb6c2469b61d8e9c3dd05fe29cc6935676acb17a7273d462e3bf263d87b"
+ name = "github.com/ipfs/go-path"
+ packages = [
+ ".",
+ "resolver",
+ ]
+ pruneopts = "UT"
+ revision = "a1e7a849ac2bae46007920db4b6efe6faa4296a6"
+ version = "v0.0.3"
+
+[[projects]]
+ digest = "1:5d5961815f8e4f1fbad28f6c7ff5e42fcd9527aa823a5daa19b622b9cc41d1ed"
+ name = "github.com/ipfs/go-todocounter"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "bc75efcf13e6e50fbba27679ba5451585d70c954"
+ version = "v0.0.1"
+
+[[projects]]
+ digest = "1:7f07522134395d0e83281d228ba5b08bd8ae440423fbd4c8780a348aa27fc804"
+ name = "github.com/ipfs/go-unixfs"
+ packages = [
+ ".",
+ "hamt",
+ "importer/helpers",
+ "importer/trickle",
+ "io",
+ "mod",
+ "pb",
+ ]
+ pruneopts = "UT"
+ revision = "0b7b8867647cb408d8c057d00b0f0b170e2f1f1c"
+ version = "v0.0.4"
+
+[[projects]]
+ digest = "1:78438260483c355139f9d83830a88ecd69578904f0f288134d3a95786c4f0864"
+ name = "github.com/ipfs/go-verifcid"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "34e41ba962e7ce0211a05915f788486c8db755f1"
+ version = "v0.0.1"
+
+[[projects]]
+ digest = "1:164193f6d91f8e2c9b5bfc5cb4522c8cd9c0994401eefbef0f5edbe9a3d10ce2"
+ name = "github.com/ipfs/interface-go-ipfs-core"
+ packages = [
+ ".",
+ "options",
+ "options/namesys",
+ "path",
+ ]
+ pruneopts = "UT"
+ revision = "77861581014b14ab47de990e82a1637fe1430ab7"
+ version = "v0.0.7"
+
+[[projects]]
+ digest = "1:b352ae8b1a77cc6b48fc8e314e34a522cfc76d6ca3a06c93b29c9cde5de6771e"
+ name = "github.com/jackpal/gateway"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "cbcf4e3f3baee7952fc386c8b2534af4d267c875"
+ version = "v1.0.5"
+
+[[projects]]
+ digest = "1:32b82e71cf24f8b78323e0d7903c4b90278486283965aa2a19b1ea13763b8f34"
+ name = "github.com/jackpal/go-nat-pmp"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "c9cfead9f2a36ddf3daa40ba269aa7f4bbba6b62"
+ version = "v1.0.1"
+
+[[projects]]
+ branch = "master"
+ digest = "1:62fe3a7ea2050ecbd753a71889026f83d73329337ada66325cbafd5dea5f713d"
+ name = "github.com/jbenet/go-context"
+ packages = ["io"]
+ pruneopts = "UT"
+ revision = "d14ea06fba99483203c19d92cfcd13ebe73135f4"
+
+[[projects]]
+ digest = "1:30f857b000a0d14f978110222f1b1ba9cb1de8f6cabaca51933f3627ca6578a0"
+ name = "github.com/jbenet/go-is-domain"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "009bc9fc8d69261cc21e8eb2aa0925af155d1c11"
+ version = "v1.0.2"
+
+[[projects]]
+ branch = "master"
+ digest = "1:8f4aedc183dc8dfef9a7a1f1ba205dc87ecd2675eea350a736bda889e3bcf8ea"
+ name = "github.com/jbenet/go-temp-err-catcher"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "aac704a3f4f27190b4ccc05f303a4931fd1241ff"
+
+[[projects]]
+ branch = "master"
+ digest = "1:a2a82ac6d7f2ab5966591f95612e3ecd9afed66051189e06876a29ed3744a3ea"
+ name = "github.com/jbenet/goprocess"
+ packages = [
+ ".",
+ "context",
+ "periodic",
+ "ratelimit",
+ ]
+ pruneopts = "UT"
+ revision = "b497e2f366b8624394fb2e89c10ab607bebdde0b"
+
+[[projects]]
+ branch = "master"
+ digest = "1:7654989089e5bd5b6734ec3be8b695e87d3f1f8d95620b343fd7d3995a5b60d7"
+ name = "github.com/jmoiron/sqlx"
+ packages = [
+ ".",
+ "reflectx",
+ ]
+ pruneopts = "UT"
+ revision = "0dae4fefe7c0e190f7b5a78dac28a1c82cc8d849"
+
+[[projects]]
+ branch = "master"
+ digest = "1:6addadad21c95f83b592099496bb250a30aa8882faff9f8bd22aa9a15b6d8db1"
+ name = "github.com/karalabe/hid"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "d815e0c1a2e2082a287a2806bc90bc8fc7b276a9"
+
+[[projects]]
+ digest = "1:0a69a1c0db3591fcefb47f115b224592c8dfa4368b7ba9fae509d5e16cdc95c8"
+ name = "github.com/konsorten/go-windows-terminal-sequences"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "5c8c8bd35d3832f5d134ae1e1e375b69a4d25242"
+ version = "v1.0.1"
+
+[[projects]]
+ digest = "1:58ad79834dc097c36a857a8c325d646af0a8bbd73375a6958a639507c5399a61"
+ name = "github.com/koron/go-ssdp"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "6d1709049dead37ead37808479f88c9bffa2c4d6"
+ version = "v0.1"
+
+[[projects]]
+ branch = "master"
+ digest = "1:8ef506fc2bb9ced9b151dafa592d4046063d744c646c1bbe801982ce87e4bc24"
+ name = "github.com/lib/pq"
+ packages = [
+ ".",
+ "oid",
+ ]
+ pruneopts = "UT"
+ revision = "4ded0e9383f75c197b3a2aaa6d590ac52df6fd79"
+
+[[projects]]
+ digest = "1:483fcb9b21a758b47501f8880628b85aa3c4e99e33166867d06fa278965c66b2"
+ name = "github.com/libp2p/go-addr-util"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "4cd36c0f325f9e38f1e31ff7a10b9d94d53a11cf"
+ version = "v0.0.1"
+
+[[projects]]
+ digest = "1:f9e8d1157f79aa5e81b34e0cdc7a6c99d6e44ad7a098f4e6869b8b83ef3d27bb"
+ name = "github.com/libp2p/go-buffer-pool"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "eecb57f6a721b4a66062ebeb61d1da7ce1c38fbf"
+ version = "v0.0.1"
+
+[[projects]]
+ digest = "1:5810d7b1453ad0a085afc2afccbe88d606be67b8be1e12706158dbcbf95ae243"
+ name = "github.com/libp2p/go-conn-security"
+ packages = [
+ ".",
+ "insecure",
+ ]
+ pruneopts = "UT"
+ revision = "80b6115ae32f104b2ed14d16a8551248f4599338"
+ version = "v0.0.1"
+
+[[projects]]
+ digest = "1:9c14cac19ac8157c9cb89637da301f6b4994b93fd71da81e252940f6d0cf7332"
+ name = "github.com/libp2p/go-conn-security-multistream"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "d4c3bf7e5688390e4106d3ec73aafd7d0856143b"
+ version = "v0.0.1"
+
+[[projects]]
+ digest = "1:83d3d59c84ff3da342ab63011d79750ccb987bda399eb64db3abd3e2fd32c18f"
+ name = "github.com/libp2p/go-flow-metrics"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "1f5b3acc846b2c8ce4c4e713296af74f5c24df55"
+ version = "v0.0.1"
+
+[[projects]]
+ digest = "1:1432bf2ddb7cfb0be623f9299e039a3910c20ecedd4beb2612c8fc6baabb666f"
+ name = "github.com/libp2p/go-libp2p"
+ packages = [
+ ".",
+ "config",
+ "p2p/discovery",
+ "p2p/host/basic",
+ "p2p/host/relay",
+ "p2p/host/routed",
+ "p2p/net/mock",
+ "p2p/protocol/identify",
+ "p2p/protocol/identify/pb",
+ "p2p/protocol/ping",
+ ]
+ pruneopts = "UT"
+ revision = "e63ff38c3d274679753cf98846b247e06e9b9f5b"
+ version = "v0.0.16"
+
+[[projects]]
+ digest = "1:7a9b53c8925819845e9ae47579cac5de87b66eddfc72988578f318504136a68c"
+ name = "github.com/libp2p/go-libp2p-autonat"
+ packages = [
+ ".",
+ "pb",
+ ]
+ pruneopts = "UT"
+ revision = "c827b8ba68e6997431c27313efad33df19b5f6a3"
+ version = "v0.0.4"
+
+[[projects]]
+ digest = "1:c6c83e198fb782c1fc0e2706d9ff01d112d07f8781fd6f06127d08addd32b5fa"
+ name = "github.com/libp2p/go-libp2p-autonat-svc"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "bcaff01a6eb53bf7e7a93f06b8fc494627a91641"
+ version = "v0.0.5"
+
+[[projects]]
+ digest = "1:1289f34bbc72cfe59de1528e793e27c67a44a9597e1537ef03597abef8641f6e"
+ name = "github.com/libp2p/go-libp2p-circuit"
+ packages = [
+ ".",
+ "pb",
+ ]
+ pruneopts = "UT"
+ revision = "d07cd5f739a7878121b10e54a8ead734f93e2ddf"
+ version = "v0.0.4"
+
+[[projects]]
+ digest = "1:b218b4385ba83a014018f63f6bcb78eae8fb51b86b410471c1ccc1ee2fac4d10"
+ name = "github.com/libp2p/go-libp2p-connmgr"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "44a04f91e1fc9eb63caaf970e55cf319be76abee"
+ version = "v0.0.3"
+
+[[projects]]
+ digest = "1:83915d6b4485f9ca8727ad9195d0881f1eeea4c9f286b0c0fb4b0757c21d1bc2"
+ name = "github.com/libp2p/go-libp2p-crypto"
+ packages = [
+ ".",
+ "pb",
+ ]
+ pruneopts = "UT"
+ revision = "b0ed0e663e8b6832bad3f4502b2f6551ff2686cd"
+ version = "v0.0.1"
+
+[[projects]]
+ digest = "1:c8e13ce10e73ffc2c59e11fd62d85a1e516e33af6521ed337d2e4777bc7605d8"
+ name = "github.com/libp2p/go-libp2p-discovery"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "4cb4193d603389a75bccd07336de74d54bea6b00"
+ version = "v0.0.2"
+
+[[projects]]
+ digest = "1:1df10c788e75259f6ebae0612de30f0db09e690042b9db64551a188c6509cc8b"
+ name = "github.com/libp2p/go-libp2p-host"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "df61f890baee33effc62473e65c0ce481407181d"
+ version = "v0.0.2"
+
+[[projects]]
+ digest = "1:bc58f4c83d59130bbef42bbd7ebb0d23ccd8cc9c1eecd63a57b5576f5f8effc2"
+ name = "github.com/libp2p/go-libp2p-interface-connmgr"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "e80dd2e9f839e44febfcb7e6b38ded8761332eb6"
+ version = "v0.0.3"
+
+[[projects]]
+ digest = "1:065f0484575f052b79972215142bb50ac634c5282bf85692192fc1dfc8752b8b"
+ name = "github.com/libp2p/go-libp2p-interface-pnet"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "b02026130a4daafb8001e039e116121cb92ae1a9"
+ version = "v0.0.1"
+
+[[projects]]
+ digest = "1:9c47cb524a992e85504d0916d1cdb9e022314d180f57f3e1bf32c6698b29e53f"
+ name = "github.com/libp2p/go-libp2p-kad-dht"
+ packages = [
+ ".",
+ "metrics",
+ "opts",
+ "pb",
+ "providers",
+ ]
+ pruneopts = "UT"
+ revision = "ca611b1605e5c64e240c98755a4f913d661979b2"
+ version = "v0.0.9"
+
+[[projects]]
+ digest = "1:029a31918e966dba732de956af5af626c92d9e1296b2b34c6e68d4e6c5cf1b7e"
+ name = "github.com/libp2p/go-libp2p-kbucket"
+ packages = [
+ ".",
+ "keyspace",
+ ]
+ pruneopts = "UT"
+ revision = "0ac6a1f84ed8c7d05b204f9f09556b1e34e1253a"
+ version = "v0.1.1"
+
+[[projects]]
+ digest = "1:401eaa568a08603ebcccd833d0d69c2ac1abe153f1260f7a82375c3a455c7223"
+ name = "github.com/libp2p/go-libp2p-loggables"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "332c68ea465a3353571377635eb0fc257a0c38c4"
+ version = "v0.0.1"
+
+[[projects]]
+ digest = "1:09deed1e61077096d762c465c8cb6bd6f75a89729e27de6b3880feb455ba6358"
+ name = "github.com/libp2p/go-libp2p-metrics"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "f7021db7729eb519a86ec6a90b5b476e6072f6f7"
+ version = "v0.0.1"
+
+[[projects]]
+ digest = "1:4614c7d351b9cc24ef6457107fad9830664615bb7d7de91de10c4a4ab1919545"
+ name = "github.com/libp2p/go-libp2p-nat"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "c50c291a61bceccb914366d93eb24f58594e9134"
+ version = "v0.0.4"
+
+[[projects]]
+ digest = "1:a87f13baa72a09a5d6fea78e3a1af82f2bc1f0637a4eb4304c5cba765720ccd3"
+ name = "github.com/libp2p/go-libp2p-net"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "e1b54a3fd69634603ac02b34e4eefcf5aca50ed9"
+ version = "v0.0.2"
+
+[[projects]]
+ digest = "1:9d7f797f63fc1d4a9960c89326cf26304c4db52e0490411da3e4deee65de5146"
+ name = "github.com/libp2p/go-libp2p-netutil"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "126124c7f3e570a469754c4857bd86527f5eb94e"
+ version = "v0.0.1"
+
+[[projects]]
+ digest = "1:dd98b7bc6fcd8ca56cd6f19f988db68d970eba9e66f25bc392e563a5791e0a26"
+ name = "github.com/libp2p/go-libp2p-peer"
+ packages = [
+ ".",
+ "peerset",
+ "test",
+ ]
+ pruneopts = "UT"
+ revision = "96d6d7940e6fc555240a92d1b4615049cd451da2"
+ version = "v0.1.0"
+
+[[projects]]
+ digest = "1:6806fd32afb9c73cf45624ddd4f6b1e3ae4ce119443b34bbb1dc8fe6fcb19823"
+ name = "github.com/libp2p/go-libp2p-peerstore"
+ packages = [
+ ".",
+ "addr",
+ "pstoremem",
+ "queue",
+ ]
+ pruneopts = "UT"
+ revision = "b496ee543347a9c724e02ff7102da9d78c8acbee"
+ version = "v0.0.3"
+
+[[projects]]
+ digest = "1:5d5de8a1d6165e92773a676617b354f352dd39849cbb6580d6d017706ca8e38e"
+ name = "github.com/libp2p/go-libp2p-pnet"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "7424696a369ba1535fd7961f22d710e39ae7c8f9"
+ version = "v0.0.1"
+
+[[projects]]
+ digest = "1:861a4351f79c9e2bca75407d8801b55da0526feec15ec98b433c2f800ad1f393"
+ name = "github.com/libp2p/go-libp2p-protocol"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "c170ad966a647835bda0cbe4dc710cf9f94949b6"
+ version = "v0.0.1"
+
+[[projects]]
+ digest = "1:e8d3d819fb8398e0945fbe5e55b519c3c76d952e0e33901a47fdadc0fd1874e7"
+ name = "github.com/libp2p/go-libp2p-pubsub"
+ packages = [
+ ".",
+ "pb",
+ ]
+ pruneopts = "UT"
+ revision = "25cbf38777e869acb77e8079c3c76d6b430e66ad"
+ version = "v0.0.1"
+
+[[projects]]
+ digest = "1:bcf57f2766818c04d2fddc0bd75167b8cbf36f7043d4f4a73c729fd6ec8ada08"
+ name = "github.com/libp2p/go-libp2p-pubsub-router"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "228ab843b11da664bb67cf1caa1b1fdf611aa769"
+ version = "v0.0.3"
+
+[[projects]]
+ digest = "1:a1cf76b0f654cd8e2aec54b8c6f2a8aa4373f15879db9f5671380c421fcba0c9"
+ name = "github.com/libp2p/go-libp2p-quic-transport"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "b069bc9fa68a05c01a361550ca59f5e3fb9b421e"
+ version = "v0.0.3"
+
+[[projects]]
+ digest = "1:712d8c0de8c227d80e589af33389c7c8b56b7ade75fa1d6b81963330ed7427e7"
+ name = "github.com/libp2p/go-libp2p-record"
+ packages = [
+ ".",
+ "pb",
+ ]
+ pruneopts = "UT"
+ revision = "4c2093f40950fe401a612a725ef0765c0c767b60"
+ version = "v0.0.1"
+
+[[projects]]
+ digest = "1:40536312550a2d67b11568a05e9885a3d7b728000a88a93d577f117fa0d2eef6"
+ name = "github.com/libp2p/go-libp2p-routing"
+ packages = [
+ ".",
+ "notifications",
+ "options",
+ ]
+ pruneopts = "UT"
+ revision = "ab366780f22ac0d2625105a9f6d3cace1817dd30"
+ version = "v0.0.1"
+
+[[projects]]
+ digest = "1:86438785b80785614784bed81c0e8bcd9cdb362bfd1bb7675e24136d32b5842a"
+ name = "github.com/libp2p/go-libp2p-routing-helpers"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "80177179327fbef5249eb0bc7f372d830f939a5c"
+ version = "v0.0.2"
+
+[[projects]]
+ digest = "1:6a12f20cd4c7260f211f096aa70234150d930514070d73ccaa46dd17ed2fbbc1"
+ name = "github.com/libp2p/go-libp2p-secio"
+ packages = [
+ ".",
+ "pb",
+ ]
+ pruneopts = "UT"
+ revision = "b5b0ccd501582b3aec0a8076e9009c4c69f075b6"
+ version = "v0.0.2"
+
+[[projects]]
+ digest = "1:13bb1cd21375488f6a49134b261439974e8105d04eb84e396c9c86248e0f4d97"
+ name = "github.com/libp2p/go-libp2p-swarm"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "51da4b6c9c2e869dce87a455a7c788d7181711c7"
+ version = "v0.0.2"
+
+[[projects]]
+ digest = "1:3b26a897674c84976f9ee6d93d91d0fc503a4aada9c6b7a69b5ed4752452d035"
+ name = "github.com/libp2p/go-libp2p-transport"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "760cba29c65701ce7b688f238f6c93cc1d899dde"
+ version = "v0.0.4"
+
+[[projects]]
+ digest = "1:9e59f3adcbbffe3fd2333843bb3d944e5b42791d86dfdbef67673fb9a1d0bce1"
+ name = "github.com/libp2p/go-libp2p-transport-upgrader"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "b4ab689796cdae99ad6641abcedcd7c23258de0c"
+ version = "v0.0.1"
+
+[[projects]]
+ digest = "1:56b76ab784de08c03549ce824b2f103390c744016cf22c7d3cacd7f4abb26e54"
+ name = "github.com/libp2p/go-maddr-filter"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "1258bb7e3e3a37bb9a93aaf77ef88f8405b39bce"
+ version = "v0.0.1"
+
+[[projects]]
+ digest = "1:dca7a0779bc8c3052ff1760928da7fab1d6bdaa568de55c175cb96c83a6d20c4"
+ name = "github.com/libp2p/go-mplex"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "b16006283f6036f9a461f78692c397b134a75393"
+ version = "v0.0.1"
+
+[[projects]]
+ digest = "1:fec6c720509c1682df4e297899d23951d1b3ad3bcc124ecf734af34053a18982"
+ name = "github.com/libp2p/go-msgio"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "b47fa43a3e8e2b96e34854e4a25b2b0988322621"
+ version = "v0.0.2"
+
+[[projects]]
+ digest = "1:82e0411449d8af0c34e200cd6b90e70689d692d17f836906194fa9fc28692e80"
+ name = "github.com/libp2p/go-nat"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "d13fdefb3bbb2fde2c6fc090a7ea992cec8b26df"
+ version = "v0.0.3"
+
+[[projects]]
+ digest = "1:3218d9edf75d814d2994ce4b14fae01c657a3284af84522efcc8dee89806f4ca"
+ name = "github.com/libp2p/go-reuseport"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "3e6d618acfdfacbbeff71cb2bd70fc188f897a0f"
+ version = "v0.0.1"
+
+[[projects]]
+ digest = "1:bf12fbd51fb864c9e2cb688581d3c14551a8c3d1c2fa60c9ad405c532e1b9d42"
+ name = "github.com/libp2p/go-reuseport-transport"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "c7583c88df654a2ecd621e863f661783d79b64d1"
+ version = "v0.0.2"
+
+[[projects]]
+ digest = "1:28994f656f7bd53b2f506641d72878250583051bd86477ab8129c613c8437ee3"
+ name = "github.com/libp2p/go-stream-muxer"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "96b8d4dc6b2577782a7c6c33776c115e3d2eacf6"
+ version = "v0.0.1"
+
+[[projects]]
+ digest = "1:32b1b70c98be85d88229af2ba0cceb9954e7ef88c3f7e90f95a8ea2deb32c0d3"
+ name = "github.com/libp2p/go-tcp-transport"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "42717ef323c6cd024d3196d18bc1b7657c453d6d"
+ version = "v0.0.2"
+
+[[projects]]
+ digest = "1:d232baf2d647f75c9a676dcc2f4dcc912aa8c399001c7a45dc981131b77e414f"
+ name = "github.com/libp2p/go-testutil"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "425d0bf3c5d09720ab62cb2b79107d83651f271b"
+ version = "v0.0.1"
+
+[[projects]]
+ digest = "1:fe4581341f14aba2ef06749c5f2fc6483d4354b25e3c6e0094a4135082a22ed2"
+ name = "github.com/libp2p/go-ws-transport"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "93daaa611babb322b314d33c6c6ad26298f55f56"
+ version = "v0.0.2"
+
+[[projects]]
+ digest = "1:d90f4189a065809b38ccc5a5a6a66d57ccad809562409903f7518352aeb5986b"
+ name = "github.com/lucas-clemente/quic-go"
+ packages = [
+ ".",
+ "internal/ackhandler",
+ "internal/congestion",
+ "internal/flowcontrol",
+ "internal/handshake",
+ "internal/protocol",
+ "internal/qerr",
+ "internal/utils",
+ "internal/wire",
+ ]
+ pruneopts = "UT"
+ revision = "8dcdf12ff78def6cfd36107d8bf42aa38110fa94"
+ version = "v0.11.1"
+
+[[projects]]
+ digest = "1:c568d7727aa262c32bdf8a3f7db83614f7af0ed661474b24588de635c20024c7"
+ name = "github.com/magiconair/properties"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "c2353362d570a7bfa228149c62842019201cfb71"
+ version = "v1.8.0"
+
+[[projects]]
+ branch = "master"
+ digest = "1:94e7d7656c79a0c4eea386d663a046bb904bb93217052b74b16e79bb04f82f57"
+ name = "github.com/marten-seemann/qtls"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "65ca381cd298d7e0aef0de8ba523a870ec5a96fe"
+
+[[projects]]
+ digest = "1:2fa7b0155cd54479a755c629de26f888a918e13f8857a2c442205d825368e084"
+ name = "github.com/mattn/go-colorable"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "3a70a971f94a22f2fa562ffcc7a0eb45f5daf045"
+ version = "v0.1.1"
+
+[[projects]]
+ digest = "1:e150b5fafbd7607e2d638e4e5cf43aa4100124e5593385147b0a74e2733d8b0d"
+ name = "github.com/mattn/go-isatty"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "c2a7a6ca930a4cd0bc33a3f298eb71960732a3a7"
+ version = "v0.0.7"
+
+[[projects]]
+ digest = "1:2b4b4b2e5544c2a11a486c1b631357aa2ddf766e50c1b2483cf809da2c511234"
+ name = "github.com/miekg/dns"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "73601d4aed9d844322611759d7f3619110b7c88e"
+ version = "v1.1.8"
+
+[[projects]]
+ branch = "master"
+ digest = "1:130cefe87d7eeefc824978dcb78e35672d4c49a11f25c153fbf0cfd952756fa3"
+ name = "github.com/minio/blake2b-simd"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "3f5f724cb5b182a5c278d6d3d55b40e7f8c2efb4"
+
+[[projects]]
+ branch = "master"
+ digest = "1:d69117243f58a0d320c2889872d8c14d323d865277dc49fc85bfcf48b2846b8f"
+ name = "github.com/minio/sha256-simd"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "05b4dd3047e5d6e86cb4e0477164b850cd896261"
+
+[[projects]]
+ digest = "1:78bbb1ba5b7c3f2ed0ea1eab57bdd3859aec7e177811563edc41198a760b06af"
+ name = "github.com/mitchellh/go-homedir"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "ae18d6b8b3205b561c79e8e5f69bff09736185f4"
+ version = "v1.0.0"
+
+[[projects]]
+ digest = "1:645110e089152bd0f4a011a2648fbb0e4df5977be73ca605781157ac297f50c4"
+ name = "github.com/mitchellh/mapstructure"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "fa473d140ef3c6adf42d6b391fe76707f1f243c8"
+ version = "v1.0.0"
+
+[[projects]]
+ digest = "1:cf5b7fbff2c87cff6c0e11f87b30edc21abc6592e6a76f41003ca6d5a712cf48"
+ name = "github.com/mr-tron/base58"
+ packages = ["base58"]
+ pruneopts = "UT"
+ revision = "6598572f05537592acb5a609ff53c4c7fbba7a3e"
+ version = "v1.1.1"
+
+[[projects]]
+ digest = "1:b9fe622bbadbb060338620752b1cb3aa1473855071195ebe83813af5ebb3629b"
+ name = "github.com/multiformats/go-base32"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "a9c2755c3d1672dbe6a7e4a5d182169fa30b6a8e"
+ version = "v0.0.3"
+
+[[projects]]
+ digest = "1:4fb02614401f3511d3c76482b6bc626a307811d53df34610ce5ded5ad83fa05d"
+ name = "github.com/multiformats/go-multiaddr"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "ce21123d5172669bbf37a166078bc5f9d345ec2f"
+ version = "v0.0.2"
+
+[[projects]]
+ digest = "1:e7b7007612b49b368d5b505b624b399a1de5fe2764271b92145aa9ca0440ab4e"
+ name = "github.com/multiformats/go-multiaddr-dns"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "e7c544d7a325c57bdbd7e9ba9c035a6701c5c7d2"
+ version = "v0.0.2"
+
+[[projects]]
+ digest = "1:ccb950e76138c70abe765c3b9c0e6cad0e55fc66ff53318cea8b651df9f892c7"
+ name = "github.com/multiformats/go-multiaddr-net"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "bd61b0499a3cfc893a8eb109c5669342b1671881"
+ version = "v0.0.1"
+
+[[projects]]
+ digest = "1:8f2a32f6d211bf2685d5c47ace5d6b59bd4359f69e92b632793d066129a65c4e"
+ name = "github.com/multiformats/go-multibase"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "d63641945dc1749baa23686ad0564ad63fef0493"
+ version = "v0.0.1"
+
+[[projects]]
+ digest = "1:b113be7291061893f53217f1b34f044f5a8ebd1d296fb6774b307f305a2ef9ed"
+ name = "github.com/multiformats/go-multicodec"
+ packages = [
+ ".",
+ "base",
+ "base/b64",
+ "base/bin",
+ "base/hex",
+ "base/mux",
+ "cbor",
+ "json",
+ "mux",
+ ]
+ pruneopts = "UT"
+ revision = "b67bc51f663437753e2028cc4b5fea6192479956"
+ version = "v0.1.6"
+
+[[projects]]
+ digest = "1:f22991b1c70f4f93dbd16bf16f59f9b7f4b7fefbc1d6b6818d4aae1cb60f05af"
+ name = "github.com/multiformats/go-multihash"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "922cbd7915f407488e3f4413ada76400a1b29b49"
+ version = "v0.0.3"
+
+[[projects]]
+ digest = "1:894daf10008cdef37454571b584832b2a281a5709f6b80d7bd440ff3a627c962"
+ name = "github.com/multiformats/go-multistream"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "f3f44044ac2444cd3a017c0b269f8da65b0012f1"
+ version = "v0.0.1"
+
+[[projects]]
+ digest = "1:42e29deef12327a69123b9cb2cb45fee4af5c12c2a23c6e477338279a052703f"
+ name = "github.com/onsi/ginkgo"
+ packages = [
+ ".",
+ "config",
+ "internal/codelocation",
+ "internal/containernode",
+ "internal/failer",
+ "internal/leafnodes",
+ "internal/remote",
+ "internal/spec",
+ "internal/spec_iterator",
+ "internal/specrunner",
+ "internal/suite",
+ "internal/testingtproxy",
+ "internal/writer",
+ "reporters",
+ "reporters/stenographer",
+ "reporters/stenographer/support/go-colorable",
+ "reporters/stenographer/support/go-isatty",
+ "types",
+ ]
+ pruneopts = "UT"
+ revision = "3774a09d95489ccaa16032e0770d08ea77ba6184"
+ version = "v1.6.0"
+
+[[projects]]
+ digest = "1:7167172a2391eaf512e8be8869b9295187c3f0d2576a11f09bca807a21374e56"
+ name = "github.com/onsi/gomega"
+ packages = [
+ ".",
+ "format",
+ "ghttp",
+ "internal/assertion",
+ "internal/asyncassertion",
+ "internal/oraclematcher",
+ "internal/testingtsupport",
+ "matchers",
+ "matchers/support/goraph/bipartitegraph",
+ "matchers/support/goraph/edge",
+ "matchers/support/goraph/node",
+ "matchers/support/goraph/util",
+ "types",
+ ]
+ pruneopts = "UT"
+ revision = "7615b9433f86a8bdf29709bf288bc4fd0636a369"
+ version = "v1.4.2"
+
+[[projects]]
+ digest = "1:11e62d6050198055e6cd87ed57e5d8c669e84f839c16e16f192374d913d1a70d"
+ name = "github.com/opentracing/opentracing-go"
+ packages = [
+ ".",
+ "ext",
+ "log",
+ ]
+ pruneopts = "UT"
+ revision = "659c90643e714681897ec2521c60567dd21da733"
+ version = "v1.1.0"
+
+[[projects]]
+ digest = "1:e5d0bd87abc2781d14e274807a470acd180f0499f8bf5bb18606e9ec22ad9de9"
+ name = "github.com/pborman/uuid"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "adf5a7427709b9deb95d29d3fa8a2bf9cfd388f1"
+ version = "v1.2"
+
+[[projects]]
+ digest = "1:95741de3af260a92cc5c7f3f3061e85273f5a81b5db20d4bd68da74bd521675e"
+ name = "github.com/pelletier/go-toml"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "c01d1270ff3e442a8a57cddc1c92dc1138598194"
+ version = "v1.2.0"
+
+[[projects]]
+ digest = "1:cf31692c14422fa27c83a05292eb5cbe0fb2775972e8f1f8446a71549bd8980b"
+ name = "github.com/pkg/errors"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "ba968bfe8b2f7e042a574c888954fccecfa385b4"
+ version = "v0.8.1"
+
+[[projects]]
+ branch = "master"
+ digest = "1:13e3ecd0eb9145fd62bebcc8fb8334b20408f31da7be3cacb68b5abcd09a1f42"
+ name = "github.com/polydawn/refmt"
+ packages = [
+ ".",
+ "cbor",
+ "json",
+ "obj",
+ "obj/atlas",
+ "pretty",
+ "shared",
+ "tok",
+ ]
+ pruneopts = "UT"
+ revision = "01bf1e26dd14f9b71f26b7005a2b1ef514d5f9a4"
+
+[[projects]]
+ digest = "1:1b8344715571e257101066e65d0bc8172715ecf09c8bd09b56763ec6389395e4"
+ name = "github.com/prometheus/tsdb"
+ packages = ["fileutil"]
+ pruneopts = "UT"
+ revision = "4b3a5ac5d36e5262d2656c8d149e137c2d1fab12"
+ version = "v0.7.0"
+
+[[projects]]
+ digest = "1:8f4b365e527c00e2ba6b25a4c41ee7b84078c375fba83c971e54d2f0582df279"
+ name = "github.com/rjeczalik/notify"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "0f065fa99b48b842c3fd3e2c8b194c6f2b69f6b8"
+ version = "v0.9.1"
+
+[[projects]]
+ digest = "1:0b8dd7447e420afff0260179dc892711e837edd1d446bc78dab924624a3c3c81"
+ name = "github.com/rs/cors"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "3fb1b69b103a84de38a19c3c6ec073dd6caa4d3f"
+ version = "v1.5.0"
+
+[[projects]]
+ digest = "1:69b1cc331fca23d702bd72f860c6a647afd0aa9fcbc1d0659b1365e26546dd70"
+ name = "github.com/sirupsen/logrus"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "bcd833dfe83d3cebad139e4a29ed79cb2318bf95"
+ version = "v1.2.0"
+
+[[projects]]
+ digest = "1:919bb3aa6d9d0b67648c219fa4925312bc3c2872da19e818fa769e9c97a2b643"
+ name = "github.com/spaolacci/murmur3"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "9f5d223c60793748f04a9d5b4b4eacddfc1f755d"
+ version = "v1.1"
+
+[[projects]]
+ digest = "1:6a4a11ba764a56d2758899ec6f3848d24698d48442ebce85ee7a3f63284526cd"
+ name = "github.com/spf13/afero"
+ packages = [
+ ".",
+ "mem",
+ ]
+ pruneopts = "UT"
+ revision = "d40851caa0d747393da1ffb28f7f9d8b4eeffebd"
+ version = "v1.1.2"
+
+[[projects]]
+ digest = "1:516e71bed754268937f57d4ecb190e01958452336fa73dbac880894164e91c1f"
+ name = "github.com/spf13/cast"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "8965335b8c7107321228e3e3702cab9832751bac"
+ version = "v1.2.0"
+
+[[projects]]
+ digest = "1:645cabccbb4fa8aab25a956cbcbdf6a6845ca736b2c64e197ca7cbb9d210b939"
+ name = "github.com/spf13/cobra"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "ef82de70bb3f60c65fb8eebacbb2d122ef517385"
+ version = "v0.0.3"
+
+[[projects]]
+ digest = "1:68ea4e23713989dc20b1bded5d9da2c5f9be14ff9885beef481848edd18c26cb"
+ name = "github.com/spf13/jwalterweatherman"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "4a4406e478ca629068e7768fc33f3f044173c0a6"
+ version = "v1.0.0"
+
+[[projects]]
+ digest = "1:dab83a1bbc7ad3d7a6ba1a1cc1760f25ac38cdf7d96a5cdd55cd915a4f5ceaf9"
+ name = "github.com/spf13/pflag"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "9a97c102cda95a86cec2345a6f09f55a939babf5"
+ version = "v1.0.2"
+
+[[projects]]
+ digest = "1:6e30a27eac59a148b3f7a32e0ba54706b31dcde5a42f63b22cb47873b62fa343"
+ name = "github.com/spf13/viper"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "8fb642006536c8d3760c99d4fa2389f5e2205631"
+ version = "v1.2.0"
+
+[[projects]]
+ branch = "develop"
+ digest = "1:6deccaba5762377091f2e5b26dba70e630e01edb3f95d1a6a59d9b098bd4358f"
+ name = "github.com/status-im/keycard-go"
+ packages = ["derivationpath"]
+ pruneopts = "UT"
+ revision = "8adf2b6627095127f26f77af865c056bb510097a"
+
+[[projects]]
+ branch = "master"
+ digest = "1:f2ffd421680b0a3f7887501b3c6974bcf19217ecd301d0e2c9b681940ec363d5"
+ name = "github.com/syndtr/goleveldb"
+ packages = [
+ "leveldb",
+ "leveldb/cache",
+ "leveldb/comparer",
+ "leveldb/errors",
+ "leveldb/filter",
+ "leveldb/iterator",
+ "leveldb/journal",
+ "leveldb/memdb",
+ "leveldb/opt",
+ "leveldb/storage",
+ "leveldb/table",
+ "leveldb/util"
+ ]
+ pruneopts = "UT"
+ revision = "ae2bd5eed72d46b28834ec3f60db3a3ebedd8dbd"
+
+[[projects]]
+ digest = "1:73e0d2644cf33beeafbfb79804143ac9738bed3c28a12fd5e61bd3b13ac95407"
+ name = "github.com/tyler-smith/go-bip39"
+ packages = [
+ ".",
+ "wordlists",
+ ]
+ pruneopts = "UT"
+ revision = "2af0a847066a4f2669040ccd44a79c8eca10806a"
+ version = "v1.0.0"
+
+[[projects]]
+ branch = "pair_with_syncAndPublish"
+ digest = "1:e39d772cfeed31912992a554049bf82b376e5d49f49b5cf2844eb211f3ca1081"
+ name = "github.com/vulcanize/eth-block-extractor"
+ packages = [
+ "pkg/ipfs",
+ "pkg/ipfs/eth_block_header",
+ "pkg/ipfs/eth_block_receipts",
+ "pkg/ipfs/eth_block_transactions",
+ "pkg/ipfs/eth_state_trie",
+ "pkg/ipfs/eth_storage_trie",
+ "pkg/ipfs/util",
+ "pkg/wrappers/rlp",
+ ]
+ pruneopts = "UT"
+ revision = "b24f61a2b476a6ca31d1b182ca6c4838534b96ab"
+
+[[projects]]
+ branch = "master"
+ digest = "1:98fa13beefbf581ec173561adad6374c460631593b4bdcf03adc29cd18e5d2f5"
+ name = "github.com/whyrusleeping/base32"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "c30ac30633ccdabefe87eb12465113f06f1bab75"
+
+[[projects]]
+ branch = "master"
+ digest = "1:ee2495c639b3b0f9736db90775b8978b6d2495566b65fb8439d7b0665a749e16"
+ name = "github.com/whyrusleeping/cbor"
+ packages = ["go"]
+ pruneopts = "UT"
+ revision = "63513f603b11583741970c5045ea567130ddb492"
+
+[[projects]]
+ branch = "master"
+ digest = "1:3ca7e47848bbb8fc6c17b86c9887117e2e83dd5d68f7c4daf8c8fd30471ea597"
+ name = "github.com/whyrusleeping/chunker"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "fe64bd25879f446bb7e8a4adf5d4a68552211bd3"
+
+[[projects]]
+ branch = "master"
+ digest = "1:b33eed6794f2b2d1a7d0b45cb705402f26af0f0ad6521667e144ffa71f52d9d9"
+ name = "github.com/whyrusleeping/go-keyspace"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "5b898ac5add1da7178a4a98e69cb7b9205c085ee"
+
+[[projects]]
+ branch = "master"
+ digest = "1:0102dfa2f98777db8ff68c920bef1be3ff8504e90485b6cdd24d61b981b487b6"
+ name = "github.com/whyrusleeping/go-logging"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "0457bb6b88fc1973573aaf6b5145d8d3ae972390"
+
+[[projects]]
+ branch = "master"
+ digest = "1:94796f9decedb46b17985693cbe996ce3642a991f0efcf7bf9a6c5197da3eefc"
+ name = "github.com/whyrusleeping/go-notifier"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "097c5d47330ff6a823f67e3515faa13566a62c6f"
+
+[[projects]]
+ digest = "1:1c5b129f012e176d9cbcb173c67fef17698a2d0a8169e94c8db9e7beeb3ef716"
+ name = "github.com/whyrusleeping/go-smux-multiplex"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "2b855d4f3a3051b0133f7783bffe06e4b7833d1e"
+ version = "v3.0.16"
+
+[[projects]]
+ digest = "1:262e85ef9e2082fcb44335f6349699d61d5ac3672d24dcf3bf4cbc7377b51e96"
+ name = "github.com/whyrusleeping/go-smux-multistream"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "e799b10bc6eea2cc5ce18f7b7b4d8e1a0439476d"
+ version = "v2.0.2"
+
+[[projects]]
+ digest = "1:f1026ff0b15a5282885d6709582eba8d2faf261ffff4bac6960a8e97a4f6dfd5"
+ name = "github.com/whyrusleeping/go-smux-yamux"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "902adacdc02ba8fca64a0d0985576a1dc3138ee5"
+ version = "v2.0.9"
+
+[[projects]]
+ digest = "1:6c96967502c55c555abfe560f561a124951345e713a8e87cc6e2c214976e6e75"
+ name = "github.com/whyrusleeping/mafmt"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "7aa7fad2ede4e7157818e3e7af5061f866a9ae23"
+ version = "v1.2.8"
+
+[[projects]]
+ branch = "master"
+ digest = "1:0a017705731cb8ad506e72d842840ba89809e5b27b5593954c7eeeb631823735"
+ name = "github.com/whyrusleeping/mdns"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "ef14215e6b30606f4ce84174ed7a644a05cb1af3"
+
+[[projects]]
+ branch = "master"
+ digest = "1:94b933c1b26f1da25d25a089937d15987170a0a54109aa521a111345c3e84581"
+ name = "github.com/whyrusleeping/multiaddr-filter"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "e903e4adabd70b78bc9293b6ee4f359afb3f9f59"
+
+[[projects]]
+ branch = "master"
+ digest = "1:1ccd9d66ae1abe6b3b28d8b68e09387533fee345d8bbaa753af2fa16e0505807"
+ name = "github.com/whyrusleeping/timecache"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "cfcb2f1abfee846c430233aef0b630a946e0a5a6"
+
+[[projects]]
+ digest = "1:1f186490a9ec1359604f041997996fb0caa98878bd53cdf0b89b6b6ec6803af9"
+ name = "github.com/whyrusleeping/yamux"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "5364a42fe4b5efa5967c11c8f9b0f049cac0c4a9"
+ version = "v1.1.5"
+
+[[projects]]
+ branch = "master"
+ digest = "1:7dca0da64f5937af74f21618cdb812c8f16a7d042316dd5bf2f1dfd086be3fc6"
+ name = "github.com/wsddn/go-ecdh"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "48726bab92085232373de4ec5c51ce7b441c63a0"
+
+[[projects]]
+ digest = "1:e99f8ec6e9c0ad99ad6615409ce6588c77df8645ad4a5d9fc559fec95d7cae49"
+ name = "go.opencensus.io"
+ packages = [
+ "internal/tagencoding",
+ "metric/metricdata",
+ "metric/metricproducer",
+ "resource",
+ "stats",
+ "stats/internal",
+ "stats/view",
+ "tag",
+ ]
+ pruneopts = "UT"
+ revision = "df6e2001952312404b06f5f6f03fcb4aec1648e5"
+ version = "v0.21.0"
+
+[[projects]]
+ branch = "master"
+ digest = "1:52796c672f9529f506ac63c10bf44072c8156cb2c85c0784a8b8ccb164e94903"
+ name = "go4.org"
+ packages = ["lock"]
+ pruneopts = "UT"
+ revision = "94abd6928b1da39b1d757b60c93fb2419c409fa1"
+
+[[projects]]
+ branch = "master"
+ digest = "1:0e122041f471cc1b3c15edcf68e96752faeb67c9b92e9365341ca8195cc6fb51"
+ name = "golang.org/x/crypto"
+ packages = [
+ "blake2s",
+ "blowfish",
+ "chacha20poly1305",
+ "cryptobyte",
+ "cryptobyte/asn1",
+ "curve25519",
+ "ed25519",
+ "ed25519/internal/edwards25519",
+ "hkdf",
+ "internal/chacha20",
+ "internal/subtle",
+ "pbkdf2",
+ "poly1305",
+ "ripemd160",
+ "salsa20",
+ "salsa20/salsa",
+ "scrypt",
+ "sha3",
+ "ssh/terminal"
+ ]
+ pruneopts = "UT"
+ revision = "ff983b9c42bc9fbf91556e191cc8efb585c16908"
+
+[[projects]]
+ branch = "master"
+ digest = "1:e3fb02bc270f8fc06628d2a1dc6811d3753ccaef05ad060c9f6e7c2340ca0e1f"
+ name = "golang.org/x/net"
+ packages = [
+ "bpf",
+ "context",
+ "html",
+ "html/atom",
+ "html/charset",
+ "websocket"
+ ]
+ "internal/iana",
+ "internal/socket",
+ "ipv4",
+ "ipv6",
+ "websocket",
+ ]
+ pruneopts = "UT"
+ revision = "26e67e76b6c3f6ce91f7c52def5af501b4e0f3a2"
+
+[[projects]]
+ branch = "master"
+ digest = "1:39ebcc2b11457b703ae9ee2e8cca0f68df21969c6102cb3b705f76cca0ea0239"
+ name = "golang.org/x/sync"
+ packages = ["errgroup"]
+ pruneopts = "UT"
+ revision = "1d60e4601c6fd243af51cc01ddf169918a5407ca"
+
+[[projects]]
+ branch = "master"
+ digest = "1:45c0985630ebeafc0dba3e5fad8ae79ac344250a0d3517da4abcf7bc25a162b6"
+ name = "golang.org/x/sys"
+ packages = [
+ "cpu",
+ "unix",
+ "windows"
+ ]
+ pruneopts = "UT"
+ revision = "953cdadca894cdc07be76fc99f95b40c28f06623"
+
+[[projects]]
+ digest = "1:4392fcf42d5cf0e3ff78c96b2acf8223d49e4fdc53eb77c99d2f8dfe4680e006"
+ name = "golang.org/x/text"
+ packages = [
+ "encoding",
+ "encoding/charmap",
+ "encoding/htmlindex",
+ "encoding/internal",
+ "encoding/internal/identifier",
+ "encoding/japanese",
+ "encoding/korean",
+ "encoding/simplifiedchinese",
+ "encoding/traditionalchinese",
+ "encoding/unicode",
+ "internal/gen",
+ "internal/tag",
+ "internal/triegen",
+ "internal/ucd",
+ "internal/utf8internal",
+ "language",
+ "runes",
+ "transform",
+ "unicode/cldr",
+ "unicode/norm"
+ ]
+ pruneopts = "UT"
+ revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0"
+ version = "v0.3.0"
+
+[[projects]]
+ branch = "master"
+ digest = "1:d9d3a231c70b17470fc134900032da48d5c146f0f4a2ce12ceb92704dae8d67d"
+ name = "golang.org/x/xerrors"
+ packages = [
+ ".",
+ "internal",
+ ]
+ pruneopts = "UT"
+ revision = "1f06c39b43733b74392b1972507822714ced3242"
+
+[[projects]]
+ digest = "1:abeb38ade3f32a92943e5be54f55ed6d6e3b6602761d74b4aab4c9dd45c18abd"
+ name = "gopkg.in/fsnotify.v1"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "c2828203cd70a50dcccfb2761f8b1f8ceef9a8e9"
+ source = "gopkg.in/fsnotify/fsnotify.v1"
+ version = "v1.4.7"
+
+[[projects]]
+ branch = "v2"
+ digest = "1:3d3f9391ab615be8655ae0d686a1564f3fec413979bb1aaf018bac1ec1bb1cc7"
+ name = "gopkg.in/natefinch/npipe.v2"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "c1b8fa8bdccecb0b8db834ee0b92fdbcfa606dd6"
+
+[[projects]]
+ branch = "v1"
+ digest = "1:0caa92e17bc0b65a98c63e5bc76a9e844cd5e56493f8fdbb28fad101a16254d9"
+ name = "gopkg.in/tomb.v1"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "dd632973f1e7218eb1089048e0798ec9ae7dceb8"
+
+[[projects]]
+ digest = "1:b24d38b282bacf9791408a080f606370efa3d364e4b5fd9ba0f7b87786d3b679"
+ name = "gopkg.in/urfave/cli.v1"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "cfb38830724cc34fedffe9a2a29fb54fa9169cd1"
+ version = "v1.20.0"
+
+[[projects]]
+ digest = "1:342378ac4dcb378a5448dd723f0784ae519383532f5e70ade24132c4c8693202"
+ name = "gopkg.in/yaml.v2"
+ packages = ["."]
+ pruneopts = "UT"
+ revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183"
+ version = "v2.2.1"
+
+[solve-meta]
+ analyzer-name = "dep"
+ analyzer-version = 1
+ inputs-digest = "d41c963e87b06f7edd9135e30472894a114d0d8298454e6b2dae7ff25ac3c62a"
+ input-imports = [
+ "github.com/dave/jennifer/jen",
+ "github.com/ethereum/go-ethereum",
+ "github.com/ethereum/go-ethereum/accounts/abi",
+ "github.com/ethereum/go-ethereum/accounts/abi/bind",
+ "github.com/ethereum/go-ethereum/common",
+ "github.com/ethereum/go-ethereum/common/hexutil",
+ "github.com/ethereum/go-ethereum/core/rawdb",
+ "github.com/ethereum/go-ethereum/core/types",
+ "github.com/ethereum/go-ethereum/crypto",
+ "github.com/ethereum/go-ethereum/ethclient",
+ "github.com/ethereum/go-ethereum/ethdb",
+ "github.com/ethereum/go-ethereum/p2p",
+ "github.com/ethereum/go-ethereum/p2p/discv5",
+ "github.com/ethereum/go-ethereum/rlp",
+ "github.com/ethereum/go-ethereum/rpc",
+ "github.com/ethereum/go-ethereum/statediff",
+ "github.com/hashicorp/golang-lru",
+ "github.com/hpcloud/tail",
+ "github.com/jmoiron/sqlx",
+ "github.com/lib/pq",
+ "github.com/mitchellh/go-homedir",
+ "github.com/onsi/ginkgo",
+ "github.com/onsi/gomega",
+ "github.com/onsi/gomega/ghttp",
+ "github.com/sirupsen/logrus",
+ "github.com/spf13/cobra",
+ "github.com/spf13/viper",
+ "github.com/vulcanize/eth-block-extractor/pkg/ipfs",
+ "github.com/vulcanize/eth-block-extractor/pkg/ipfs/eth_block_header",
+ "github.com/vulcanize/eth-block-extractor/pkg/ipfs/eth_block_receipts",
+ "github.com/vulcanize/eth-block-extractor/pkg/ipfs/eth_block_transactions",
+ "github.com/vulcanize/eth-block-extractor/pkg/ipfs/eth_state_trie",
+ "github.com/vulcanize/eth-block-extractor/pkg/ipfs/eth_storage_trie",
+ "github.com/vulcanize/eth-block-extractor/pkg/wrappers/rlp",
+ "golang.org/x/net/context",
+ "golang.org/x/sync/errgroup",
+ "gopkg.in/tomb.v1",
+ ]
+ solver-name = "gps-cdcl"
+ solver-version = 1
diff --git a/Gopkg.toml b/Gopkg.toml
new file mode 100644
index 00000000..5c9bb894
--- /dev/null
+++ b/Gopkg.toml
@@ -0,0 +1,67 @@
+
+# Gopkg.toml example
+#
+# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
+# for detailed Gopkg.toml documentation.
+#
+# required = ["github.com/user/thing/cmd/thing"]
+# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
+#
+# [[constraint]]
+# name = "github.com/user/project"
+# version = "1.0.0"
+#
+# [[constraint]]
+# name = "github.com/user/project2"
+# branch = "dev"
+# source = "github.com/myfork/project2"
+#
+# [[override]]
+# name = "github.com/x/y"
+# version = "2.4.0"
+
+
+[[override]]
+ name = "gopkg.in/fsnotify.v1"
+ source = "gopkg.in/fsnotify/fsnotify.v1"
+
+[[override]]
+ name = "github.com/pressly/sup"
+ version = "0.5.3"
+
+[[constraint]]
+ name = "github.com/onsi/ginkgo"
+ version = "1.4.0"
+
+[[constraint]]
+ branch = "master"
+ name = "github.com/jmoiron/sqlx"
+
+[[constraint]]
+ branch = "master"
+ name = "github.com/lib/pq"
+
+[[constraint]]
+ name = "github.com/sirupsen/logrus"
+ version = "1.2.0"
+
+[[constraint]]
+ name = "github.com/spf13/cobra"
+ version = "0.0.1"
+
+[[constraint]]
+ name = "github.com/ethereum/go-ethereum"
+ source = "github.com/vulcanize/go-ethereum"
+ branch = "rpc_statediffs_at_head"
+
+[[constraint]]
+ name = "github.com/vulcanize/eth-block-extractor"
+ branch = "pair_with_syncAndPublish"
+
+[[override]]
+ name = "github.com/ipfs/go-ipfs"
+ version = "0.4.20"
+
+[prune]
+ go-tests = true
+ unused-packages = true
diff --git a/cmd/syncAndPublish.go b/cmd/syncAndPublish.go
index 2ea0479a..365fe79b 100644
--- a/cmd/syncAndPublish.go
+++ b/cmd/syncAndPublish.go
@@ -24,13 +24,13 @@ import (
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/rpc"
+ "github.com/vulcanize/vulcanizedb/pkg/core"
"github.com/vulcanize/vulcanizedb/pkg/geth"
"github.com/vulcanize/vulcanizedb/pkg/geth/client"
vRpc "github.com/vulcanize/vulcanizedb/pkg/geth/converters/rpc"
"github.com/vulcanize/vulcanizedb/pkg/geth/node"
"github.com/vulcanize/vulcanizedb/pkg/ipfs"
"github.com/vulcanize/vulcanizedb/utils"
- "github.com/vulcanize/vulcanizedb/pkg/core"
)
// syncAndPublishCmd represents the syncAndPublish command
@@ -65,7 +65,7 @@ func syncAndPublish() {
log.Fatal(err)
}
- wg := syn.WaitGroup{}
+ wg := &syn.WaitGroup{}
err = indexer.Index(wg)
if err != nil {
log.Fatal(err)
@@ -86,4 +86,4 @@ func getBlockChainAndClients() (*geth.BlockChain, core.EthClient, core.RpcClient
transactionConverter := vRpc.NewRpcTransactionConverter(ethClient)
blockChain := geth.NewBlockChain(vdbEthClient, rpcClient, vdbNode, transactionConverter)
return blockChain, ethClient, rpcClient
-}
\ No newline at end of file
+}
diff --git a/pkg/eth/client/rpc_client.go b/pkg/eth/client/rpc_client.go
index fac16ccb..3c8dafa6 100644
--- a/pkg/eth/client/rpc_client.go
+++ b/pkg/eth/client/rpc_client.go
@@ -17,7 +17,6 @@
package client
import (
- "errors"
"context"
"errors"
"reflect"
diff --git a/pkg/fakes/mock_rpc_client.go b/pkg/fakes/mock_rpc_client.go
index 33e453b8..190309ea 100644
--- a/pkg/fakes/mock_rpc_client.go
+++ b/pkg/fakes/mock_rpc_client.go
@@ -187,3 +187,7 @@ func (client *MockRPCClient) AssertBatchCalledWith(method string, lengthOfBatch
}
Expect(client.passedMethod).To(Equal(method))
}
+
+func (client *MockRpcClient) Subscribe(namespace string, payloadChan interface{}, args ...interface{}) (*rpc.ClientSubscription, error) {
+ panic("implement me")
+}
diff --git a/pkg/ipfs/converter.go b/pkg/ipfs/converter.go
new file mode 100644
index 00000000..15116516
--- /dev/null
+++ b/pkg/ipfs/converter.go
@@ -0,0 +1,114 @@
+// VulcanizeDB
+// Copyright © 2019 Vulcanize
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+package ipfs
+
+import (
+ "context"
+ "math/big"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/rlp"
+ "github.com/ethereum/go-ethereum/statediff"
+
+ "github.com/vulcanize/vulcanizedb/pkg/core"
+)
+
+// Converter interface is used to convert a geth statediff.Payload to our IPLDPayload type
+type Converter interface {
+ Convert(payload statediff.Payload) (*IPLDPayload, error)
+}
+
+// PayloadConverter is the underlying struct for the Converter interface
+type PayloadConverter struct {
+ client core.EthClient
+}
+
+// IPLDPayload is a custom type which packages ETH data for the IPFS publisher
+type IPLDPayload struct {
+ HeaderRLP []byte
+ BlockNumber *big.Int
+ BlockHash common.Hash
+ BlockBody *types.Body
+ Receipts types.Receipts
+ StateLeafs map[common.Hash][]byte
+ StorageLeafs map[common.Hash]map[common.Hash][]byte
+}
+
+// NewPayloadConverter creates a pointer to a new PayloadConverter which satisfies the Converter interface
+func NewPayloadConverter(client core.EthClient) *PayloadConverter {
+ return &PayloadConverter{
+ client: client,
+ }
+}
+
+// Convert method is used to convert a geth statediff.Payload to a IPLDPayload
+func (pc *PayloadConverter) Convert(payload statediff.Payload) (*IPLDPayload, error) {
+ // Unpack block rlp to access fields
+ block := new(types.Block)
+ err := rlp.DecodeBytes(payload.BlockRlp, block)
+ header := block.Header()
+ headerRlp, err := rlp.EncodeToBytes(header)
+ if err != nil {
+ return nil, err
+ }
+ convertedPayload := &IPLDPayload{
+ BlockHash: block.Hash(),
+ BlockNumber: block.Number(),
+ HeaderRLP: headerRlp,
+ BlockBody: block.Body(),
+ Receipts: make(types.Receipts, 0),
+ StateLeafs: make(map[common.Hash][]byte),
+ StorageLeafs: make(map[common.Hash]map[common.Hash][]byte),
+ }
+ for _, trx := range block.Transactions() {
+ gethReceipt, err := pc.client.TransactionReceipt(context.Background(), trx.Hash())
+ if err != nil {
+ return nil, err
+ }
+ convertedPayload.Receipts = append(convertedPayload.Receipts, gethReceipt)
+ }
+
+ // Unpack state diff rlp to access fields
+ stateDiff := new(statediff.StateDiff)
+ err = rlp.DecodeBytes(payload.StateDiffRlp, stateDiff)
+ if err != nil {
+ return nil, err
+ }
+ for addr, createdAccount := range stateDiff.CreatedAccounts {
+ convertedPayload.StateLeafs[addr] = createdAccount.Value
+ convertedPayload.StorageLeafs[addr] = make(map[common.Hash][]byte)
+ for _, storageDiff := range createdAccount.Storage {
+ convertedPayload.StorageLeafs[addr][common.BytesToHash(storageDiff.Key)] = storageDiff.Value
+ }
+ }
+ for addr, deletedAccount := range stateDiff.DeletedAccounts {
+ convertedPayload.StateLeafs[addr] = deletedAccount.Value
+ convertedPayload.StorageLeafs[addr] = make(map[common.Hash][]byte)
+ for _, storageDiff := range deletedAccount.Storage {
+ convertedPayload.StorageLeafs[addr][common.BytesToHash(storageDiff.Key)] = storageDiff.Value
+ }
+ }
+ for addr, updatedAccount := range stateDiff.UpdatedAccounts {
+ convertedPayload.StateLeafs[addr] = updatedAccount.Value
+ convertedPayload.StorageLeafs[addr] = make(map[common.Hash][]byte)
+ for _, storageDiff := range updatedAccount.Storage {
+ convertedPayload.StorageLeafs[addr][common.BytesToHash(storageDiff.Key)] = storageDiff.Value
+ }
+ }
+ return convertedPayload, nil
+}
diff --git a/pkg/ipfs/converter_test.go b/pkg/ipfs/converter_test.go
new file mode 100644
index 00000000..bef22610
--- /dev/null
+++ b/pkg/ipfs/converter_test.go
@@ -0,0 +1,17 @@
+// VulcanizeDB
+// Copyright © 2019 Vulcanize
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+package ipfs_test
diff --git a/pkg/ipfs/indexer.go b/pkg/ipfs/indexer.go
index baabd213..8018ff1f 100644
--- a/pkg/ipfs/indexer.go
+++ b/pkg/ipfs/indexer.go
@@ -19,8 +19,8 @@ package ipfs
import (
"sync"
- log "github.com/sirupsen/logrus"
"github.com/ethereum/go-ethereum/statediff"
+ log "github.com/sirupsen/logrus"
"github.com/vulcanize/vulcanizedb/pkg/core"
"github.com/vulcanize/vulcanizedb/pkg/datastore/postgres"
@@ -31,16 +31,16 @@ const payloadChanBufferSize = 800 // 1/10th max eth sub buffer size
// Indexer is an interface for streaming, converting to IPLDs, publishing, and indexing all Ethereum data
// This is the top-level interface used by the syncAndPublish command
type Indexer interface {
- Index(wg sync.WaitGroup) error
+ Index(wg *sync.WaitGroup) error
}
// ipfsIndexer is the underlying struct for the Indexer interface
// we are not exporting this to enforce proper initialization through the NewIPFSIndexer function
type ipfsIndexer struct {
- Streamer Streamer
- Converter Converter
- Publisher Publisher
- Repository Repository
+ Streamer Streamer
+ Converter Converter
+ Publisher Publisher
+ Repository Repository
PayloadChan chan statediff.Payload
QuitChan chan bool
}
@@ -52,17 +52,17 @@ func NewIPFSIndexer(ipfsPath string, db *postgres.DB, ethClient core.EthClient,
return nil, err
}
return &ipfsIndexer{
- Streamer: NewStateDiffSyncer(rpcClient),
- Repository: NewCIDRepository(db),
- Converter: NewPayloadConverter(ethClient),
- Publisher: publisher,
+ Streamer: NewStateDiffSyncer(rpcClient),
+ Repository: NewCIDRepository(db),
+ Converter: NewPayloadConverter(ethClient),
+ Publisher: publisher,
PayloadChan: make(chan statediff.Payload, payloadChanBufferSize),
- QuitChan: qc,
+ QuitChan: qc,
}, nil
}
// Index is the main processing loop
-func (i *ipfsIndexer) Index(wg sync.WaitGroup) error {
+func (i *ipfsIndexer) Index(wg *sync.WaitGroup) error {
sub, err := i.Streamer.Stream(i.PayloadChan)
if err != nil {
return err
@@ -73,6 +73,10 @@ func (i *ipfsIndexer) Index(wg sync.WaitGroup) error {
for {
select {
case payload := <-i.PayloadChan:
+ if payload.Err != nil {
+ log.Error(err)
+ continue
+ }
ipldPayload, err := i.Converter.Convert(payload)
if err != nil {
log.Error(err)
diff --git a/pkg/ipfs/indexer_test.go b/pkg/ipfs/indexer_test.go
new file mode 100644
index 00000000..bef22610
--- /dev/null
+++ b/pkg/ipfs/indexer_test.go
@@ -0,0 +1,17 @@
+// VulcanizeDB
+// Copyright © 2019 Vulcanize
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+package ipfs_test
diff --git a/pkg/ipfs/payload_converter.go b/pkg/ipfs/payload_converter.go
deleted file mode 100644
index 8573cf90..00000000
--- a/pkg/ipfs/payload_converter.go
+++ /dev/null
@@ -1,115 +0,0 @@
-// VulcanizeDB
-// Copyright © 2019 Vulcanize
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Affero General Public License for more details.
-
-// You should have received a copy of the GNU Affero General Public License
-// along with this program. If not, see .
-
-package ipfs
-
-import (
- "context"
- "math/big"
-
- "github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/core/types"
- "github.com/ethereum/go-ethereum/rlp"
- "github.com/ethereum/go-ethereum/statediff"
-
- "github.com/vulcanize/vulcanizedb/pkg/core"
-)
-
-// Converter interface is used to convert a geth statediff.Payload to our IPLDPayload type
-type Converter interface {
- Convert(payload statediff.Payload) (*IPLDPayload, error)
-}
-
-// PayloadConverter is the underlying struct for the Converter interface
-type PayloadConverter struct {
- client core.EthClient
-}
-
-// IPLDPayload is a custom type which packages ETH data for the IPFS publisher
-type IPLDPayload struct {
- HeaderRLP []byte
- BlockNumber *big.Int
- BlockHash common.Hash
- BlockBody *types.Body
- Receipts types.Receipts
- StateLeafs map[common.Hash][]byte
- StorageLeafs map[common.Hash]map[common.Hash][]byte
-}
-
-// NewPayloadConverter creates a pointer to a new PayloadConverter which satisfies the Converter interface
-func NewPayloadConverter(client core.EthClient) *PayloadConverter {
- return &PayloadConverter{
- client: client,
- }
-}
-
-// Convert method is used to convert a geth statediff.Payload to a IPLDPayload
-func (pc *PayloadConverter) Convert(payload statediff.Payload) (*IPLDPayload, error) {
- // Unpack block rlp to access fields
- block := new(types.Block)
- err := rlp.DecodeBytes(payload.BlockRlp, block)
- header := block.Header()
- headerRlp, err := rlp.EncodeToBytes(header)
- if err != nil {
- return nil, err
- }
- convertedPayload := &IPLDPayload{
- BlockHash: block.Hash(),
- BlockNumber: block.Number(),
- HeaderRLP: headerRlp,
- BlockBody: block.Body(),
- Receipts: make(types.Receipts, 0),
- StateLeafs: make(map[common.Hash][]byte),
- StorageLeafs: make(map[common.Hash]map[common.Hash][]byte),
- }
- for _, trx := range block.Transactions() {
- gethReceipt, err := pc.client.TransactionReceipt(context.Background(), trx.Hash())
- if err != nil {
- return nil, err
- }
- convertedPayload.Receipts = append(convertedPayload.Receipts, gethReceipt)
- }
-
- // Unpack state diff rlp to access fields
- stateDiff := new(statediff.StateDiff)
- err = rlp.DecodeBytes(payload.StateDiffRlp, stateDiff)
- if err != nil {
- return nil, err
- }
- for addr, createdAccount := range stateDiff.CreatedAccounts {
- convertedPayload.StateLeafs[addr] = createdAccount.Value
- convertedPayload.StorageLeafs[addr] = make(map[common.Hash][]byte)
- for _, storageDiff := range createdAccount.Storage {
- convertedPayload.StorageLeafs[addr][common.BytesToHash(storageDiff.Key)] = storageDiff.Value
- }
- }
- for addr, deletedAccount := range stateDiff.DeletedAccounts {
- convertedPayload.StateLeafs[addr] = deletedAccount.Value
- convertedPayload.StorageLeafs[addr] = make(map[common.Hash][]byte)
- for _, storageDiff := range deletedAccount.Storage {
- convertedPayload.StorageLeafs[addr][common.BytesToHash(storageDiff.Key)] = storageDiff.Value
- }
- }
- for addr, updatedAccount := range stateDiff.UpdatedAccounts {
- convertedPayload.StateLeafs[addr] = updatedAccount.Value
- convertedPayload.StorageLeafs[addr] = make(map[common.Hash][]byte)
- for _, storageDiff := range updatedAccount.Storage {
- convertedPayload.StorageLeafs[addr][common.BytesToHash(storageDiff.Key)] = storageDiff.Value
- }
- }
- return convertedPayload, nil
-}
-
diff --git a/pkg/ipfs/publisher.go b/pkg/ipfs/publisher.go
index 9c137473..09b723dd 100644
--- a/pkg/ipfs/publisher.go
+++ b/pkg/ipfs/publisher.go
@@ -19,8 +19,8 @@ package ipfs
import (
"errors"
- "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core/types"
"github.com/vulcanize/eth-block-extractor/pkg/ipfs"
"github.com/vulcanize/eth-block-extractor/pkg/ipfs/eth_block_header"
@@ -38,22 +38,22 @@ type Publisher interface {
// IPLDPublisher is the underlying struct for the Publisher interface
type IPLDPublisher struct {
- Node *ipfs.IPFS
- HeaderPutter *eth_block_header.BlockHeaderDagPutter
+ Node *ipfs.IPFS
+ HeaderPutter *eth_block_header.BlockHeaderDagPutter
TransactionPutter *eth_block_transactions.BlockTransactionsDagPutter
- ReceiptPutter *eth_block_receipts.EthBlockReceiptDagPutter
- StatePutter *eth_state_trie.StateTrieDagPutter
- StoragePutter *eth_storage_trie.StorageTrieDagPutter
+ ReceiptPutter *eth_block_receipts.EthBlockReceiptDagPutter
+ StatePutter *eth_state_trie.StateTrieDagPutter
+ StoragePutter *eth_storage_trie.StorageTrieDagPutter
}
// CID payload is a struct to hold all the CIDs and their meta data
type CIDPayload struct {
- BlockNumber string
- BlockHash string
- HeaderCID string
+ BlockNumber string
+ BlockHash string
+ HeaderCID string
TransactionCIDs map[common.Hash]string
- ReceiptCIDs map[common.Hash]string
- StateLeafCIDs map[common.Hash]string
+ ReceiptCIDs map[common.Hash]string
+ StateLeafCIDs map[common.Hash]string
StorageLeafCIDs map[common.Hash]map[common.Hash]string
}
@@ -65,12 +65,12 @@ func NewIPLDPublisher(ipfsPath string) (*IPLDPublisher, error) {
}
decoder := rlp.RlpDecoder{}
return &IPLDPublisher{
- Node: node,
- HeaderPutter: eth_block_header.NewBlockHeaderDagPutter(node, decoder),
+ Node: node,
+ HeaderPutter: eth_block_header.NewBlockHeaderDagPutter(node, decoder),
TransactionPutter: eth_block_transactions.NewBlockTransactionsDagPutter(node),
- ReceiptPutter: eth_block_receipts.NewEthBlockReceiptDagPutter(node),
- StatePutter: eth_state_trie.NewStateTrieDagPutter(node),
- StoragePutter: eth_storage_trie.NewStorageTrieDagPutter(node),
+ ReceiptPutter: eth_block_receipts.NewEthBlockReceiptDagPutter(node),
+ StatePutter: eth_state_trie.NewStateTrieDagPutter(node),
+ StoragePutter: eth_storage_trie.NewStorageTrieDagPutter(node),
}, nil
}
@@ -108,12 +108,12 @@ func (pub *IPLDPublisher) Publish(payload *IPLDPayload) (*CIDPayload, error) {
// Package CIDs into a single struct
return &CIDPayload{
- BlockHash: payload.BlockHash.Hex(),
- BlockNumber: payload.BlockNumber.String(),
- HeaderCID: headerCid,
+ BlockHash: payload.BlockHash.Hex(),
+ BlockNumber: payload.BlockNumber.String(),
+ HeaderCID: headerCid,
TransactionCIDs: transactionCids,
- ReceiptCIDs: receiptsCids,
- StateLeafCIDs: stateLeafCids,
+ ReceiptCIDs: receiptsCids,
+ StateLeafCIDs: stateLeafCids,
StorageLeafCIDs: storageLeafCids,
}, nil
}
@@ -190,4 +190,4 @@ func (pub *IPLDPublisher) publishStorageLeafs(storageLeafs map[common.Hash]map[c
}
}
return storageLeafCids, nil
-}
\ No newline at end of file
+}
diff --git a/pkg/ipfs/publisher_test.go b/pkg/ipfs/publisher_test.go
new file mode 100644
index 00000000..bef22610
--- /dev/null
+++ b/pkg/ipfs/publisher_test.go
@@ -0,0 +1,17 @@
+// VulcanizeDB
+// Copyright © 2019 Vulcanize
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+package ipfs_test
diff --git a/pkg/ipfs/repository.go b/pkg/ipfs/repository.go
index a52aa9af..32458b1e 100644
--- a/pkg/ipfs/repository.go
+++ b/pkg/ipfs/repository.go
@@ -60,13 +60,12 @@ func (repo *CIDRepository) Index(cidPayload *CIDPayload) error {
return tx.Commit()
}
-
func (repo *CIDRepository) indexHeaderCID(tx *sqlx.Tx, cid, blockNumber, hash string) (int64, error) {
var headerID int64
err := tx.QueryRowx(`INSERT INTO public.header_cids (block_number, block_hash, cid) VALUES ($1, $2, $3)
ON CONFLICT DO UPDATE SET cid = $3
RETURNING id`,
- blockNumber, hash, cid).Scan(&headerID)
+ blockNumber, hash, cid).Scan(&headerID)
return headerID, err
}
@@ -76,7 +75,7 @@ func (repo *CIDRepository) indexTransactionAndReceiptCIDs(tx *sqlx.Tx, payload *
err := tx.QueryRowx(`INSERT INTO public.transaction_cids (header_id, tx_hash, cid) VALUES ($1, $2, $3)
ON CONFLICT DO UPDATE SET cid = $3
RETURNING id`,
- headerID, hash.Hex(), trxCid).Scan(&txID)
+ headerID, hash.Hex(), trxCid).Scan(&txID)
if err != nil {
return err
}
@@ -103,7 +102,7 @@ func (repo *CIDRepository) indexStateAndStorageCIDs(tx *sqlx.Tx, payload *CIDPay
err := tx.QueryRowx(`INSERT INTO public.state_cids (header_id, account_key, cid) VALUES ($1, $2, $3)
ON CONFLICT DO UPDATE SET cid = $3
RETURNING id`,
- headerID, accountKey.Hex(), stateCID).Scan(&stateID)
+ headerID, accountKey.Hex(), stateCID).Scan(&stateID)
if err != nil {
return err
}
@@ -121,4 +120,4 @@ func (repo *CIDRepository) indexStorageCID(tx *sqlx.Tx, key, cid string, stateId
_, err := repo.db.Exec(`INSERT INTO public.storage_cids (state_id, storage_key, cid) VALUES ($1, $2, $3)
ON CONFLICT DO UPDATE SET cid = $3`, stateId, key, cid)
return err
-}
\ No newline at end of file
+}
diff --git a/pkg/ipfs/repository_test.go b/pkg/ipfs/repository_test.go
new file mode 100644
index 00000000..bef22610
--- /dev/null
+++ b/pkg/ipfs/repository_test.go
@@ -0,0 +1,17 @@
+// VulcanizeDB
+// Copyright © 2019 Vulcanize
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+package ipfs_test
diff --git a/pkg/ipfs/streamer.go b/pkg/ipfs/streamer.go
index 02b67305..67ec8b0b 100644
--- a/pkg/ipfs/streamer.go
+++ b/pkg/ipfs/streamer.go
@@ -44,4 +44,4 @@ func NewStateDiffSyncer(client core.RpcClient) *StateDiffStreamer {
// Stream is the main loop for subscribing to data from the Geth state diff process
func (i *StateDiffStreamer) Stream(payloadChan chan statediff.Payload) (*rpc.ClientSubscription, error) {
return i.Client.Subscribe("statediff", i.PayloadChan)
-}
\ No newline at end of file
+}
diff --git a/pkg/ipfs/streamer_test.go b/pkg/ipfs/streamer_test.go
new file mode 100644
index 00000000..bef22610
--- /dev/null
+++ b/pkg/ipfs/streamer_test.go
@@ -0,0 +1,17 @@
+// VulcanizeDB
+// Copyright © 2019 Vulcanize
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+package ipfs_test
diff --git a/pkg/ipfs/test_helpers/fakes.go b/pkg/ipfs/test_helpers/fakes.go
new file mode 100644
index 00000000..2c443bf3
--- /dev/null
+++ b/pkg/ipfs/test_helpers/fakes.go
@@ -0,0 +1,17 @@
+// VulcanizeDB
+// Copyright © 2019 Vulcanize
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+package test_helpers
diff --git a/pkg/ipfs/test_helpers/mocks/converter.go b/pkg/ipfs/test_helpers/mocks/converter.go
new file mode 100644
index 00000000..11d51d50
--- /dev/null
+++ b/pkg/ipfs/test_helpers/mocks/converter.go
@@ -0,0 +1,17 @@
+// VulcanizeDB
+// Copyright © 2019 Vulcanize
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+package mocks
diff --git a/pkg/ipfs/test_helpers/mocks/publisher.go b/pkg/ipfs/test_helpers/mocks/publisher.go
new file mode 100644
index 00000000..11d51d50
--- /dev/null
+++ b/pkg/ipfs/test_helpers/mocks/publisher.go
@@ -0,0 +1,17 @@
+// VulcanizeDB
+// Copyright © 2019 Vulcanize
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+package mocks
diff --git a/pkg/ipfs/test_helpers/mocks/repository.go b/pkg/ipfs/test_helpers/mocks/repository.go
new file mode 100644
index 00000000..11d51d50
--- /dev/null
+++ b/pkg/ipfs/test_helpers/mocks/repository.go
@@ -0,0 +1,17 @@
+// VulcanizeDB
+// Copyright © 2019 Vulcanize
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+package mocks
diff --git a/pkg/ipfs/test_helpers/mocks/streamer.go b/pkg/ipfs/test_helpers/mocks/streamer.go
new file mode 100644
index 00000000..11d51d50
--- /dev/null
+++ b/pkg/ipfs/test_helpers/mocks/streamer.go
@@ -0,0 +1,17 @@
+// VulcanizeDB
+// Copyright © 2019 Vulcanize
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+package mocks
diff --git a/pkg/ipfs/test_helpers/test_helpers.go b/pkg/ipfs/test_helpers/test_helpers.go
new file mode 100644
index 00000000..2c443bf3
--- /dev/null
+++ b/pkg/ipfs/test_helpers/test_helpers.go
@@ -0,0 +1,17 @@
+// VulcanizeDB
+// Copyright © 2019 Vulcanize
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+package test_helpers
diff --git a/vendor/bazil.org/fuse/.gitattributes b/vendor/bazil.org/fuse/.gitattributes
new file mode 100644
index 00000000..b65f2a9f
--- /dev/null
+++ b/vendor/bazil.org/fuse/.gitattributes
@@ -0,0 +1,2 @@
+*.go filter=gofmt
+*.cgo filter=gofmt
diff --git a/vendor/bazil.org/fuse/.gitignore b/vendor/bazil.org/fuse/.gitignore
new file mode 100644
index 00000000..53589948
--- /dev/null
+++ b/vendor/bazil.org/fuse/.gitignore
@@ -0,0 +1,11 @@
+*~
+.#*
+## the next line needs to start with a backslash to avoid looking like
+## a comment
+\#*#
+.*.swp
+
+*.test
+
+/clockfs
+/hellofs
diff --git a/vendor/bazil.org/fuse/LICENSE b/vendor/bazil.org/fuse/LICENSE
new file mode 100644
index 00000000..4ac7cd83
--- /dev/null
+++ b/vendor/bazil.org/fuse/LICENSE
@@ -0,0 +1,93 @@
+Copyright (c) 2013-2015 Tommi Virtanen.
+Copyright (c) 2009, 2011, 2012 The Go 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:
+
+ * 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 Google Inc. 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
+OWNER 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.
+
+
+
+The following included software components have additional copyright
+notices and license terms that may differ from the above.
+
+
+File fuse.go:
+
+// Adapted from Plan 9 from User Space's src/cmd/9pfuse/fuse.c,
+// which carries this notice:
+//
+// The files in this directory are subject to the following license.
+//
+// The author of this software is Russ Cox.
+//
+// Copyright (c) 2006 Russ Cox
+//
+// Permission to use, copy, modify, and distribute this software for any
+// purpose without fee is hereby granted, provided that this entire notice
+// is included in all copies of any software which is or includes a copy
+// or modification of this software and in all copies of the supporting
+// documentation for such software.
+//
+// THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+// WARRANTY. IN PARTICULAR, THE AUTHOR MAKES NO REPRESENTATION OR WARRANTY
+// OF ANY KIND CONCERNING THE MERCHANTABILITY OF THIS SOFTWARE OR ITS
+// FITNESS FOR ANY PARTICULAR PURPOSE.
+
+
+File fuse_kernel.go:
+
+// Derived from FUSE's fuse_kernel.h
+/*
+ This file defines the kernel interface of FUSE
+ Copyright (C) 2001-2007 Miklos Szeredi
+
+
+ This -- and only this -- header file may also be distributed under
+ the terms of the BSD Licence as follows:
+
+ Copyright (C) 2001-2007 Miklos Szeredi. 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.
+
+ THIS SOFTWARE IS PROVIDED BY AUTHOR 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 AUTHOR 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.
+*/
diff --git a/vendor/bazil.org/fuse/README.md b/vendor/bazil.org/fuse/README.md
new file mode 100644
index 00000000..8c6d556e
--- /dev/null
+++ b/vendor/bazil.org/fuse/README.md
@@ -0,0 +1,23 @@
+bazil.org/fuse -- Filesystems in Go
+===================================
+
+`bazil.org/fuse` is a Go library for writing FUSE userspace
+filesystems.
+
+It is a from-scratch implementation of the kernel-userspace
+communication protocol, and does not use the C library from the
+project called FUSE. `bazil.org/fuse` embraces Go fully for safety and
+ease of programming.
+
+Here’s how to get going:
+
+ go get bazil.org/fuse
+
+Website: http://bazil.org/fuse/
+
+Github repository: https://github.com/bazil/fuse
+
+API docs: http://godoc.org/bazil.org/fuse
+
+Our thanks to Russ Cox for his fuse library, which this project is
+based on.
diff --git a/vendor/bazil.org/fuse/buffer.go b/vendor/bazil.org/fuse/buffer.go
new file mode 100644
index 00000000..bb1d2b77
--- /dev/null
+++ b/vendor/bazil.org/fuse/buffer.go
@@ -0,0 +1,35 @@
+package fuse
+
+import "unsafe"
+
+// buffer provides a mechanism for constructing a message from
+// multiple segments.
+type buffer []byte
+
+// alloc allocates size bytes and returns a pointer to the new
+// segment.
+func (w *buffer) alloc(size uintptr) unsafe.Pointer {
+ s := int(size)
+ if len(*w)+s > cap(*w) {
+ old := *w
+ *w = make([]byte, len(*w), 2*cap(*w)+s)
+ copy(*w, old)
+ }
+ l := len(*w)
+ *w = (*w)[:l+s]
+ return unsafe.Pointer(&(*w)[l])
+}
+
+// reset clears out the contents of the buffer.
+func (w *buffer) reset() {
+ for i := range (*w)[:cap(*w)] {
+ (*w)[i] = 0
+ }
+ *w = (*w)[:0]
+}
+
+func newBuffer(extra uintptr) buffer {
+ const hdrSize = unsafe.Sizeof(outHeader{})
+ buf := make(buffer, hdrSize, hdrSize+extra)
+ return buf
+}
diff --git a/vendor/bazil.org/fuse/debug.go b/vendor/bazil.org/fuse/debug.go
new file mode 100644
index 00000000..be9f900d
--- /dev/null
+++ b/vendor/bazil.org/fuse/debug.go
@@ -0,0 +1,21 @@
+package fuse
+
+import (
+ "runtime"
+)
+
+func stack() string {
+ buf := make([]byte, 1024)
+ return string(buf[:runtime.Stack(buf, false)])
+}
+
+func nop(msg interface{}) {}
+
+// Debug is called to output debug messages, including protocol
+// traces. The default behavior is to do nothing.
+//
+// The messages have human-friendly string representations and are
+// safe to marshal to JSON.
+//
+// Implementations must not retain msg.
+var Debug func(msg interface{}) = nop
diff --git a/vendor/bazil.org/fuse/error_darwin.go b/vendor/bazil.org/fuse/error_darwin.go
new file mode 100644
index 00000000..a3fb89ca
--- /dev/null
+++ b/vendor/bazil.org/fuse/error_darwin.go
@@ -0,0 +1,17 @@
+package fuse
+
+import (
+ "syscall"
+)
+
+const (
+ ENOATTR = Errno(syscall.ENOATTR)
+)
+
+const (
+ errNoXattr = ENOATTR
+)
+
+func init() {
+ errnoNames[errNoXattr] = "ENOATTR"
+}
diff --git a/vendor/bazil.org/fuse/error_freebsd.go b/vendor/bazil.org/fuse/error_freebsd.go
new file mode 100644
index 00000000..c6ea6d6e
--- /dev/null
+++ b/vendor/bazil.org/fuse/error_freebsd.go
@@ -0,0 +1,15 @@
+package fuse
+
+import "syscall"
+
+const (
+ ENOATTR = Errno(syscall.ENOATTR)
+)
+
+const (
+ errNoXattr = ENOATTR
+)
+
+func init() {
+ errnoNames[errNoXattr] = "ENOATTR"
+}
diff --git a/vendor/bazil.org/fuse/error_linux.go b/vendor/bazil.org/fuse/error_linux.go
new file mode 100644
index 00000000..6f113e71
--- /dev/null
+++ b/vendor/bazil.org/fuse/error_linux.go
@@ -0,0 +1,17 @@
+package fuse
+
+import (
+ "syscall"
+)
+
+const (
+ ENODATA = Errno(syscall.ENODATA)
+)
+
+const (
+ errNoXattr = ENODATA
+)
+
+func init() {
+ errnoNames[errNoXattr] = "ENODATA"
+}
diff --git a/vendor/bazil.org/fuse/error_std.go b/vendor/bazil.org/fuse/error_std.go
new file mode 100644
index 00000000..398f43fb
--- /dev/null
+++ b/vendor/bazil.org/fuse/error_std.go
@@ -0,0 +1,31 @@
+package fuse
+
+// There is very little commonality in extended attribute errors
+// across platforms.
+//
+// getxattr return value for "extended attribute does not exist" is
+// ENOATTR on OS X, and ENODATA on Linux and apparently at least
+// NetBSD. There may be a #define ENOATTR on Linux too, but the value
+// is ENODATA in the actual syscalls. FreeBSD and OpenBSD have no
+// ENODATA, only ENOATTR. ENOATTR is not in any of the standards,
+// ENODATA exists but is only used for STREAMs.
+//
+// Each platform will define it a errNoXattr constant, and this file
+// will enforce that it implements the right interfaces and hide the
+// implementation.
+//
+// https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man2/getxattr.2.html
+// http://mail-index.netbsd.org/tech-kern/2012/04/30/msg013090.html
+// http://mail-index.netbsd.org/tech-kern/2012/04/30/msg013097.html
+// http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/errno.h.html
+// http://www.freebsd.org/cgi/man.cgi?query=extattr_get_file&sektion=2
+// http://nixdoc.net/man-pages/openbsd/man2/extattr_get_file.2.html
+
+// ErrNoXattr is a platform-independent error value meaning the
+// extended attribute was not found. It can be used to respond to
+// GetxattrRequest and such.
+const ErrNoXattr = errNoXattr
+
+var _ error = ErrNoXattr
+var _ Errno = ErrNoXattr
+var _ ErrorNumber = ErrNoXattr
diff --git a/vendor/bazil.org/fuse/fs/serve.go b/vendor/bazil.org/fuse/fs/serve.go
new file mode 100644
index 00000000..e9fc5659
--- /dev/null
+++ b/vendor/bazil.org/fuse/fs/serve.go
@@ -0,0 +1,1568 @@
+// FUSE service loop, for servers that wish to use it.
+
+package fs // import "bazil.org/fuse/fs"
+
+import (
+ "encoding/binary"
+ "fmt"
+ "hash/fnv"
+ "io"
+ "log"
+ "reflect"
+ "runtime"
+ "strings"
+ "sync"
+ "time"
+
+ "golang.org/x/net/context"
+)
+
+import (
+ "bytes"
+
+ "bazil.org/fuse"
+ "bazil.org/fuse/fuseutil"
+)
+
+const (
+ attrValidTime = 1 * time.Minute
+ entryValidTime = 1 * time.Minute
+)
+
+// TODO: FINISH DOCS
+
+// An FS is the interface required of a file system.
+//
+// Other FUSE requests can be handled by implementing methods from the
+// FS* interfaces, for example FSStatfser.
+type FS interface {
+ // Root is called to obtain the Node for the file system root.
+ Root() (Node, error)
+}
+
+type FSStatfser interface {
+ // Statfs is called to obtain file system metadata.
+ // It should write that data to resp.
+ Statfs(ctx context.Context, req *fuse.StatfsRequest, resp *fuse.StatfsResponse) error
+}
+
+type FSDestroyer interface {
+ // Destroy is called when the file system is shutting down.
+ //
+ // Linux only sends this request for block device backed (fuseblk)
+ // filesystems, to allow them to flush writes to disk before the
+ // unmount completes.
+ Destroy()
+}
+
+type FSInodeGenerator interface {
+ // GenerateInode is called to pick a dynamic inode number when it
+ // would otherwise be 0.
+ //
+ // Not all filesystems bother tracking inodes, but FUSE requires
+ // the inode to be set, and fewer duplicates in general makes UNIX
+ // tools work better.
+ //
+ // Operations where the nodes may return 0 inodes include Getattr,
+ // Setattr and ReadDir.
+ //
+ // If FS does not implement FSInodeGenerator, GenerateDynamicInode
+ // is used.
+ //
+ // Implementing this is useful to e.g. constrain the range of
+ // inode values used for dynamic inodes.
+ GenerateInode(parentInode uint64, name string) uint64
+}
+
+// A Node is the interface required of a file or directory.
+// See the documentation for type FS for general information
+// pertaining to all methods.
+//
+// A Node must be usable as a map key, that is, it cannot be a
+// function, map or slice.
+//
+// Other FUSE requests can be handled by implementing methods from the
+// Node* interfaces, for example NodeOpener.
+//
+// Methods returning Node should take care to return the same Node
+// when the result is logically the same instance. Without this, each
+// Node will get a new NodeID, causing spurious cache invalidations,
+// extra lookups and aliasing anomalies. This may not matter for a
+// simple, read-only filesystem.
+type Node interface {
+ // Attr fills attr with the standard metadata for the node.
+ //
+ // Fields with reasonable defaults are prepopulated. For example,
+ // all times are set to a fixed moment when the program started.
+ //
+ // If Inode is left as 0, a dynamic inode number is chosen.
+ //
+ // The result may be cached for the duration set in Valid.
+ Attr(ctx context.Context, attr *fuse.Attr) error
+}
+
+type NodeGetattrer interface {
+ // Getattr obtains the standard metadata for the receiver.
+ // It should store that metadata in resp.
+ //
+ // If this method is not implemented, the attributes will be
+ // generated based on Attr(), with zero values filled in.
+ Getattr(ctx context.Context, req *fuse.GetattrRequest, resp *fuse.GetattrResponse) error
+}
+
+type NodeSetattrer interface {
+ // Setattr sets the standard metadata for the receiver.
+ //
+ // Note, this is also used to communicate changes in the size of
+ // the file, outside of Writes.
+ //
+ // req.Valid is a bitmask of what fields are actually being set.
+ // For example, the method should not change the mode of the file
+ // unless req.Valid.Mode() is true.
+ Setattr(ctx context.Context, req *fuse.SetattrRequest, resp *fuse.SetattrResponse) error
+}
+
+type NodeSymlinker interface {
+ // Symlink creates a new symbolic link in the receiver, which must be a directory.
+ //
+ // TODO is the above true about directories?
+ Symlink(ctx context.Context, req *fuse.SymlinkRequest) (Node, error)
+}
+
+// This optional request will be called only for symbolic link nodes.
+type NodeReadlinker interface {
+ // Readlink reads a symbolic link.
+ Readlink(ctx context.Context, req *fuse.ReadlinkRequest) (string, error)
+}
+
+type NodeLinker interface {
+ // Link creates a new directory entry in the receiver based on an
+ // existing Node. Receiver must be a directory.
+ Link(ctx context.Context, req *fuse.LinkRequest, old Node) (Node, error)
+}
+
+type NodeRemover interface {
+ // Remove removes the entry with the given name from
+ // the receiver, which must be a directory. The entry to be removed
+ // may correspond to a file (unlink) or to a directory (rmdir).
+ Remove(ctx context.Context, req *fuse.RemoveRequest) error
+}
+
+type NodeAccesser interface {
+ // Access checks whether the calling context has permission for
+ // the given operations on the receiver. If so, Access should
+ // return nil. If not, Access should return EPERM.
+ //
+ // Note that this call affects the result of the access(2) system
+ // call but not the open(2) system call. If Access is not
+ // implemented, the Node behaves as if it always returns nil
+ // (permission granted), relying on checks in Open instead.
+ Access(ctx context.Context, req *fuse.AccessRequest) error
+}
+
+type NodeStringLookuper interface {
+ // Lookup looks up a specific entry in the receiver,
+ // which must be a directory. Lookup should return a Node
+ // corresponding to the entry. If the name does not exist in
+ // the directory, Lookup should return ENOENT.
+ //
+ // Lookup need not to handle the names "." and "..".
+ Lookup(ctx context.Context, name string) (Node, error)
+}
+
+type NodeRequestLookuper interface {
+ // Lookup looks up a specific entry in the receiver.
+ // See NodeStringLookuper for more.
+ Lookup(ctx context.Context, req *fuse.LookupRequest, resp *fuse.LookupResponse) (Node, error)
+}
+
+type NodeMkdirer interface {
+ Mkdir(ctx context.Context, req *fuse.MkdirRequest) (Node, error)
+}
+
+type NodeOpener interface {
+ // Open opens the receiver. After a successful open, a client
+ // process has a file descriptor referring to this Handle.
+ //
+ // Open can also be also called on non-files. For example,
+ // directories are Opened for ReadDir or fchdir(2).
+ //
+ // If this method is not implemented, the open will always
+ // succeed, and the Node itself will be used as the Handle.
+ //
+ // XXX note about access. XXX OpenFlags.
+ Open(ctx context.Context, req *fuse.OpenRequest, resp *fuse.OpenResponse) (Handle, error)
+}
+
+type NodeCreater interface {
+ // Create creates a new directory entry in the receiver, which
+ // must be a directory.
+ Create(ctx context.Context, req *fuse.CreateRequest, resp *fuse.CreateResponse) (Node, Handle, error)
+}
+
+type NodeForgetter interface {
+ // Forget about this node. This node will not receive further
+ // method calls.
+ //
+ // Forget is not necessarily seen on unmount, as all nodes are
+ // implicitly forgotten as part part of the unmount.
+ Forget()
+}
+
+type NodeRenamer interface {
+ Rename(ctx context.Context, req *fuse.RenameRequest, newDir Node) error
+}
+
+type NodeMknoder interface {
+ Mknod(ctx context.Context, req *fuse.MknodRequest) (Node, error)
+}
+
+// TODO this should be on Handle not Node
+type NodeFsyncer interface {
+ Fsync(ctx context.Context, req *fuse.FsyncRequest) error
+}
+
+type NodeGetxattrer interface {
+ // Getxattr gets an extended attribute by the given name from the
+ // node.
+ //
+ // If there is no xattr by that name, returns fuse.ErrNoXattr.
+ Getxattr(ctx context.Context, req *fuse.GetxattrRequest, resp *fuse.GetxattrResponse) error
+}
+
+type NodeListxattrer interface {
+ // Listxattr lists the extended attributes recorded for the node.
+ Listxattr(ctx context.Context, req *fuse.ListxattrRequest, resp *fuse.ListxattrResponse) error
+}
+
+type NodeSetxattrer interface {
+ // Setxattr sets an extended attribute with the given name and
+ // value for the node.
+ Setxattr(ctx context.Context, req *fuse.SetxattrRequest) error
+}
+
+type NodeRemovexattrer interface {
+ // Removexattr removes an extended attribute for the name.
+ //
+ // If there is no xattr by that name, returns fuse.ErrNoXattr.
+ Removexattr(ctx context.Context, req *fuse.RemovexattrRequest) error
+}
+
+var startTime = time.Now()
+
+func nodeAttr(ctx context.Context, n Node, attr *fuse.Attr) error {
+ attr.Valid = attrValidTime
+ attr.Nlink = 1
+ attr.Atime = startTime
+ attr.Mtime = startTime
+ attr.Ctime = startTime
+ attr.Crtime = startTime
+ if err := n.Attr(ctx, attr); err != nil {
+ return err
+ }
+ return nil
+}
+
+// A Handle is the interface required of an opened file or directory.
+// See the documentation for type FS for general information
+// pertaining to all methods.
+//
+// Other FUSE requests can be handled by implementing methods from the
+// Handle* interfaces. The most common to implement are HandleReader,
+// HandleReadDirer, and HandleWriter.
+//
+// TODO implement methods: Getlk, Setlk, Setlkw
+type Handle interface {
+}
+
+type HandleFlusher interface {
+ // Flush is called each time the file or directory is closed.
+ // Because there can be multiple file descriptors referring to a
+ // single opened file, Flush can be called multiple times.
+ Flush(ctx context.Context, req *fuse.FlushRequest) error
+}
+
+type HandleReadAller interface {
+ ReadAll(ctx context.Context) ([]byte, error)
+}
+
+type HandleReadDirAller interface {
+ ReadDirAll(ctx context.Context) ([]fuse.Dirent, error)
+}
+
+type HandleReader interface {
+ // Read requests to read data from the handle.
+ //
+ // There is a page cache in the kernel that normally submits only
+ // page-aligned reads spanning one or more pages. However, you
+ // should not rely on this. To see individual requests as
+ // submitted by the file system clients, set OpenDirectIO.
+ //
+ // Note that reads beyond the size of the file as reported by Attr
+ // are not even attempted (except in OpenDirectIO mode).
+ Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error
+}
+
+type HandleWriter interface {
+ // Write requests to write data into the handle at the given offset.
+ // Store the amount of data written in resp.Size.
+ //
+ // There is a writeback page cache in the kernel that normally submits
+ // only page-aligned writes spanning one or more pages. However,
+ // you should not rely on this. To see individual requests as
+ // submitted by the file system clients, set OpenDirectIO.
+ //
+ // Writes that grow the file are expected to update the file size
+ // (as seen through Attr). Note that file size changes are
+ // communicated also through Setattr.
+ Write(ctx context.Context, req *fuse.WriteRequest, resp *fuse.WriteResponse) error
+}
+
+type HandleReleaser interface {
+ Release(ctx context.Context, req *fuse.ReleaseRequest) error
+}
+
+type Config struct {
+ // Function to send debug log messages to. If nil, use fuse.Debug.
+ // Note that changing this or fuse.Debug may not affect existing
+ // calls to Serve.
+ //
+ // See fuse.Debug for the rules that log functions must follow.
+ Debug func(msg interface{})
+
+ // Function to put things into context for processing the request.
+ // The returned context must have ctx as its parent.
+ //
+ // Note that changing this may not affect existing calls to Serve.
+ //
+ // Must not retain req.
+ WithContext func(ctx context.Context, req fuse.Request) context.Context
+}
+
+// New returns a new FUSE server ready to serve this kernel FUSE
+// connection.
+//
+// Config may be nil.
+func New(conn *fuse.Conn, config *Config) *Server {
+ s := &Server{
+ conn: conn,
+ req: map[fuse.RequestID]*serveRequest{},
+ nodeRef: map[Node]fuse.NodeID{},
+ dynamicInode: GenerateDynamicInode,
+ }
+ if config != nil {
+ s.debug = config.Debug
+ s.context = config.WithContext
+ }
+ if s.debug == nil {
+ s.debug = fuse.Debug
+ }
+ return s
+}
+
+type Server struct {
+ // set in New
+ conn *fuse.Conn
+ debug func(msg interface{})
+ context func(ctx context.Context, req fuse.Request) context.Context
+
+ // set once at Serve time
+ fs FS
+ dynamicInode func(parent uint64, name string) uint64
+
+ // state, protected by meta
+ meta sync.Mutex
+ req map[fuse.RequestID]*serveRequest
+ node []*serveNode
+ nodeRef map[Node]fuse.NodeID
+ handle []*serveHandle
+ freeNode []fuse.NodeID
+ freeHandle []fuse.HandleID
+ nodeGen uint64
+
+ // Used to ensure worker goroutines finish before Serve returns
+ wg sync.WaitGroup
+}
+
+// Serve serves the FUSE connection by making calls to the methods
+// of fs and the Nodes and Handles it makes available. It returns only
+// when the connection has been closed or an unexpected error occurs.
+func (s *Server) Serve(fs FS) error {
+ defer s.wg.Wait() // Wait for worker goroutines to complete before return
+
+ s.fs = fs
+ if dyn, ok := fs.(FSInodeGenerator); ok {
+ s.dynamicInode = dyn.GenerateInode
+ }
+
+ root, err := fs.Root()
+ if err != nil {
+ return fmt.Errorf("cannot obtain root node: %v", err)
+ }
+ // Recognize the root node if it's ever returned from Lookup,
+ // passed to Invalidate, etc.
+ s.nodeRef[root] = 1
+ s.node = append(s.node, nil, &serveNode{
+ inode: 1,
+ generation: s.nodeGen,
+ node: root,
+ refs: 1,
+ })
+ s.handle = append(s.handle, nil)
+
+ for {
+ req, err := s.conn.ReadRequest()
+ if err != nil {
+ if err == io.EOF {
+ break
+ }
+ return err
+ }
+
+ s.wg.Add(1)
+ go func() {
+ defer s.wg.Done()
+ s.serve(req)
+ }()
+ }
+ return nil
+}
+
+// Serve serves a FUSE connection with the default settings. See
+// Server.Serve.
+func Serve(c *fuse.Conn, fs FS) error {
+ server := New(c, nil)
+ return server.Serve(fs)
+}
+
+type nothing struct{}
+
+type serveRequest struct {
+ Request fuse.Request
+ cancel func()
+}
+
+type serveNode struct {
+ inode uint64
+ generation uint64
+ node Node
+ refs uint64
+
+ // Delay freeing the NodeID until waitgroup is done. This allows
+ // using the NodeID for short periods of time without holding the
+ // Server.meta lock.
+ //
+ // Rules:
+ //
+ // - hold Server.meta while calling wg.Add, then unlock
+ // - do NOT try to reacquire Server.meta
+ wg sync.WaitGroup
+}
+
+func (sn *serveNode) attr(ctx context.Context, attr *fuse.Attr) error {
+ err := nodeAttr(ctx, sn.node, attr)
+ if attr.Inode == 0 {
+ attr.Inode = sn.inode
+ }
+ return err
+}
+
+type serveHandle struct {
+ handle Handle
+ readData []byte
+ nodeID fuse.NodeID
+}
+
+// NodeRef is deprecated. It remains here to decrease code churn on
+// FUSE library users. You may remove it from your program now;
+// returning the same Node values are now recognized automatically,
+// without needing NodeRef.
+type NodeRef struct{}
+
+func (c *Server) saveNode(inode uint64, node Node) (id fuse.NodeID, gen uint64) {
+ c.meta.Lock()
+ defer c.meta.Unlock()
+
+ if id, ok := c.nodeRef[node]; ok {
+ sn := c.node[id]
+ sn.refs++
+ return id, sn.generation
+ }
+
+ sn := &serveNode{inode: inode, node: node, refs: 1}
+ if n := len(c.freeNode); n > 0 {
+ id = c.freeNode[n-1]
+ c.freeNode = c.freeNode[:n-1]
+ c.node[id] = sn
+ c.nodeGen++
+ } else {
+ id = fuse.NodeID(len(c.node))
+ c.node = append(c.node, sn)
+ }
+ sn.generation = c.nodeGen
+ c.nodeRef[node] = id
+ return id, sn.generation
+}
+
+func (c *Server) saveHandle(handle Handle, nodeID fuse.NodeID) (id fuse.HandleID) {
+ c.meta.Lock()
+ shandle := &serveHandle{handle: handle, nodeID: nodeID}
+ if n := len(c.freeHandle); n > 0 {
+ id = c.freeHandle[n-1]
+ c.freeHandle = c.freeHandle[:n-1]
+ c.handle[id] = shandle
+ } else {
+ id = fuse.HandleID(len(c.handle))
+ c.handle = append(c.handle, shandle)
+ }
+ c.meta.Unlock()
+ return
+}
+
+type nodeRefcountDropBug struct {
+ N uint64
+ Refs uint64
+ Node fuse.NodeID
+}
+
+func (n *nodeRefcountDropBug) String() string {
+ return fmt.Sprintf("bug: trying to drop %d of %d references to %v", n.N, n.Refs, n.Node)
+}
+
+func (c *Server) dropNode(id fuse.NodeID, n uint64) (forget bool) {
+ c.meta.Lock()
+ defer c.meta.Unlock()
+ snode := c.node[id]
+
+ if snode == nil {
+ // this should only happen if refcounts kernel<->us disagree
+ // *and* two ForgetRequests for the same node race each other;
+ // this indicates a bug somewhere
+ c.debug(nodeRefcountDropBug{N: n, Node: id})
+
+ // we may end up triggering Forget twice, but that's better
+ // than not even once, and that's the best we can do
+ return true
+ }
+
+ if n > snode.refs {
+ c.debug(nodeRefcountDropBug{N: n, Refs: snode.refs, Node: id})
+ n = snode.refs
+ }
+
+ snode.refs -= n
+ if snode.refs == 0 {
+ snode.wg.Wait()
+ c.node[id] = nil
+ delete(c.nodeRef, snode.node)
+ c.freeNode = append(c.freeNode, id)
+ return true
+ }
+ return false
+}
+
+func (c *Server) dropHandle(id fuse.HandleID) {
+ c.meta.Lock()
+ c.handle[id] = nil
+ c.freeHandle = append(c.freeHandle, id)
+ c.meta.Unlock()
+}
+
+type missingHandle struct {
+ Handle fuse.HandleID
+ MaxHandle fuse.HandleID
+}
+
+func (m missingHandle) String() string {
+ return fmt.Sprint("missing handle: ", m.Handle, m.MaxHandle)
+}
+
+// Returns nil for invalid handles.
+func (c *Server) getHandle(id fuse.HandleID) (shandle *serveHandle) {
+ c.meta.Lock()
+ defer c.meta.Unlock()
+ if id < fuse.HandleID(len(c.handle)) {
+ shandle = c.handle[uint(id)]
+ }
+ if shandle == nil {
+ c.debug(missingHandle{
+ Handle: id,
+ MaxHandle: fuse.HandleID(len(c.handle)),
+ })
+ }
+ return
+}
+
+type request struct {
+ Op string
+ Request *fuse.Header
+ In interface{} `json:",omitempty"`
+}
+
+func (r request) String() string {
+ return fmt.Sprintf("<- %s", r.In)
+}
+
+type logResponseHeader struct {
+ ID fuse.RequestID
+}
+
+func (m logResponseHeader) String() string {
+ return fmt.Sprintf("ID=%v", m.ID)
+}
+
+type response struct {
+ Op string
+ Request logResponseHeader
+ Out interface{} `json:",omitempty"`
+ // Errno contains the errno value as a string, for example "EPERM".
+ Errno string `json:",omitempty"`
+ // Error may contain a free form error message.
+ Error string `json:",omitempty"`
+}
+
+func (r response) errstr() string {
+ s := r.Errno
+ if r.Error != "" {
+ // prefix the errno constant to the long form message
+ s = s + ": " + r.Error
+ }
+ return s
+}
+
+func (r response) String() string {
+ switch {
+ case r.Errno != "" && r.Out != nil:
+ return fmt.Sprintf("-> [%v] %v error=%s", r.Request, r.Out, r.errstr())
+ case r.Errno != "":
+ return fmt.Sprintf("-> [%v] %s error=%s", r.Request, r.Op, r.errstr())
+ case r.Out != nil:
+ // make sure (seemingly) empty values are readable
+ switch r.Out.(type) {
+ case string:
+ return fmt.Sprintf("-> [%v] %s %q", r.Request, r.Op, r.Out)
+ case []byte:
+ return fmt.Sprintf("-> [%v] %s [% x]", r.Request, r.Op, r.Out)
+ default:
+ return fmt.Sprintf("-> [%v] %v", r.Request, r.Out)
+ }
+ default:
+ return fmt.Sprintf("-> [%v] %s", r.Request, r.Op)
+ }
+}
+
+type notification struct {
+ Op string
+ Node fuse.NodeID
+ Out interface{} `json:",omitempty"`
+ Err string `json:",omitempty"`
+}
+
+func (n notification) String() string {
+ var buf bytes.Buffer
+ fmt.Fprintf(&buf, "=> %s %v", n.Op, n.Node)
+ if n.Out != nil {
+ // make sure (seemingly) empty values are readable
+ switch n.Out.(type) {
+ case string:
+ fmt.Fprintf(&buf, " %q", n.Out)
+ case []byte:
+ fmt.Fprintf(&buf, " [% x]", n.Out)
+ default:
+ fmt.Fprintf(&buf, " %s", n.Out)
+ }
+ }
+ if n.Err != "" {
+ fmt.Fprintf(&buf, " Err:%v", n.Err)
+ }
+ return buf.String()
+}
+
+type logMissingNode struct {
+ MaxNode fuse.NodeID
+}
+
+func opName(req fuse.Request) string {
+ t := reflect.Indirect(reflect.ValueOf(req)).Type()
+ s := t.Name()
+ s = strings.TrimSuffix(s, "Request")
+ return s
+}
+
+type logLinkRequestOldNodeNotFound struct {
+ Request *fuse.Header
+ In *fuse.LinkRequest
+}
+
+func (m *logLinkRequestOldNodeNotFound) String() string {
+ return fmt.Sprintf("In LinkRequest (request %v), node %d not found", m.Request.Hdr().ID, m.In.OldNode)
+}
+
+type renameNewDirNodeNotFound struct {
+ Request *fuse.Header
+ In *fuse.RenameRequest
+}
+
+func (m *renameNewDirNodeNotFound) String() string {
+ return fmt.Sprintf("In RenameRequest (request %v), node %d not found", m.Request.Hdr().ID, m.In.NewDir)
+}
+
+type handlerPanickedError struct {
+ Request interface{}
+ Err interface{}
+}
+
+var _ error = handlerPanickedError{}
+
+func (h handlerPanickedError) Error() string {
+ return fmt.Sprintf("handler panicked: %v", h.Err)
+}
+
+var _ fuse.ErrorNumber = handlerPanickedError{}
+
+func (h handlerPanickedError) Errno() fuse.Errno {
+ if err, ok := h.Err.(fuse.ErrorNumber); ok {
+ return err.Errno()
+ }
+ return fuse.DefaultErrno
+}
+
+// handlerTerminatedError happens when a handler terminates itself
+// with runtime.Goexit. This is most commonly because of incorrect use
+// of testing.TB.FailNow, typically via t.Fatal.
+type handlerTerminatedError struct {
+ Request interface{}
+}
+
+var _ error = handlerTerminatedError{}
+
+func (h handlerTerminatedError) Error() string {
+ return fmt.Sprintf("handler terminated (called runtime.Goexit)")
+}
+
+var _ fuse.ErrorNumber = handlerTerminatedError{}
+
+func (h handlerTerminatedError) Errno() fuse.Errno {
+ return fuse.DefaultErrno
+}
+
+type handleNotReaderError struct {
+ handle Handle
+}
+
+var _ error = handleNotReaderError{}
+
+func (e handleNotReaderError) Error() string {
+ return fmt.Sprintf("handle has no Read: %T", e.handle)
+}
+
+var _ fuse.ErrorNumber = handleNotReaderError{}
+
+func (e handleNotReaderError) Errno() fuse.Errno {
+ return fuse.ENOTSUP
+}
+
+func initLookupResponse(s *fuse.LookupResponse) {
+ s.EntryValid = entryValidTime
+}
+
+func (c *Server) serve(r fuse.Request) {
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ parentCtx := ctx
+ if c.context != nil {
+ ctx = c.context(ctx, r)
+ }
+
+ req := &serveRequest{Request: r, cancel: cancel}
+
+ c.debug(request{
+ Op: opName(r),
+ Request: r.Hdr(),
+ In: r,
+ })
+ var node Node
+ var snode *serveNode
+ c.meta.Lock()
+ hdr := r.Hdr()
+ if id := hdr.Node; id != 0 {
+ if id < fuse.NodeID(len(c.node)) {
+ snode = c.node[uint(id)]
+ }
+ if snode == nil {
+ c.meta.Unlock()
+ c.debug(response{
+ Op: opName(r),
+ Request: logResponseHeader{ID: hdr.ID},
+ Error: fuse.ESTALE.ErrnoName(),
+ // this is the only place that sets both Error and
+ // Out; not sure if i want to do that; might get rid
+ // of len(c.node) things altogether
+ Out: logMissingNode{
+ MaxNode: fuse.NodeID(len(c.node)),
+ },
+ })
+ r.RespondError(fuse.ESTALE)
+ return
+ }
+ node = snode.node
+ }
+ if c.req[hdr.ID] != nil {
+ // This happens with OSXFUSE. Assume it's okay and
+ // that we'll never see an interrupt for this one.
+ // Otherwise everything wedges. TODO: Report to OSXFUSE?
+ //
+ // TODO this might have been because of missing done() calls
+ } else {
+ c.req[hdr.ID] = req
+ }
+ c.meta.Unlock()
+
+ // Call this before responding.
+ // After responding is too late: we might get another request
+ // with the same ID and be very confused.
+ done := func(resp interface{}) {
+ msg := response{
+ Op: opName(r),
+ Request: logResponseHeader{ID: hdr.ID},
+ }
+ if err, ok := resp.(error); ok {
+ msg.Error = err.Error()
+ if ferr, ok := err.(fuse.ErrorNumber); ok {
+ errno := ferr.Errno()
+ msg.Errno = errno.ErrnoName()
+ if errno == err {
+ // it's just a fuse.Errno with no extra detail;
+ // skip the textual message for log readability
+ msg.Error = ""
+ }
+ } else {
+ msg.Errno = fuse.DefaultErrno.ErrnoName()
+ }
+ } else {
+ msg.Out = resp
+ }
+ c.debug(msg)
+
+ c.meta.Lock()
+ delete(c.req, hdr.ID)
+ c.meta.Unlock()
+ }
+
+ var responded bool
+ defer func() {
+ if rec := recover(); rec != nil {
+ const size = 1 << 16
+ buf := make([]byte, size)
+ n := runtime.Stack(buf, false)
+ buf = buf[:n]
+ log.Printf("fuse: panic in handler for %v: %v\n%s", r, rec, buf)
+ err := handlerPanickedError{
+ Request: r,
+ Err: rec,
+ }
+ done(err)
+ r.RespondError(err)
+ return
+ }
+
+ if !responded {
+ err := handlerTerminatedError{
+ Request: r,
+ }
+ done(err)
+ r.RespondError(err)
+ }
+ }()
+
+ if err := c.handleRequest(ctx, node, snode, r, done); err != nil {
+ if err == context.Canceled {
+ select {
+ case <-parentCtx.Done():
+ // We canceled the parent context because of an
+ // incoming interrupt request, so return EINTR
+ // to trigger the right behavior in the client app.
+ //
+ // Only do this when it's the parent context that was
+ // canceled, not a context controlled by the program
+ // using this library, so we don't return EINTR too
+ // eagerly -- it might cause busy loops.
+ //
+ // Decent write-up on role of EINTR:
+ // http://250bpm.com/blog:12
+ err = fuse.EINTR
+ default:
+ // nothing
+ }
+ }
+ done(err)
+ r.RespondError(err)
+ }
+
+ // disarm runtime.Goexit protection
+ responded = true
+}
+
+// handleRequest will either a) call done(s) and r.Respond(s) OR b) return an error.
+func (c *Server) handleRequest(ctx context.Context, node Node, snode *serveNode, r fuse.Request, done func(resp interface{})) error {
+ switch r := r.(type) {
+ default:
+ // Note: To FUSE, ENOSYS means "this server never implements this request."
+ // It would be inappropriate to return ENOSYS for other operations in this
+ // switch that might only be unavailable in some contexts, not all.
+ return fuse.ENOSYS
+
+ case *fuse.StatfsRequest:
+ s := &fuse.StatfsResponse{}
+ if fs, ok := c.fs.(FSStatfser); ok {
+ if err := fs.Statfs(ctx, r, s); err != nil {
+ return err
+ }
+ }
+ done(s)
+ r.Respond(s)
+ return nil
+
+ // Node operations.
+ case *fuse.GetattrRequest:
+ s := &fuse.GetattrResponse{}
+ if n, ok := node.(NodeGetattrer); ok {
+ if err := n.Getattr(ctx, r, s); err != nil {
+ return err
+ }
+ } else {
+ if err := snode.attr(ctx, &s.Attr); err != nil {
+ return err
+ }
+ }
+ done(s)
+ r.Respond(s)
+ return nil
+
+ case *fuse.SetattrRequest:
+ s := &fuse.SetattrResponse{}
+ if n, ok := node.(NodeSetattrer); ok {
+ if err := n.Setattr(ctx, r, s); err != nil {
+ return err
+ }
+ }
+
+ if err := snode.attr(ctx, &s.Attr); err != nil {
+ return err
+ }
+ done(s)
+ r.Respond(s)
+ return nil
+
+ case *fuse.SymlinkRequest:
+ s := &fuse.SymlinkResponse{}
+ initLookupResponse(&s.LookupResponse)
+ n, ok := node.(NodeSymlinker)
+ if !ok {
+ return fuse.EIO // XXX or EPERM like Mkdir?
+ }
+ n2, err := n.Symlink(ctx, r)
+ if err != nil {
+ return err
+ }
+ if err := c.saveLookup(ctx, &s.LookupResponse, snode, r.NewName, n2); err != nil {
+ return err
+ }
+ done(s)
+ r.Respond(s)
+ return nil
+
+ case *fuse.ReadlinkRequest:
+ n, ok := node.(NodeReadlinker)
+ if !ok {
+ return fuse.EIO /// XXX or EPERM?
+ }
+ target, err := n.Readlink(ctx, r)
+ if err != nil {
+ return err
+ }
+ done(target)
+ r.Respond(target)
+ return nil
+
+ case *fuse.LinkRequest:
+ n, ok := node.(NodeLinker)
+ if !ok {
+ return fuse.EIO /// XXX or EPERM?
+ }
+ c.meta.Lock()
+ var oldNode *serveNode
+ if int(r.OldNode) < len(c.node) {
+ oldNode = c.node[r.OldNode]
+ }
+ c.meta.Unlock()
+ if oldNode == nil {
+ c.debug(logLinkRequestOldNodeNotFound{
+ Request: r.Hdr(),
+ In: r,
+ })
+ return fuse.EIO
+ }
+ n2, err := n.Link(ctx, r, oldNode.node)
+ if err != nil {
+ return err
+ }
+ s := &fuse.LookupResponse{}
+ initLookupResponse(s)
+ if err := c.saveLookup(ctx, s, snode, r.NewName, n2); err != nil {
+ return err
+ }
+ done(s)
+ r.Respond(s)
+ return nil
+
+ case *fuse.RemoveRequest:
+ n, ok := node.(NodeRemover)
+ if !ok {
+ return fuse.EIO /// XXX or EPERM?
+ }
+ err := n.Remove(ctx, r)
+ if err != nil {
+ return err
+ }
+ done(nil)
+ r.Respond()
+ return nil
+
+ case *fuse.AccessRequest:
+ if n, ok := node.(NodeAccesser); ok {
+ if err := n.Access(ctx, r); err != nil {
+ return err
+ }
+ }
+ done(nil)
+ r.Respond()
+ return nil
+
+ case *fuse.LookupRequest:
+ var n2 Node
+ var err error
+ s := &fuse.LookupResponse{}
+ initLookupResponse(s)
+ if n, ok := node.(NodeStringLookuper); ok {
+ n2, err = n.Lookup(ctx, r.Name)
+ } else if n, ok := node.(NodeRequestLookuper); ok {
+ n2, err = n.Lookup(ctx, r, s)
+ } else {
+ return fuse.ENOENT
+ }
+ if err != nil {
+ return err
+ }
+ if err := c.saveLookup(ctx, s, snode, r.Name, n2); err != nil {
+ return err
+ }
+ done(s)
+ r.Respond(s)
+ return nil
+
+ case *fuse.MkdirRequest:
+ s := &fuse.MkdirResponse{}
+ initLookupResponse(&s.LookupResponse)
+ n, ok := node.(NodeMkdirer)
+ if !ok {
+ return fuse.EPERM
+ }
+ n2, err := n.Mkdir(ctx, r)
+ if err != nil {
+ return err
+ }
+ if err := c.saveLookup(ctx, &s.LookupResponse, snode, r.Name, n2); err != nil {
+ return err
+ }
+ done(s)
+ r.Respond(s)
+ return nil
+
+ case *fuse.OpenRequest:
+ s := &fuse.OpenResponse{}
+ var h2 Handle
+ if n, ok := node.(NodeOpener); ok {
+ hh, err := n.Open(ctx, r, s)
+ if err != nil {
+ return err
+ }
+ h2 = hh
+ } else {
+ h2 = node
+ }
+ s.Handle = c.saveHandle(h2, r.Hdr().Node)
+ done(s)
+ r.Respond(s)
+ return nil
+
+ case *fuse.CreateRequest:
+ n, ok := node.(NodeCreater)
+ if !ok {
+ // If we send back ENOSYS, FUSE will try mknod+open.
+ return fuse.EPERM
+ }
+ s := &fuse.CreateResponse{OpenResponse: fuse.OpenResponse{}}
+ initLookupResponse(&s.LookupResponse)
+ n2, h2, err := n.Create(ctx, r, s)
+ if err != nil {
+ return err
+ }
+ if err := c.saveLookup(ctx, &s.LookupResponse, snode, r.Name, n2); err != nil {
+ return err
+ }
+ s.Handle = c.saveHandle(h2, r.Hdr().Node)
+ done(s)
+ r.Respond(s)
+ return nil
+
+ case *fuse.GetxattrRequest:
+ n, ok := node.(NodeGetxattrer)
+ if !ok {
+ return fuse.ENOTSUP
+ }
+ s := &fuse.GetxattrResponse{}
+ err := n.Getxattr(ctx, r, s)
+ if err != nil {
+ return err
+ }
+ if r.Size != 0 && uint64(len(s.Xattr)) > uint64(r.Size) {
+ return fuse.ERANGE
+ }
+ done(s)
+ r.Respond(s)
+ return nil
+
+ case *fuse.ListxattrRequest:
+ n, ok := node.(NodeListxattrer)
+ if !ok {
+ return fuse.ENOTSUP
+ }
+ s := &fuse.ListxattrResponse{}
+ err := n.Listxattr(ctx, r, s)
+ if err != nil {
+ return err
+ }
+ if r.Size != 0 && uint64(len(s.Xattr)) > uint64(r.Size) {
+ return fuse.ERANGE
+ }
+ done(s)
+ r.Respond(s)
+ return nil
+
+ case *fuse.SetxattrRequest:
+ n, ok := node.(NodeSetxattrer)
+ if !ok {
+ return fuse.ENOTSUP
+ }
+ err := n.Setxattr(ctx, r)
+ if err != nil {
+ return err
+ }
+ done(nil)
+ r.Respond()
+ return nil
+
+ case *fuse.RemovexattrRequest:
+ n, ok := node.(NodeRemovexattrer)
+ if !ok {
+ return fuse.ENOTSUP
+ }
+ err := n.Removexattr(ctx, r)
+ if err != nil {
+ return err
+ }
+ done(nil)
+ r.Respond()
+ return nil
+
+ case *fuse.ForgetRequest:
+ forget := c.dropNode(r.Hdr().Node, r.N)
+ if forget {
+ n, ok := node.(NodeForgetter)
+ if ok {
+ n.Forget()
+ }
+ }
+ done(nil)
+ r.Respond()
+ return nil
+
+ // Handle operations.
+ case *fuse.ReadRequest:
+ shandle := c.getHandle(r.Handle)
+ if shandle == nil {
+ return fuse.ESTALE
+ }
+ handle := shandle.handle
+
+ s := &fuse.ReadResponse{Data: make([]byte, 0, r.Size)}
+ if r.Dir {
+ if h, ok := handle.(HandleReadDirAller); ok {
+ // detect rewinddir(3) or similar seek and refresh
+ // contents
+ if r.Offset == 0 {
+ shandle.readData = nil
+ }
+
+ if shandle.readData == nil {
+ dirs, err := h.ReadDirAll(ctx)
+ if err != nil {
+ return err
+ }
+ var data []byte
+ for _, dir := range dirs {
+ if dir.Inode == 0 {
+ dir.Inode = c.dynamicInode(snode.inode, dir.Name)
+ }
+ data = fuse.AppendDirent(data, dir)
+ }
+ shandle.readData = data
+ }
+ fuseutil.HandleRead(r, s, shandle.readData)
+ done(s)
+ r.Respond(s)
+ return nil
+ }
+ } else {
+ if h, ok := handle.(HandleReadAller); ok {
+ if shandle.readData == nil {
+ data, err := h.ReadAll(ctx)
+ if err != nil {
+ return err
+ }
+ if data == nil {
+ data = []byte{}
+ }
+ shandle.readData = data
+ }
+ fuseutil.HandleRead(r, s, shandle.readData)
+ done(s)
+ r.Respond(s)
+ return nil
+ }
+ h, ok := handle.(HandleReader)
+ if !ok {
+ err := handleNotReaderError{handle: handle}
+ return err
+ }
+ if err := h.Read(ctx, r, s); err != nil {
+ return err
+ }
+ }
+ done(s)
+ r.Respond(s)
+ return nil
+
+ case *fuse.WriteRequest:
+ shandle := c.getHandle(r.Handle)
+ if shandle == nil {
+ return fuse.ESTALE
+ }
+
+ s := &fuse.WriteResponse{}
+ if h, ok := shandle.handle.(HandleWriter); ok {
+ if err := h.Write(ctx, r, s); err != nil {
+ return err
+ }
+ done(s)
+ r.Respond(s)
+ return nil
+ }
+ return fuse.EIO
+
+ case *fuse.FlushRequest:
+ shandle := c.getHandle(r.Handle)
+ if shandle == nil {
+ return fuse.ESTALE
+ }
+ handle := shandle.handle
+
+ if h, ok := handle.(HandleFlusher); ok {
+ if err := h.Flush(ctx, r); err != nil {
+ return err
+ }
+ }
+ done(nil)
+ r.Respond()
+ return nil
+
+ case *fuse.ReleaseRequest:
+ shandle := c.getHandle(r.Handle)
+ if shandle == nil {
+ return fuse.ESTALE
+ }
+ handle := shandle.handle
+
+ // No matter what, release the handle.
+ c.dropHandle(r.Handle)
+
+ if h, ok := handle.(HandleReleaser); ok {
+ if err := h.Release(ctx, r); err != nil {
+ return err
+ }
+ }
+ done(nil)
+ r.Respond()
+ return nil
+
+ case *fuse.DestroyRequest:
+ if fs, ok := c.fs.(FSDestroyer); ok {
+ fs.Destroy()
+ }
+ done(nil)
+ r.Respond()
+ return nil
+
+ case *fuse.RenameRequest:
+ c.meta.Lock()
+ var newDirNode *serveNode
+ if int(r.NewDir) < len(c.node) {
+ newDirNode = c.node[r.NewDir]
+ }
+ c.meta.Unlock()
+ if newDirNode == nil {
+ c.debug(renameNewDirNodeNotFound{
+ Request: r.Hdr(),
+ In: r,
+ })
+ return fuse.EIO
+ }
+ n, ok := node.(NodeRenamer)
+ if !ok {
+ return fuse.EIO // XXX or EPERM like Mkdir?
+ }
+ err := n.Rename(ctx, r, newDirNode.node)
+ if err != nil {
+ return err
+ }
+ done(nil)
+ r.Respond()
+ return nil
+
+ case *fuse.MknodRequest:
+ n, ok := node.(NodeMknoder)
+ if !ok {
+ return fuse.EIO
+ }
+ n2, err := n.Mknod(ctx, r)
+ if err != nil {
+ return err
+ }
+ s := &fuse.LookupResponse{}
+ initLookupResponse(s)
+ if err := c.saveLookup(ctx, s, snode, r.Name, n2); err != nil {
+ return err
+ }
+ done(s)
+ r.Respond(s)
+ return nil
+
+ case *fuse.FsyncRequest:
+ n, ok := node.(NodeFsyncer)
+ if !ok {
+ return fuse.EIO
+ }
+ err := n.Fsync(ctx, r)
+ if err != nil {
+ return err
+ }
+ done(nil)
+ r.Respond()
+ return nil
+
+ case *fuse.InterruptRequest:
+ c.meta.Lock()
+ ireq := c.req[r.IntrID]
+ if ireq != nil && ireq.cancel != nil {
+ ireq.cancel()
+ ireq.cancel = nil
+ }
+ c.meta.Unlock()
+ done(nil)
+ r.Respond()
+ return nil
+
+ /* case *FsyncdirRequest:
+ return ENOSYS
+
+ case *GetlkRequest, *SetlkRequest, *SetlkwRequest:
+ return ENOSYS
+
+ case *BmapRequest:
+ return ENOSYS
+
+ case *SetvolnameRequest, *GetxtimesRequest, *ExchangeRequest:
+ return ENOSYS
+ */
+ }
+
+ panic("not reached")
+}
+
+func (c *Server) saveLookup(ctx context.Context, s *fuse.LookupResponse, snode *serveNode, elem string, n2 Node) error {
+ if err := nodeAttr(ctx, n2, &s.Attr); err != nil {
+ return err
+ }
+ if s.Attr.Inode == 0 {
+ s.Attr.Inode = c.dynamicInode(snode.inode, elem)
+ }
+
+ s.Node, s.Generation = c.saveNode(s.Attr.Inode, n2)
+ return nil
+}
+
+type invalidateNodeDetail struct {
+ Off int64
+ Size int64
+}
+
+func (i invalidateNodeDetail) String() string {
+ return fmt.Sprintf("Off:%d Size:%d", i.Off, i.Size)
+}
+
+func errstr(err error) string {
+ if err == nil {
+ return ""
+ }
+ return err.Error()
+}
+
+func (s *Server) invalidateNode(node Node, off int64, size int64) error {
+ s.meta.Lock()
+ id, ok := s.nodeRef[node]
+ if ok {
+ snode := s.node[id]
+ snode.wg.Add(1)
+ defer snode.wg.Done()
+ }
+ s.meta.Unlock()
+ if !ok {
+ // This is what the kernel would have said, if we had been
+ // able to send this message; it's not cached.
+ return fuse.ErrNotCached
+ }
+ // Delay logging until after we can record the error too. We
+ // consider a /dev/fuse write to be instantaneous enough to not
+ // need separate before and after messages.
+ err := s.conn.InvalidateNode(id, off, size)
+ s.debug(notification{
+ Op: "InvalidateNode",
+ Node: id,
+ Out: invalidateNodeDetail{
+ Off: off,
+ Size: size,
+ },
+ Err: errstr(err),
+ })
+ return err
+}
+
+// InvalidateNodeAttr invalidates the kernel cache of the attributes
+// of node.
+//
+// Returns fuse.ErrNotCached if the kernel is not currently caching
+// the node.
+func (s *Server) InvalidateNodeAttr(node Node) error {
+ return s.invalidateNode(node, 0, 0)
+}
+
+// InvalidateNodeData invalidates the kernel cache of the attributes
+// and data of node.
+//
+// Returns fuse.ErrNotCached if the kernel is not currently caching
+// the node.
+func (s *Server) InvalidateNodeData(node Node) error {
+ return s.invalidateNode(node, 0, -1)
+}
+
+// InvalidateNodeDataRange invalidates the kernel cache of the
+// attributes and a range of the data of node.
+//
+// Returns fuse.ErrNotCached if the kernel is not currently caching
+// the node.
+func (s *Server) InvalidateNodeDataRange(node Node, off int64, size int64) error {
+ return s.invalidateNode(node, off, size)
+}
+
+type invalidateEntryDetail struct {
+ Name string
+}
+
+func (i invalidateEntryDetail) String() string {
+ return fmt.Sprintf("%q", i.Name)
+}
+
+// InvalidateEntry invalidates the kernel cache of the directory entry
+// identified by parent node and entry basename.
+//
+// Kernel may or may not cache directory listings. To invalidate
+// those, use InvalidateNode to invalidate all of the data for a
+// directory. (As of 2015-06, Linux FUSE does not cache directory
+// listings.)
+//
+// Returns ErrNotCached if the kernel is not currently caching the
+// node.
+func (s *Server) InvalidateEntry(parent Node, name string) error {
+ s.meta.Lock()
+ id, ok := s.nodeRef[parent]
+ if ok {
+ snode := s.node[id]
+ snode.wg.Add(1)
+ defer snode.wg.Done()
+ }
+ s.meta.Unlock()
+ if !ok {
+ // This is what the kernel would have said, if we had been
+ // able to send this message; it's not cached.
+ return fuse.ErrNotCached
+ }
+ err := s.conn.InvalidateEntry(id, name)
+ s.debug(notification{
+ Op: "InvalidateEntry",
+ Node: id,
+ Out: invalidateEntryDetail{
+ Name: name,
+ },
+ Err: errstr(err),
+ })
+ return err
+}
+
+// DataHandle returns a read-only Handle that satisfies reads
+// using the given data.
+func DataHandle(data []byte) Handle {
+ return &dataHandle{data}
+}
+
+type dataHandle struct {
+ data []byte
+}
+
+func (d *dataHandle) ReadAll(ctx context.Context) ([]byte, error) {
+ return d.data, nil
+}
+
+// GenerateDynamicInode returns a dynamic inode.
+//
+// The parent inode and current entry name are used as the criteria
+// for choosing a pseudorandom inode. This makes it likely the same
+// entry will get the same inode on multiple runs.
+func GenerateDynamicInode(parent uint64, name string) uint64 {
+ h := fnv.New64a()
+ var buf [8]byte
+ binary.LittleEndian.PutUint64(buf[:], parent)
+ _, _ = h.Write(buf[:])
+ _, _ = h.Write([]byte(name))
+ var inode uint64
+ for {
+ inode = h.Sum64()
+ if inode != 0 {
+ break
+ }
+ // there's a tiny probability that result is zero; change the
+ // input a little and try again
+ _, _ = h.Write([]byte{'x'})
+ }
+ return inode
+}
diff --git a/vendor/bazil.org/fuse/fs/tree.go b/vendor/bazil.org/fuse/fs/tree.go
new file mode 100644
index 00000000..7e078045
--- /dev/null
+++ b/vendor/bazil.org/fuse/fs/tree.go
@@ -0,0 +1,99 @@
+// FUSE directory tree, for servers that wish to use it with the service loop.
+
+package fs
+
+import (
+ "os"
+ pathpkg "path"
+ "strings"
+
+ "golang.org/x/net/context"
+)
+
+import (
+ "bazil.org/fuse"
+)
+
+// A Tree implements a basic read-only directory tree for FUSE.
+// The Nodes contained in it may still be writable.
+type Tree struct {
+ tree
+}
+
+func (t *Tree) Root() (Node, error) {
+ return &t.tree, nil
+}
+
+// Add adds the path to the tree, resolving to the given node.
+// If path or a prefix of path has already been added to the tree,
+// Add panics.
+//
+// Add is only safe to call before starting to serve requests.
+func (t *Tree) Add(path string, node Node) {
+ path = pathpkg.Clean("/" + path)[1:]
+ elems := strings.Split(path, "/")
+ dir := Node(&t.tree)
+ for i, elem := range elems {
+ dt, ok := dir.(*tree)
+ if !ok {
+ panic("fuse: Tree.Add for " + strings.Join(elems[:i], "/") + " and " + path)
+ }
+ n := dt.lookup(elem)
+ if n != nil {
+ if i+1 == len(elems) {
+ panic("fuse: Tree.Add for " + path + " conflicts with " + elem)
+ }
+ dir = n
+ } else {
+ if i+1 == len(elems) {
+ dt.add(elem, node)
+ } else {
+ dir = &tree{}
+ dt.add(elem, dir)
+ }
+ }
+ }
+}
+
+type treeDir struct {
+ name string
+ node Node
+}
+
+type tree struct {
+ dir []treeDir
+}
+
+func (t *tree) lookup(name string) Node {
+ for _, d := range t.dir {
+ if d.name == name {
+ return d.node
+ }
+ }
+ return nil
+}
+
+func (t *tree) add(name string, n Node) {
+ t.dir = append(t.dir, treeDir{name, n})
+}
+
+func (t *tree) Attr(ctx context.Context, a *fuse.Attr) error {
+ a.Mode = os.ModeDir | 0555
+ return nil
+}
+
+func (t *tree) Lookup(ctx context.Context, name string) (Node, error) {
+ n := t.lookup(name)
+ if n != nil {
+ return n, nil
+ }
+ return nil, fuse.ENOENT
+}
+
+func (t *tree) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
+ var out []fuse.Dirent
+ for _, d := range t.dir {
+ out = append(out, fuse.Dirent{Name: d.name})
+ }
+ return out, nil
+}
diff --git a/vendor/bazil.org/fuse/fuse.go b/vendor/bazil.org/fuse/fuse.go
new file mode 100644
index 00000000..7dc70f9e
--- /dev/null
+++ b/vendor/bazil.org/fuse/fuse.go
@@ -0,0 +1,2304 @@
+// See the file LICENSE for copyright and licensing information.
+
+// Adapted from Plan 9 from User Space's src/cmd/9pfuse/fuse.c,
+// which carries this notice:
+//
+// The files in this directory are subject to the following license.
+//
+// The author of this software is Russ Cox.
+//
+// Copyright (c) 2006 Russ Cox
+//
+// Permission to use, copy, modify, and distribute this software for any
+// purpose without fee is hereby granted, provided that this entire notice
+// is included in all copies of any software which is or includes a copy
+// or modification of this software and in all copies of the supporting
+// documentation for such software.
+//
+// THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+// WARRANTY. IN PARTICULAR, THE AUTHOR MAKES NO REPRESENTATION OR WARRANTY
+// OF ANY KIND CONCERNING THE MERCHANTABILITY OF THIS SOFTWARE OR ITS
+// FITNESS FOR ANY PARTICULAR PURPOSE.
+
+// Package fuse enables writing FUSE file systems on Linux, OS X, and FreeBSD.
+//
+// On OS X, it requires OSXFUSE (http://osxfuse.github.com/).
+//
+// There are two approaches to writing a FUSE file system. The first is to speak
+// the low-level message protocol, reading from a Conn using ReadRequest and
+// writing using the various Respond methods. This approach is closest to
+// the actual interaction with the kernel and can be the simplest one in contexts
+// such as protocol translators.
+//
+// Servers of synthesized file systems tend to share common
+// bookkeeping abstracted away by the second approach, which is to
+// call fs.Serve to serve the FUSE protocol using an implementation of
+// the service methods in the interfaces FS* (file system), Node* (file
+// or directory), and Handle* (opened file or directory).
+// There are a daunting number of such methods that can be written,
+// but few are required.
+// The specific methods are described in the documentation for those interfaces.
+//
+// The hellofs subdirectory contains a simple illustration of the fs.Serve approach.
+//
+// Service Methods
+//
+// The required and optional methods for the FS, Node, and Handle interfaces
+// have the general form
+//
+// Op(ctx context.Context, req *OpRequest, resp *OpResponse) error
+//
+// where Op is the name of a FUSE operation. Op reads request
+// parameters from req and writes results to resp. An operation whose
+// only result is the error result omits the resp parameter.
+//
+// Multiple goroutines may call service methods simultaneously; the
+// methods being called are responsible for appropriate
+// synchronization.
+//
+// The operation must not hold on to the request or response,
+// including any []byte fields such as WriteRequest.Data or
+// SetxattrRequest.Xattr.
+//
+// Errors
+//
+// Operations can return errors. The FUSE interface can only
+// communicate POSIX errno error numbers to file system clients, the
+// message is not visible to file system clients. The returned error
+// can implement ErrorNumber to control the errno returned. Without
+// ErrorNumber, a generic errno (EIO) is returned.
+//
+// Error messages will be visible in the debug log as part of the
+// response.
+//
+// Interrupted Operations
+//
+// In some file systems, some operations
+// may take an undetermined amount of time. For example, a Read waiting for
+// a network message or a matching Write might wait indefinitely. If the request
+// is cancelled and no longer needed, the context will be cancelled.
+// Blocking operations should select on a receive from ctx.Done() and attempt to
+// abort the operation early if the receive succeeds (meaning the channel is closed).
+// To indicate that the operation failed because it was aborted, return fuse.EINTR.
+//
+// If an operation does not block for an indefinite amount of time, supporting
+// cancellation is not necessary.
+//
+// Authentication
+//
+// All requests types embed a Header, meaning that the method can
+// inspect req.Pid, req.Uid, and req.Gid as necessary to implement
+// permission checking. The kernel FUSE layer normally prevents other
+// users from accessing the FUSE file system (to change this, see
+// AllowOther, AllowRoot), but does not enforce access modes (to
+// change this, see DefaultPermissions).
+//
+// Mount Options
+//
+// Behavior and metadata of the mounted file system can be changed by
+// passing MountOption values to Mount.
+//
+package fuse // import "bazil.org/fuse"
+
+import (
+ "bytes"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io"
+ "os"
+ "sync"
+ "syscall"
+ "time"
+ "unsafe"
+)
+
+// A Conn represents a connection to a mounted FUSE file system.
+type Conn struct {
+ // Ready is closed when the mount is complete or has failed.
+ Ready <-chan struct{}
+
+ // MountError stores any error from the mount process. Only valid
+ // after Ready is closed.
+ MountError error
+
+ // File handle for kernel communication. Only safe to access if
+ // rio or wio is held.
+ dev *os.File
+ wio sync.RWMutex
+ rio sync.RWMutex
+
+ // Protocol version negotiated with InitRequest/InitResponse.
+ proto Protocol
+}
+
+// MountpointDoesNotExistError is an error returned when the
+// mountpoint does not exist.
+type MountpointDoesNotExistError struct {
+ Path string
+}
+
+var _ error = (*MountpointDoesNotExistError)(nil)
+
+func (e *MountpointDoesNotExistError) Error() string {
+ return fmt.Sprintf("mountpoint does not exist: %v", e.Path)
+}
+
+// Mount mounts a new FUSE connection on the named directory
+// and returns a connection for reading and writing FUSE messages.
+//
+// After a successful return, caller must call Close to free
+// resources.
+//
+// Even on successful return, the new mount is not guaranteed to be
+// visible until after Conn.Ready is closed. See Conn.MountError for
+// possible errors. Incoming requests on Conn must be served to make
+// progress.
+func Mount(dir string, options ...MountOption) (*Conn, error) {
+ conf := mountConfig{
+ options: make(map[string]string),
+ }
+ for _, option := range options {
+ if err := option(&conf); err != nil {
+ return nil, err
+ }
+ }
+
+ ready := make(chan struct{}, 1)
+ c := &Conn{
+ Ready: ready,
+ }
+ f, err := mount(dir, &conf, ready, &c.MountError)
+ if err != nil {
+ return nil, err
+ }
+ c.dev = f
+
+ if err := initMount(c, &conf); err != nil {
+ c.Close()
+ if err == ErrClosedWithoutInit {
+ // see if we can provide a better error
+ <-c.Ready
+ if err := c.MountError; err != nil {
+ return nil, err
+ }
+ }
+ return nil, err
+ }
+
+ return c, nil
+}
+
+type OldVersionError struct {
+ Kernel Protocol
+ LibraryMin Protocol
+}
+
+func (e *OldVersionError) Error() string {
+ return fmt.Sprintf("kernel FUSE version is too old: %v < %v", e.Kernel, e.LibraryMin)
+}
+
+var (
+ ErrClosedWithoutInit = errors.New("fuse connection closed without init")
+)
+
+func initMount(c *Conn, conf *mountConfig) error {
+ req, err := c.ReadRequest()
+ if err != nil {
+ if err == io.EOF {
+ return ErrClosedWithoutInit
+ }
+ return err
+ }
+ r, ok := req.(*InitRequest)
+ if !ok {
+ return fmt.Errorf("missing init, got: %T", req)
+ }
+
+ min := Protocol{protoVersionMinMajor, protoVersionMinMinor}
+ if r.Kernel.LT(min) {
+ req.RespondError(Errno(syscall.EPROTO))
+ c.Close()
+ return &OldVersionError{
+ Kernel: r.Kernel,
+ LibraryMin: min,
+ }
+ }
+
+ proto := Protocol{protoVersionMaxMajor, protoVersionMaxMinor}
+ if r.Kernel.LT(proto) {
+ // Kernel doesn't support the latest version we have.
+ proto = r.Kernel
+ }
+ c.proto = proto
+
+ s := &InitResponse{
+ Library: proto,
+ MaxReadahead: conf.maxReadahead,
+ MaxWrite: maxWrite,
+ Flags: InitBigWrites | conf.initFlags,
+ }
+ r.Respond(s)
+ return nil
+}
+
+// A Request represents a single FUSE request received from the kernel.
+// Use a type switch to determine the specific kind.
+// A request of unrecognized type will have concrete type *Header.
+type Request interface {
+ // Hdr returns the Header associated with this request.
+ Hdr() *Header
+
+ // RespondError responds to the request with the given error.
+ RespondError(error)
+
+ String() string
+}
+
+// A RequestID identifies an active FUSE request.
+type RequestID uint64
+
+func (r RequestID) String() string {
+ return fmt.Sprintf("%#x", uint64(r))
+}
+
+// A NodeID is a number identifying a directory or file.
+// It must be unique among IDs returned in LookupResponses
+// that have not yet been forgotten by ForgetRequests.
+type NodeID uint64
+
+func (n NodeID) String() string {
+ return fmt.Sprintf("%#x", uint64(n))
+}
+
+// A HandleID is a number identifying an open directory or file.
+// It only needs to be unique while the directory or file is open.
+type HandleID uint64
+
+func (h HandleID) String() string {
+ return fmt.Sprintf("%#x", uint64(h))
+}
+
+// The RootID identifies the root directory of a FUSE file system.
+const RootID NodeID = rootID
+
+// A Header describes the basic information sent in every request.
+type Header struct {
+ Conn *Conn `json:"-"` // connection this request was received on
+ ID RequestID // unique ID for request
+ Node NodeID // file or directory the request is about
+ Uid uint32 // user ID of process making request
+ Gid uint32 // group ID of process making request
+ Pid uint32 // process ID of process making request
+
+ // for returning to reqPool
+ msg *message
+}
+
+func (h *Header) String() string {
+ return fmt.Sprintf("ID=%v Node=%v Uid=%d Gid=%d Pid=%d", h.ID, h.Node, h.Uid, h.Gid, h.Pid)
+}
+
+func (h *Header) Hdr() *Header {
+ return h
+}
+
+func (h *Header) noResponse() {
+ putMessage(h.msg)
+}
+
+func (h *Header) respond(msg []byte) {
+ out := (*outHeader)(unsafe.Pointer(&msg[0]))
+ out.Unique = uint64(h.ID)
+ h.Conn.respond(msg)
+ putMessage(h.msg)
+}
+
+// An ErrorNumber is an error with a specific error number.
+//
+// Operations may return an error value that implements ErrorNumber to
+// control what specific error number (errno) to return.
+type ErrorNumber interface {
+ // Errno returns the the error number (errno) for this error.
+ Errno() Errno
+}
+
+const (
+ // ENOSYS indicates that the call is not supported.
+ ENOSYS = Errno(syscall.ENOSYS)
+
+ // ESTALE is used by Serve to respond to violations of the FUSE protocol.
+ ESTALE = Errno(syscall.ESTALE)
+
+ ENOENT = Errno(syscall.ENOENT)
+ EIO = Errno(syscall.EIO)
+ EPERM = Errno(syscall.EPERM)
+
+ // EINTR indicates request was interrupted by an InterruptRequest.
+ // See also fs.Intr.
+ EINTR = Errno(syscall.EINTR)
+
+ ERANGE = Errno(syscall.ERANGE)
+ ENOTSUP = Errno(syscall.ENOTSUP)
+ EEXIST = Errno(syscall.EEXIST)
+)
+
+// DefaultErrno is the errno used when error returned does not
+// implement ErrorNumber.
+const DefaultErrno = EIO
+
+var errnoNames = map[Errno]string{
+ ENOSYS: "ENOSYS",
+ ESTALE: "ESTALE",
+ ENOENT: "ENOENT",
+ EIO: "EIO",
+ EPERM: "EPERM",
+ EINTR: "EINTR",
+ EEXIST: "EEXIST",
+}
+
+// Errno implements Error and ErrorNumber using a syscall.Errno.
+type Errno syscall.Errno
+
+var _ = ErrorNumber(Errno(0))
+var _ = error(Errno(0))
+
+func (e Errno) Errno() Errno {
+ return e
+}
+
+func (e Errno) String() string {
+ return syscall.Errno(e).Error()
+}
+
+func (e Errno) Error() string {
+ return syscall.Errno(e).Error()
+}
+
+// ErrnoName returns the short non-numeric identifier for this errno.
+// For example, "EIO".
+func (e Errno) ErrnoName() string {
+ s := errnoNames[e]
+ if s == "" {
+ s = fmt.Sprint(e.Errno())
+ }
+ return s
+}
+
+func (e Errno) MarshalText() ([]byte, error) {
+ s := e.ErrnoName()
+ return []byte(s), nil
+}
+
+func (h *Header) RespondError(err error) {
+ errno := DefaultErrno
+ if ferr, ok := err.(ErrorNumber); ok {
+ errno = ferr.Errno()
+ }
+ // FUSE uses negative errors!
+ // TODO: File bug report against OSXFUSE: positive error causes kernel panic.
+ buf := newBuffer(0)
+ hOut := (*outHeader)(unsafe.Pointer(&buf[0]))
+ hOut.Error = -int32(errno)
+ h.respond(buf)
+}
+
+// All requests read from the kernel, without data, are shorter than
+// this.
+var maxRequestSize = syscall.Getpagesize()
+var bufSize = maxRequestSize + maxWrite
+
+// reqPool is a pool of messages.
+//
+// Lifetime of a logical message is from getMessage to putMessage.
+// getMessage is called by ReadRequest. putMessage is called by
+// Conn.ReadRequest, Request.Respond, or Request.RespondError.
+//
+// Messages in the pool are guaranteed to have conn and off zeroed,
+// buf allocated and len==bufSize, and hdr set.
+var reqPool = sync.Pool{
+ New: allocMessage,
+}
+
+func allocMessage() interface{} {
+ m := &message{buf: make([]byte, bufSize)}
+ m.hdr = (*inHeader)(unsafe.Pointer(&m.buf[0]))
+ return m
+}
+
+func getMessage(c *Conn) *message {
+ m := reqPool.Get().(*message)
+ m.conn = c
+ return m
+}
+
+func putMessage(m *message) {
+ m.buf = m.buf[:bufSize]
+ m.conn = nil
+ m.off = 0
+ reqPool.Put(m)
+}
+
+// a message represents the bytes of a single FUSE message
+type message struct {
+ conn *Conn
+ buf []byte // all bytes
+ hdr *inHeader // header
+ off int // offset for reading additional fields
+}
+
+func (m *message) len() uintptr {
+ return uintptr(len(m.buf) - m.off)
+}
+
+func (m *message) data() unsafe.Pointer {
+ var p unsafe.Pointer
+ if m.off < len(m.buf) {
+ p = unsafe.Pointer(&m.buf[m.off])
+ }
+ return p
+}
+
+func (m *message) bytes() []byte {
+ return m.buf[m.off:]
+}
+
+func (m *message) Header() Header {
+ h := m.hdr
+ return Header{
+ Conn: m.conn,
+ ID: RequestID(h.Unique),
+ Node: NodeID(h.Nodeid),
+ Uid: h.Uid,
+ Gid: h.Gid,
+ Pid: h.Pid,
+
+ msg: m,
+ }
+}
+
+// fileMode returns a Go os.FileMode from a Unix mode.
+func fileMode(unixMode uint32) os.FileMode {
+ mode := os.FileMode(unixMode & 0777)
+ switch unixMode & syscall.S_IFMT {
+ case syscall.S_IFREG:
+ // nothing
+ case syscall.S_IFDIR:
+ mode |= os.ModeDir
+ case syscall.S_IFCHR:
+ mode |= os.ModeCharDevice | os.ModeDevice
+ case syscall.S_IFBLK:
+ mode |= os.ModeDevice
+ case syscall.S_IFIFO:
+ mode |= os.ModeNamedPipe
+ case syscall.S_IFLNK:
+ mode |= os.ModeSymlink
+ case syscall.S_IFSOCK:
+ mode |= os.ModeSocket
+ default:
+ // no idea
+ mode |= os.ModeDevice
+ }
+ if unixMode&syscall.S_ISUID != 0 {
+ mode |= os.ModeSetuid
+ }
+ if unixMode&syscall.S_ISGID != 0 {
+ mode |= os.ModeSetgid
+ }
+ return mode
+}
+
+type noOpcode struct {
+ Opcode uint32
+}
+
+func (m noOpcode) String() string {
+ return fmt.Sprintf("No opcode %v", m.Opcode)
+}
+
+type malformedMessage struct {
+}
+
+func (malformedMessage) String() string {
+ return "malformed message"
+}
+
+// Close closes the FUSE connection.
+func (c *Conn) Close() error {
+ c.wio.Lock()
+ defer c.wio.Unlock()
+ c.rio.Lock()
+ defer c.rio.Unlock()
+ return c.dev.Close()
+}
+
+// caller must hold wio or rio
+func (c *Conn) fd() int {
+ return int(c.dev.Fd())
+}
+
+func (c *Conn) Protocol() Protocol {
+ return c.proto
+}
+
+// ReadRequest returns the next FUSE request from the kernel.
+//
+// Caller must call either Request.Respond or Request.RespondError in
+// a reasonable time. Caller must not retain Request after that call.
+func (c *Conn) ReadRequest() (Request, error) {
+ m := getMessage(c)
+loop:
+ c.rio.RLock()
+ n, err := syscall.Read(c.fd(), m.buf)
+ c.rio.RUnlock()
+ if err == syscall.EINTR {
+ // OSXFUSE sends EINTR to userspace when a request interrupt
+ // completed before it got sent to userspace?
+ goto loop
+ }
+ if err != nil && err != syscall.ENODEV {
+ putMessage(m)
+ return nil, err
+ }
+ if n <= 0 {
+ putMessage(m)
+ return nil, io.EOF
+ }
+ m.buf = m.buf[:n]
+
+ if n < inHeaderSize {
+ putMessage(m)
+ return nil, errors.New("fuse: message too short")
+ }
+
+ // FreeBSD FUSE sends a short length in the header
+ // for FUSE_INIT even though the actual read length is correct.
+ if n == inHeaderSize+initInSize && m.hdr.Opcode == opInit && m.hdr.Len < uint32(n) {
+ m.hdr.Len = uint32(n)
+ }
+
+ // OSXFUSE sometimes sends the wrong m.hdr.Len in a FUSE_WRITE message.
+ if m.hdr.Len < uint32(n) && m.hdr.Len >= uint32(unsafe.Sizeof(writeIn{})) && m.hdr.Opcode == opWrite {
+ m.hdr.Len = uint32(n)
+ }
+
+ if m.hdr.Len != uint32(n) {
+ // prepare error message before returning m to pool
+ err := fmt.Errorf("fuse: read %d opcode %d but expected %d", n, m.hdr.Opcode, m.hdr.Len)
+ putMessage(m)
+ return nil, err
+ }
+
+ m.off = inHeaderSize
+
+ // Convert to data structures.
+ // Do not trust kernel to hand us well-formed data.
+ var req Request
+ switch m.hdr.Opcode {
+ default:
+ Debug(noOpcode{Opcode: m.hdr.Opcode})
+ goto unrecognized
+
+ case opLookup:
+ buf := m.bytes()
+ n := len(buf)
+ if n == 0 || buf[n-1] != '\x00' {
+ goto corrupt
+ }
+ req = &LookupRequest{
+ Header: m.Header(),
+ Name: string(buf[:n-1]),
+ }
+
+ case opForget:
+ in := (*forgetIn)(m.data())
+ if m.len() < unsafe.Sizeof(*in) {
+ goto corrupt
+ }
+ req = &ForgetRequest{
+ Header: m.Header(),
+ N: in.Nlookup,
+ }
+
+ case opGetattr:
+ switch {
+ case c.proto.LT(Protocol{7, 9}):
+ req = &GetattrRequest{
+ Header: m.Header(),
+ }
+
+ default:
+ in := (*getattrIn)(m.data())
+ if m.len() < unsafe.Sizeof(*in) {
+ goto corrupt
+ }
+ req = &GetattrRequest{
+ Header: m.Header(),
+ Flags: GetattrFlags(in.GetattrFlags),
+ Handle: HandleID(in.Fh),
+ }
+ }
+
+ case opSetattr:
+ in := (*setattrIn)(m.data())
+ if m.len() < unsafe.Sizeof(*in) {
+ goto corrupt
+ }
+ req = &SetattrRequest{
+ Header: m.Header(),
+ Valid: SetattrValid(in.Valid),
+ Handle: HandleID(in.Fh),
+ Size: in.Size,
+ Atime: time.Unix(int64(in.Atime), int64(in.AtimeNsec)),
+ Mtime: time.Unix(int64(in.Mtime), int64(in.MtimeNsec)),
+ Mode: fileMode(in.Mode),
+ Uid: in.Uid,
+ Gid: in.Gid,
+ Bkuptime: in.BkupTime(),
+ Chgtime: in.Chgtime(),
+ Flags: in.Flags(),
+ }
+
+ case opReadlink:
+ if len(m.bytes()) > 0 {
+ goto corrupt
+ }
+ req = &ReadlinkRequest{
+ Header: m.Header(),
+ }
+
+ case opSymlink:
+ // m.bytes() is "newName\0target\0"
+ names := m.bytes()
+ if len(names) == 0 || names[len(names)-1] != 0 {
+ goto corrupt
+ }
+ i := bytes.IndexByte(names, '\x00')
+ if i < 0 {
+ goto corrupt
+ }
+ newName, target := names[0:i], names[i+1:len(names)-1]
+ req = &SymlinkRequest{
+ Header: m.Header(),
+ NewName: string(newName),
+ Target: string(target),
+ }
+
+ case opLink:
+ in := (*linkIn)(m.data())
+ if m.len() < unsafe.Sizeof(*in) {
+ goto corrupt
+ }
+ newName := m.bytes()[unsafe.Sizeof(*in):]
+ if len(newName) < 2 || newName[len(newName)-1] != 0 {
+ goto corrupt
+ }
+ newName = newName[:len(newName)-1]
+ req = &LinkRequest{
+ Header: m.Header(),
+ OldNode: NodeID(in.Oldnodeid),
+ NewName: string(newName),
+ }
+
+ case opMknod:
+ size := mknodInSize(c.proto)
+ if m.len() < size {
+ goto corrupt
+ }
+ in := (*mknodIn)(m.data())
+ name := m.bytes()[size:]
+ if len(name) < 2 || name[len(name)-1] != '\x00' {
+ goto corrupt
+ }
+ name = name[:len(name)-1]
+ r := &MknodRequest{
+ Header: m.Header(),
+ Mode: fileMode(in.Mode),
+ Rdev: in.Rdev,
+ Name: string(name),
+ }
+ if c.proto.GE(Protocol{7, 12}) {
+ r.Umask = fileMode(in.Umask) & os.ModePerm
+ }
+ req = r
+
+ case opMkdir:
+ size := mkdirInSize(c.proto)
+ if m.len() < size {
+ goto corrupt
+ }
+ in := (*mkdirIn)(m.data())
+ name := m.bytes()[size:]
+ i := bytes.IndexByte(name, '\x00')
+ if i < 0 {
+ goto corrupt
+ }
+ r := &MkdirRequest{
+ Header: m.Header(),
+ Name: string(name[:i]),
+ // observed on Linux: mkdirIn.Mode & syscall.S_IFMT == 0,
+ // and this causes fileMode to go into it's "no idea"
+ // code branch; enforce type to directory
+ Mode: fileMode((in.Mode &^ syscall.S_IFMT) | syscall.S_IFDIR),
+ }
+ if c.proto.GE(Protocol{7, 12}) {
+ r.Umask = fileMode(in.Umask) & os.ModePerm
+ }
+ req = r
+
+ case opUnlink, opRmdir:
+ buf := m.bytes()
+ n := len(buf)
+ if n == 0 || buf[n-1] != '\x00' {
+ goto corrupt
+ }
+ req = &RemoveRequest{
+ Header: m.Header(),
+ Name: string(buf[:n-1]),
+ Dir: m.hdr.Opcode == opRmdir,
+ }
+
+ case opRename:
+ in := (*renameIn)(m.data())
+ if m.len() < unsafe.Sizeof(*in) {
+ goto corrupt
+ }
+ newDirNodeID := NodeID(in.Newdir)
+ oldNew := m.bytes()[unsafe.Sizeof(*in):]
+ // oldNew should be "old\x00new\x00"
+ if len(oldNew) < 4 {
+ goto corrupt
+ }
+ if oldNew[len(oldNew)-1] != '\x00' {
+ goto corrupt
+ }
+ i := bytes.IndexByte(oldNew, '\x00')
+ if i < 0 {
+ goto corrupt
+ }
+ oldName, newName := string(oldNew[:i]), string(oldNew[i+1:len(oldNew)-1])
+ req = &RenameRequest{
+ Header: m.Header(),
+ NewDir: newDirNodeID,
+ OldName: oldName,
+ NewName: newName,
+ }
+
+ case opOpendir, opOpen:
+ in := (*openIn)(m.data())
+ if m.len() < unsafe.Sizeof(*in) {
+ goto corrupt
+ }
+ req = &OpenRequest{
+ Header: m.Header(),
+ Dir: m.hdr.Opcode == opOpendir,
+ Flags: openFlags(in.Flags),
+ }
+
+ case opRead, opReaddir:
+ in := (*readIn)(m.data())
+ if m.len() < readInSize(c.proto) {
+ goto corrupt
+ }
+ r := &ReadRequest{
+ Header: m.Header(),
+ Dir: m.hdr.Opcode == opReaddir,
+ Handle: HandleID(in.Fh),
+ Offset: int64(in.Offset),
+ Size: int(in.Size),
+ }
+ if c.proto.GE(Protocol{7, 9}) {
+ r.Flags = ReadFlags(in.ReadFlags)
+ r.LockOwner = in.LockOwner
+ r.FileFlags = openFlags(in.Flags)
+ }
+ req = r
+
+ case opWrite:
+ in := (*writeIn)(m.data())
+ if m.len() < writeInSize(c.proto) {
+ goto corrupt
+ }
+ r := &WriteRequest{
+ Header: m.Header(),
+ Handle: HandleID(in.Fh),
+ Offset: int64(in.Offset),
+ Flags: WriteFlags(in.WriteFlags),
+ }
+ if c.proto.GE(Protocol{7, 9}) {
+ r.LockOwner = in.LockOwner
+ r.FileFlags = openFlags(in.Flags)
+ }
+ buf := m.bytes()[writeInSize(c.proto):]
+ if uint32(len(buf)) < in.Size {
+ goto corrupt
+ }
+ r.Data = buf
+ req = r
+
+ case opStatfs:
+ req = &StatfsRequest{
+ Header: m.Header(),
+ }
+
+ case opRelease, opReleasedir:
+ in := (*releaseIn)(m.data())
+ if m.len() < unsafe.Sizeof(*in) {
+ goto corrupt
+ }
+ req = &ReleaseRequest{
+ Header: m.Header(),
+ Dir: m.hdr.Opcode == opReleasedir,
+ Handle: HandleID(in.Fh),
+ Flags: openFlags(in.Flags),
+ ReleaseFlags: ReleaseFlags(in.ReleaseFlags),
+ LockOwner: in.LockOwner,
+ }
+
+ case opFsync, opFsyncdir:
+ in := (*fsyncIn)(m.data())
+ if m.len() < unsafe.Sizeof(*in) {
+ goto corrupt
+ }
+ req = &FsyncRequest{
+ Dir: m.hdr.Opcode == opFsyncdir,
+ Header: m.Header(),
+ Handle: HandleID(in.Fh),
+ Flags: in.FsyncFlags,
+ }
+
+ case opSetxattr:
+ in := (*setxattrIn)(m.data())
+ if m.len() < unsafe.Sizeof(*in) {
+ goto corrupt
+ }
+ m.off += int(unsafe.Sizeof(*in))
+ name := m.bytes()
+ i := bytes.IndexByte(name, '\x00')
+ if i < 0 {
+ goto corrupt
+ }
+ xattr := name[i+1:]
+ if uint32(len(xattr)) < in.Size {
+ goto corrupt
+ }
+ xattr = xattr[:in.Size]
+ req = &SetxattrRequest{
+ Header: m.Header(),
+ Flags: in.Flags,
+ Position: in.position(),
+ Name: string(name[:i]),
+ Xattr: xattr,
+ }
+
+ case opGetxattr:
+ in := (*getxattrIn)(m.data())
+ if m.len() < unsafe.Sizeof(*in) {
+ goto corrupt
+ }
+ name := m.bytes()[unsafe.Sizeof(*in):]
+ i := bytes.IndexByte(name, '\x00')
+ if i < 0 {
+ goto corrupt
+ }
+ req = &GetxattrRequest{
+ Header: m.Header(),
+ Name: string(name[:i]),
+ Size: in.Size,
+ Position: in.position(),
+ }
+
+ case opListxattr:
+ in := (*getxattrIn)(m.data())
+ if m.len() < unsafe.Sizeof(*in) {
+ goto corrupt
+ }
+ req = &ListxattrRequest{
+ Header: m.Header(),
+ Size: in.Size,
+ Position: in.position(),
+ }
+
+ case opRemovexattr:
+ buf := m.bytes()
+ n := len(buf)
+ if n == 0 || buf[n-1] != '\x00' {
+ goto corrupt
+ }
+ req = &RemovexattrRequest{
+ Header: m.Header(),
+ Name: string(buf[:n-1]),
+ }
+
+ case opFlush:
+ in := (*flushIn)(m.data())
+ if m.len() < unsafe.Sizeof(*in) {
+ goto corrupt
+ }
+ req = &FlushRequest{
+ Header: m.Header(),
+ Handle: HandleID(in.Fh),
+ Flags: in.FlushFlags,
+ LockOwner: in.LockOwner,
+ }
+
+ case opInit:
+ in := (*initIn)(m.data())
+ if m.len() < unsafe.Sizeof(*in) {
+ goto corrupt
+ }
+ req = &InitRequest{
+ Header: m.Header(),
+ Kernel: Protocol{in.Major, in.Minor},
+ MaxReadahead: in.MaxReadahead,
+ Flags: InitFlags(in.Flags),
+ }
+
+ case opGetlk:
+ panic("opGetlk")
+ case opSetlk:
+ panic("opSetlk")
+ case opSetlkw:
+ panic("opSetlkw")
+
+ case opAccess:
+ in := (*accessIn)(m.data())
+ if m.len() < unsafe.Sizeof(*in) {
+ goto corrupt
+ }
+ req = &AccessRequest{
+ Header: m.Header(),
+ Mask: in.Mask,
+ }
+
+ case opCreate:
+ size := createInSize(c.proto)
+ if m.len() < size {
+ goto corrupt
+ }
+ in := (*createIn)(m.data())
+ name := m.bytes()[size:]
+ i := bytes.IndexByte(name, '\x00')
+ if i < 0 {
+ goto corrupt
+ }
+ r := &CreateRequest{
+ Header: m.Header(),
+ Flags: openFlags(in.Flags),
+ Mode: fileMode(in.Mode),
+ Name: string(name[:i]),
+ }
+ if c.proto.GE(Protocol{7, 12}) {
+ r.Umask = fileMode(in.Umask) & os.ModePerm
+ }
+ req = r
+
+ case opInterrupt:
+ in := (*interruptIn)(m.data())
+ if m.len() < unsafe.Sizeof(*in) {
+ goto corrupt
+ }
+ req = &InterruptRequest{
+ Header: m.Header(),
+ IntrID: RequestID(in.Unique),
+ }
+
+ case opBmap:
+ panic("opBmap")
+
+ case opDestroy:
+ req = &DestroyRequest{
+ Header: m.Header(),
+ }
+
+ // OS X
+ case opSetvolname:
+ panic("opSetvolname")
+ case opGetxtimes:
+ panic("opGetxtimes")
+ case opExchange:
+ in := (*exchangeIn)(m.data())
+ if m.len() < unsafe.Sizeof(*in) {
+ goto corrupt
+ }
+ oldDirNodeID := NodeID(in.Olddir)
+ newDirNodeID := NodeID(in.Newdir)
+ oldNew := m.bytes()[unsafe.Sizeof(*in):]
+ // oldNew should be "oldname\x00newname\x00"
+ if len(oldNew) < 4 {
+ goto corrupt
+ }
+ if oldNew[len(oldNew)-1] != '\x00' {
+ goto corrupt
+ }
+ i := bytes.IndexByte(oldNew, '\x00')
+ if i < 0 {
+ goto corrupt
+ }
+ oldName, newName := string(oldNew[:i]), string(oldNew[i+1:len(oldNew)-1])
+ req = &ExchangeDataRequest{
+ Header: m.Header(),
+ OldDir: oldDirNodeID,
+ NewDir: newDirNodeID,
+ OldName: oldName,
+ NewName: newName,
+ // TODO options
+ }
+ }
+
+ return req, nil
+
+corrupt:
+ Debug(malformedMessage{})
+ putMessage(m)
+ return nil, fmt.Errorf("fuse: malformed message")
+
+unrecognized:
+ // Unrecognized message.
+ // Assume higher-level code will send a "no idea what you mean" error.
+ h := m.Header()
+ return &h, nil
+}
+
+type bugShortKernelWrite struct {
+ Written int64
+ Length int64
+ Error string
+ Stack string
+}
+
+func (b bugShortKernelWrite) String() string {
+ return fmt.Sprintf("short kernel write: written=%d/%d error=%q stack=\n%s", b.Written, b.Length, b.Error, b.Stack)
+}
+
+type bugKernelWriteError struct {
+ Error string
+ Stack string
+}
+
+func (b bugKernelWriteError) String() string {
+ return fmt.Sprintf("kernel write error: error=%q stack=\n%s", b.Error, b.Stack)
+}
+
+// safe to call even with nil error
+func errorString(err error) string {
+ if err == nil {
+ return ""
+ }
+ return err.Error()
+}
+
+func (c *Conn) writeToKernel(msg []byte) error {
+ out := (*outHeader)(unsafe.Pointer(&msg[0]))
+ out.Len = uint32(len(msg))
+
+ c.wio.RLock()
+ defer c.wio.RUnlock()
+ nn, err := syscall.Write(c.fd(), msg)
+ if err == nil && nn != len(msg) {
+ Debug(bugShortKernelWrite{
+ Written: int64(nn),
+ Length: int64(len(msg)),
+ Error: errorString(err),
+ Stack: stack(),
+ })
+ }
+ return err
+}
+
+func (c *Conn) respond(msg []byte) {
+ if err := c.writeToKernel(msg); err != nil {
+ Debug(bugKernelWriteError{
+ Error: errorString(err),
+ Stack: stack(),
+ })
+ }
+}
+
+type notCachedError struct{}
+
+func (notCachedError) Error() string {
+ return "node not cached"
+}
+
+var _ ErrorNumber = notCachedError{}
+
+func (notCachedError) Errno() Errno {
+ // Behave just like if the original syscall.ENOENT had been passed
+ // straight through.
+ return ENOENT
+}
+
+var (
+ ErrNotCached = notCachedError{}
+)
+
+// sendInvalidate sends an invalidate notification to kernel.
+//
+// A returned ENOENT is translated to a friendlier error.
+func (c *Conn) sendInvalidate(msg []byte) error {
+ switch err := c.writeToKernel(msg); err {
+ case syscall.ENOENT:
+ return ErrNotCached
+ default:
+ return err
+ }
+}
+
+// InvalidateNode invalidates the kernel cache of the attributes and a
+// range of the data of a node.
+//
+// Giving offset 0 and size -1 means all data. To invalidate just the
+// attributes, give offset 0 and size 0.
+//
+// Returns ErrNotCached if the kernel is not currently caching the
+// node.
+func (c *Conn) InvalidateNode(nodeID NodeID, off int64, size int64) error {
+ buf := newBuffer(unsafe.Sizeof(notifyInvalInodeOut{}))
+ h := (*outHeader)(unsafe.Pointer(&buf[0]))
+ // h.Unique is 0
+ h.Error = notifyCodeInvalInode
+ out := (*notifyInvalInodeOut)(buf.alloc(unsafe.Sizeof(notifyInvalInodeOut{})))
+ out.Ino = uint64(nodeID)
+ out.Off = off
+ out.Len = size
+ return c.sendInvalidate(buf)
+}
+
+// InvalidateEntry invalidates the kernel cache of the directory entry
+// identified by parent directory node ID and entry basename.
+//
+// Kernel may or may not cache directory listings. To invalidate
+// those, use InvalidateNode to invalidate all of the data for a
+// directory. (As of 2015-06, Linux FUSE does not cache directory
+// listings.)
+//
+// Returns ErrNotCached if the kernel is not currently caching the
+// node.
+func (c *Conn) InvalidateEntry(parent NodeID, name string) error {
+ const maxUint32 = ^uint32(0)
+ if uint64(len(name)) > uint64(maxUint32) {
+ // very unlikely, but we don't want to silently truncate
+ return syscall.ENAMETOOLONG
+ }
+ buf := newBuffer(unsafe.Sizeof(notifyInvalEntryOut{}) + uintptr(len(name)) + 1)
+ h := (*outHeader)(unsafe.Pointer(&buf[0]))
+ // h.Unique is 0
+ h.Error = notifyCodeInvalEntry
+ out := (*notifyInvalEntryOut)(buf.alloc(unsafe.Sizeof(notifyInvalEntryOut{})))
+ out.Parent = uint64(parent)
+ out.Namelen = uint32(len(name))
+ buf = append(buf, name...)
+ buf = append(buf, '\x00')
+ return c.sendInvalidate(buf)
+}
+
+// An InitRequest is the first request sent on a FUSE file system.
+type InitRequest struct {
+ Header `json:"-"`
+ Kernel Protocol
+ // Maximum readahead in bytes that the kernel plans to use.
+ MaxReadahead uint32
+ Flags InitFlags
+}
+
+var _ = Request(&InitRequest{})
+
+func (r *InitRequest) String() string {
+ return fmt.Sprintf("Init [%v] %v ra=%d fl=%v", &r.Header, r.Kernel, r.MaxReadahead, r.Flags)
+}
+
+// An InitResponse is the response to an InitRequest.
+type InitResponse struct {
+ Library Protocol
+ // Maximum readahead in bytes that the kernel can use. Ignored if
+ // greater than InitRequest.MaxReadahead.
+ MaxReadahead uint32
+ Flags InitFlags
+ // Maximum size of a single write operation.
+ // Linux enforces a minimum of 4 KiB.
+ MaxWrite uint32
+}
+
+func (r *InitResponse) String() string {
+ return fmt.Sprintf("Init %v ra=%d fl=%v w=%d", r.Library, r.MaxReadahead, r.Flags, r.MaxWrite)
+}
+
+// Respond replies to the request with the given response.
+func (r *InitRequest) Respond(resp *InitResponse) {
+ buf := newBuffer(unsafe.Sizeof(initOut{}))
+ out := (*initOut)(buf.alloc(unsafe.Sizeof(initOut{})))
+ out.Major = resp.Library.Major
+ out.Minor = resp.Library.Minor
+ out.MaxReadahead = resp.MaxReadahead
+ out.Flags = uint32(resp.Flags)
+ out.MaxWrite = resp.MaxWrite
+
+ // MaxWrite larger than our receive buffer would just lead to
+ // errors on large writes.
+ if out.MaxWrite > maxWrite {
+ out.MaxWrite = maxWrite
+ }
+ r.respond(buf)
+}
+
+// A StatfsRequest requests information about the mounted file system.
+type StatfsRequest struct {
+ Header `json:"-"`
+}
+
+var _ = Request(&StatfsRequest{})
+
+func (r *StatfsRequest) String() string {
+ return fmt.Sprintf("Statfs [%s]", &r.Header)
+}
+
+// Respond replies to the request with the given response.
+func (r *StatfsRequest) Respond(resp *StatfsResponse) {
+ buf := newBuffer(unsafe.Sizeof(statfsOut{}))
+ out := (*statfsOut)(buf.alloc(unsafe.Sizeof(statfsOut{})))
+ out.St = kstatfs{
+ Blocks: resp.Blocks,
+ Bfree: resp.Bfree,
+ Bavail: resp.Bavail,
+ Files: resp.Files,
+ Ffree: resp.Ffree,
+ Bsize: resp.Bsize,
+ Namelen: resp.Namelen,
+ Frsize: resp.Frsize,
+ }
+ r.respond(buf)
+}
+
+// A StatfsResponse is the response to a StatfsRequest.
+type StatfsResponse struct {
+ Blocks uint64 // Total data blocks in file system.
+ Bfree uint64 // Free blocks in file system.
+ Bavail uint64 // Free blocks in file system if you're not root.
+ Files uint64 // Total files in file system.
+ Ffree uint64 // Free files in file system.
+ Bsize uint32 // Block size
+ Namelen uint32 // Maximum file name length?
+ Frsize uint32 // Fragment size, smallest addressable data size in the file system.
+}
+
+func (r *StatfsResponse) String() string {
+ return fmt.Sprintf("Statfs blocks=%d/%d/%d files=%d/%d bsize=%d frsize=%d namelen=%d",
+ r.Bavail, r.Bfree, r.Blocks,
+ r.Ffree, r.Files,
+ r.Bsize,
+ r.Frsize,
+ r.Namelen,
+ )
+}
+
+// An AccessRequest asks whether the file can be accessed
+// for the purpose specified by the mask.
+type AccessRequest struct {
+ Header `json:"-"`
+ Mask uint32
+}
+
+var _ = Request(&AccessRequest{})
+
+func (r *AccessRequest) String() string {
+ return fmt.Sprintf("Access [%s] mask=%#x", &r.Header, r.Mask)
+}
+
+// Respond replies to the request indicating that access is allowed.
+// To deny access, use RespondError.
+func (r *AccessRequest) Respond() {
+ buf := newBuffer(0)
+ r.respond(buf)
+}
+
+// An Attr is the metadata for a single file or directory.
+type Attr struct {
+ Valid time.Duration // how long Attr can be cached
+
+ Inode uint64 // inode number
+ Size uint64 // size in bytes
+ Blocks uint64 // size in 512-byte units
+ Atime time.Time // time of last access
+ Mtime time.Time // time of last modification
+ Ctime time.Time // time of last inode change
+ Crtime time.Time // time of creation (OS X only)
+ Mode os.FileMode // file mode
+ Nlink uint32 // number of links (usually 1)
+ Uid uint32 // owner uid
+ Gid uint32 // group gid
+ Rdev uint32 // device numbers
+ Flags uint32 // chflags(2) flags (OS X only)
+ BlockSize uint32 // preferred blocksize for filesystem I/O
+}
+
+func (a Attr) String() string {
+ return fmt.Sprintf("valid=%v ino=%v size=%d mode=%v", a.Valid, a.Inode, a.Size, a.Mode)
+}
+
+func unix(t time.Time) (sec uint64, nsec uint32) {
+ nano := t.UnixNano()
+ sec = uint64(nano / 1e9)
+ nsec = uint32(nano % 1e9)
+ return
+}
+
+func (a *Attr) attr(out *attr, proto Protocol) {
+ out.Ino = a.Inode
+ out.Size = a.Size
+ out.Blocks = a.Blocks
+ out.Atime, out.AtimeNsec = unix(a.Atime)
+ out.Mtime, out.MtimeNsec = unix(a.Mtime)
+ out.Ctime, out.CtimeNsec = unix(a.Ctime)
+ out.SetCrtime(unix(a.Crtime))
+ out.Mode = uint32(a.Mode) & 0777
+ switch {
+ default:
+ out.Mode |= syscall.S_IFREG
+ case a.Mode&os.ModeDir != 0:
+ out.Mode |= syscall.S_IFDIR
+ case a.Mode&os.ModeDevice != 0:
+ if a.Mode&os.ModeCharDevice != 0 {
+ out.Mode |= syscall.S_IFCHR
+ } else {
+ out.Mode |= syscall.S_IFBLK
+ }
+ case a.Mode&os.ModeNamedPipe != 0:
+ out.Mode |= syscall.S_IFIFO
+ case a.Mode&os.ModeSymlink != 0:
+ out.Mode |= syscall.S_IFLNK
+ case a.Mode&os.ModeSocket != 0:
+ out.Mode |= syscall.S_IFSOCK
+ }
+ if a.Mode&os.ModeSetuid != 0 {
+ out.Mode |= syscall.S_ISUID
+ }
+ if a.Mode&os.ModeSetgid != 0 {
+ out.Mode |= syscall.S_ISGID
+ }
+ out.Nlink = a.Nlink
+ out.Uid = a.Uid
+ out.Gid = a.Gid
+ out.Rdev = a.Rdev
+ out.SetFlags(a.Flags)
+ if proto.GE(Protocol{7, 9}) {
+ out.Blksize = a.BlockSize
+ }
+
+ return
+}
+
+// A GetattrRequest asks for the metadata for the file denoted by r.Node.
+type GetattrRequest struct {
+ Header `json:"-"`
+ Flags GetattrFlags
+ Handle HandleID
+}
+
+var _ = Request(&GetattrRequest{})
+
+func (r *GetattrRequest) String() string {
+ return fmt.Sprintf("Getattr [%s] %v fl=%v", &r.Header, r.Handle, r.Flags)
+}
+
+// Respond replies to the request with the given response.
+func (r *GetattrRequest) Respond(resp *GetattrResponse) {
+ size := attrOutSize(r.Header.Conn.proto)
+ buf := newBuffer(size)
+ out := (*attrOut)(buf.alloc(size))
+ out.AttrValid = uint64(resp.Attr.Valid / time.Second)
+ out.AttrValidNsec = uint32(resp.Attr.Valid % time.Second / time.Nanosecond)
+ resp.Attr.attr(&out.Attr, r.Header.Conn.proto)
+ r.respond(buf)
+}
+
+// A GetattrResponse is the response to a GetattrRequest.
+type GetattrResponse struct {
+ Attr Attr // file attributes
+}
+
+func (r *GetattrResponse) String() string {
+ return fmt.Sprintf("Getattr %v", r.Attr)
+}
+
+// A GetxattrRequest asks for the extended attributes associated with r.Node.
+type GetxattrRequest struct {
+ Header `json:"-"`
+
+ // Maximum size to return.
+ Size uint32
+
+ // Name of the attribute requested.
+ Name string
+
+ // Offset within extended attributes.
+ //
+ // Only valid for OS X, and then only with the resource fork
+ // attribute.
+ Position uint32
+}
+
+var _ = Request(&GetxattrRequest{})
+
+func (r *GetxattrRequest) String() string {
+ return fmt.Sprintf("Getxattr [%s] %q %d @%d", &r.Header, r.Name, r.Size, r.Position)
+}
+
+// Respond replies to the request with the given response.
+func (r *GetxattrRequest) Respond(resp *GetxattrResponse) {
+ if r.Size == 0 {
+ buf := newBuffer(unsafe.Sizeof(getxattrOut{}))
+ out := (*getxattrOut)(buf.alloc(unsafe.Sizeof(getxattrOut{})))
+ out.Size = uint32(len(resp.Xattr))
+ r.respond(buf)
+ } else {
+ buf := newBuffer(uintptr(len(resp.Xattr)))
+ buf = append(buf, resp.Xattr...)
+ r.respond(buf)
+ }
+}
+
+// A GetxattrResponse is the response to a GetxattrRequest.
+type GetxattrResponse struct {
+ Xattr []byte
+}
+
+func (r *GetxattrResponse) String() string {
+ return fmt.Sprintf("Getxattr %x", r.Xattr)
+}
+
+// A ListxattrRequest asks to list the extended attributes associated with r.Node.
+type ListxattrRequest struct {
+ Header `json:"-"`
+ Size uint32 // maximum size to return
+ Position uint32 // offset within attribute list
+}
+
+var _ = Request(&ListxattrRequest{})
+
+func (r *ListxattrRequest) String() string {
+ return fmt.Sprintf("Listxattr [%s] %d @%d", &r.Header, r.Size, r.Position)
+}
+
+// Respond replies to the request with the given response.
+func (r *ListxattrRequest) Respond(resp *ListxattrResponse) {
+ if r.Size == 0 {
+ buf := newBuffer(unsafe.Sizeof(getxattrOut{}))
+ out := (*getxattrOut)(buf.alloc(unsafe.Sizeof(getxattrOut{})))
+ out.Size = uint32(len(resp.Xattr))
+ r.respond(buf)
+ } else {
+ buf := newBuffer(uintptr(len(resp.Xattr)))
+ buf = append(buf, resp.Xattr...)
+ r.respond(buf)
+ }
+}
+
+// A ListxattrResponse is the response to a ListxattrRequest.
+type ListxattrResponse struct {
+ Xattr []byte
+}
+
+func (r *ListxattrResponse) String() string {
+ return fmt.Sprintf("Listxattr %x", r.Xattr)
+}
+
+// Append adds an extended attribute name to the response.
+func (r *ListxattrResponse) Append(names ...string) {
+ for _, name := range names {
+ r.Xattr = append(r.Xattr, name...)
+ r.Xattr = append(r.Xattr, '\x00')
+ }
+}
+
+// A RemovexattrRequest asks to remove an extended attribute associated with r.Node.
+type RemovexattrRequest struct {
+ Header `json:"-"`
+ Name string // name of extended attribute
+}
+
+var _ = Request(&RemovexattrRequest{})
+
+func (r *RemovexattrRequest) String() string {
+ return fmt.Sprintf("Removexattr [%s] %q", &r.Header, r.Name)
+}
+
+// Respond replies to the request, indicating that the attribute was removed.
+func (r *RemovexattrRequest) Respond() {
+ buf := newBuffer(0)
+ r.respond(buf)
+}
+
+// A SetxattrRequest asks to set an extended attribute associated with a file.
+type SetxattrRequest struct {
+ Header `json:"-"`
+
+ // Flags can make the request fail if attribute does/not already
+ // exist. Unfortunately, the constants are platform-specific and
+ // not exposed by Go1.2. Look for XATTR_CREATE, XATTR_REPLACE.
+ //
+ // TODO improve this later
+ //
+ // TODO XATTR_CREATE and exist -> EEXIST
+ //
+ // TODO XATTR_REPLACE and not exist -> ENODATA
+ Flags uint32
+
+ // Offset within extended attributes.
+ //
+ // Only valid for OS X, and then only with the resource fork
+ // attribute.
+ Position uint32
+
+ Name string
+ Xattr []byte
+}
+
+var _ = Request(&SetxattrRequest{})
+
+func trunc(b []byte, max int) ([]byte, string) {
+ if len(b) > max {
+ return b[:max], "..."
+ }
+ return b, ""
+}
+
+func (r *SetxattrRequest) String() string {
+ xattr, tail := trunc(r.Xattr, 16)
+ return fmt.Sprintf("Setxattr [%s] %q %x%s fl=%v @%#x", &r.Header, r.Name, xattr, tail, r.Flags, r.Position)
+}
+
+// Respond replies to the request, indicating that the extended attribute was set.
+func (r *SetxattrRequest) Respond() {
+ buf := newBuffer(0)
+ r.respond(buf)
+}
+
+// A LookupRequest asks to look up the given name in the directory named by r.Node.
+type LookupRequest struct {
+ Header `json:"-"`
+ Name string
+}
+
+var _ = Request(&LookupRequest{})
+
+func (r *LookupRequest) String() string {
+ return fmt.Sprintf("Lookup [%s] %q", &r.Header, r.Name)
+}
+
+// Respond replies to the request with the given response.
+func (r *LookupRequest) Respond(resp *LookupResponse) {
+ size := entryOutSize(r.Header.Conn.proto)
+ buf := newBuffer(size)
+ out := (*entryOut)(buf.alloc(size))
+ out.Nodeid = uint64(resp.Node)
+ out.Generation = resp.Generation
+ out.EntryValid = uint64(resp.EntryValid / time.Second)
+ out.EntryValidNsec = uint32(resp.EntryValid % time.Second / time.Nanosecond)
+ out.AttrValid = uint64(resp.Attr.Valid / time.Second)
+ out.AttrValidNsec = uint32(resp.Attr.Valid % time.Second / time.Nanosecond)
+ resp.Attr.attr(&out.Attr, r.Header.Conn.proto)
+ r.respond(buf)
+}
+
+// A LookupResponse is the response to a LookupRequest.
+type LookupResponse struct {
+ Node NodeID
+ Generation uint64
+ EntryValid time.Duration
+ Attr Attr
+}
+
+func (r *LookupResponse) string() string {
+ return fmt.Sprintf("%v gen=%d valid=%v attr={%v}", r.Node, r.Generation, r.EntryValid, r.Attr)
+}
+
+func (r *LookupResponse) String() string {
+ return fmt.Sprintf("Lookup %s", r.string())
+}
+
+// An OpenRequest asks to open a file or directory
+type OpenRequest struct {
+ Header `json:"-"`
+ Dir bool // is this Opendir?
+ Flags OpenFlags
+}
+
+var _ = Request(&OpenRequest{})
+
+func (r *OpenRequest) String() string {
+ return fmt.Sprintf("Open [%s] dir=%v fl=%v", &r.Header, r.Dir, r.Flags)
+}
+
+// Respond replies to the request with the given response.
+func (r *OpenRequest) Respond(resp *OpenResponse) {
+ buf := newBuffer(unsafe.Sizeof(openOut{}))
+ out := (*openOut)(buf.alloc(unsafe.Sizeof(openOut{})))
+ out.Fh = uint64(resp.Handle)
+ out.OpenFlags = uint32(resp.Flags)
+ r.respond(buf)
+}
+
+// A OpenResponse is the response to a OpenRequest.
+type OpenResponse struct {
+ Handle HandleID
+ Flags OpenResponseFlags
+}
+
+func (r *OpenResponse) string() string {
+ return fmt.Sprintf("%v fl=%v", r.Handle, r.Flags)
+}
+
+func (r *OpenResponse) String() string {
+ return fmt.Sprintf("Open %s", r.string())
+}
+
+// A CreateRequest asks to create and open a file (not a directory).
+type CreateRequest struct {
+ Header `json:"-"`
+ Name string
+ Flags OpenFlags
+ Mode os.FileMode
+ // Umask of the request. Not supported on OS X.
+ Umask os.FileMode
+}
+
+var _ = Request(&CreateRequest{})
+
+func (r *CreateRequest) String() string {
+ return fmt.Sprintf("Create [%s] %q fl=%v mode=%v umask=%v", &r.Header, r.Name, r.Flags, r.Mode, r.Umask)
+}
+
+// Respond replies to the request with the given response.
+func (r *CreateRequest) Respond(resp *CreateResponse) {
+ eSize := entryOutSize(r.Header.Conn.proto)
+ buf := newBuffer(eSize + unsafe.Sizeof(openOut{}))
+
+ e := (*entryOut)(buf.alloc(eSize))
+ e.Nodeid = uint64(resp.Node)
+ e.Generation = resp.Generation
+ e.EntryValid = uint64(resp.EntryValid / time.Second)
+ e.EntryValidNsec = uint32(resp.EntryValid % time.Second / time.Nanosecond)
+ e.AttrValid = uint64(resp.Attr.Valid / time.Second)
+ e.AttrValidNsec = uint32(resp.Attr.Valid % time.Second / time.Nanosecond)
+ resp.Attr.attr(&e.Attr, r.Header.Conn.proto)
+
+ o := (*openOut)(buf.alloc(unsafe.Sizeof(openOut{})))
+ o.Fh = uint64(resp.Handle)
+ o.OpenFlags = uint32(resp.Flags)
+
+ r.respond(buf)
+}
+
+// A CreateResponse is the response to a CreateRequest.
+// It describes the created node and opened handle.
+type CreateResponse struct {
+ LookupResponse
+ OpenResponse
+}
+
+func (r *CreateResponse) String() string {
+ return fmt.Sprintf("Create {%s} {%s}", r.LookupResponse.string(), r.OpenResponse.string())
+}
+
+// A MkdirRequest asks to create (but not open) a directory.
+type MkdirRequest struct {
+ Header `json:"-"`
+ Name string
+ Mode os.FileMode
+ // Umask of the request. Not supported on OS X.
+ Umask os.FileMode
+}
+
+var _ = Request(&MkdirRequest{})
+
+func (r *MkdirRequest) String() string {
+ return fmt.Sprintf("Mkdir [%s] %q mode=%v umask=%v", &r.Header, r.Name, r.Mode, r.Umask)
+}
+
+// Respond replies to the request with the given response.
+func (r *MkdirRequest) Respond(resp *MkdirResponse) {
+ size := entryOutSize(r.Header.Conn.proto)
+ buf := newBuffer(size)
+ out := (*entryOut)(buf.alloc(size))
+ out.Nodeid = uint64(resp.Node)
+ out.Generation = resp.Generation
+ out.EntryValid = uint64(resp.EntryValid / time.Second)
+ out.EntryValidNsec = uint32(resp.EntryValid % time.Second / time.Nanosecond)
+ out.AttrValid = uint64(resp.Attr.Valid / time.Second)
+ out.AttrValidNsec = uint32(resp.Attr.Valid % time.Second / time.Nanosecond)
+ resp.Attr.attr(&out.Attr, r.Header.Conn.proto)
+ r.respond(buf)
+}
+
+// A MkdirResponse is the response to a MkdirRequest.
+type MkdirResponse struct {
+ LookupResponse
+}
+
+func (r *MkdirResponse) String() string {
+ return fmt.Sprintf("Mkdir %v", r.LookupResponse.string())
+}
+
+// A ReadRequest asks to read from an open file.
+type ReadRequest struct {
+ Header `json:"-"`
+ Dir bool // is this Readdir?
+ Handle HandleID
+ Offset int64
+ Size int
+ Flags ReadFlags
+ LockOwner uint64
+ FileFlags OpenFlags
+}
+
+var _ = Request(&ReadRequest{})
+
+func (r *ReadRequest) String() string {
+ return fmt.Sprintf("Read [%s] %v %d @%#x dir=%v fl=%v lock=%d ffl=%v", &r.Header, r.Handle, r.Size, r.Offset, r.Dir, r.Flags, r.LockOwner, r.FileFlags)
+}
+
+// Respond replies to the request with the given response.
+func (r *ReadRequest) Respond(resp *ReadResponse) {
+ buf := newBuffer(uintptr(len(resp.Data)))
+ buf = append(buf, resp.Data...)
+ r.respond(buf)
+}
+
+// A ReadResponse is the response to a ReadRequest.
+type ReadResponse struct {
+ Data []byte
+}
+
+func (r *ReadResponse) String() string {
+ return fmt.Sprintf("Read %d", len(r.Data))
+}
+
+type jsonReadResponse struct {
+ Len uint64
+}
+
+func (r *ReadResponse) MarshalJSON() ([]byte, error) {
+ j := jsonReadResponse{
+ Len: uint64(len(r.Data)),
+ }
+ return json.Marshal(j)
+}
+
+// A ReleaseRequest asks to release (close) an open file handle.
+type ReleaseRequest struct {
+ Header `json:"-"`
+ Dir bool // is this Releasedir?
+ Handle HandleID
+ Flags OpenFlags // flags from OpenRequest
+ ReleaseFlags ReleaseFlags
+ LockOwner uint32
+}
+
+var _ = Request(&ReleaseRequest{})
+
+func (r *ReleaseRequest) String() string {
+ return fmt.Sprintf("Release [%s] %v fl=%v rfl=%v owner=%#x", &r.Header, r.Handle, r.Flags, r.ReleaseFlags, r.LockOwner)
+}
+
+// Respond replies to the request, indicating that the handle has been released.
+func (r *ReleaseRequest) Respond() {
+ buf := newBuffer(0)
+ r.respond(buf)
+}
+
+// A DestroyRequest is sent by the kernel when unmounting the file system.
+// No more requests will be received after this one, but it should still be
+// responded to.
+type DestroyRequest struct {
+ Header `json:"-"`
+}
+
+var _ = Request(&DestroyRequest{})
+
+func (r *DestroyRequest) String() string {
+ return fmt.Sprintf("Destroy [%s]", &r.Header)
+}
+
+// Respond replies to the request.
+func (r *DestroyRequest) Respond() {
+ buf := newBuffer(0)
+ r.respond(buf)
+}
+
+// A ForgetRequest is sent by the kernel when forgetting about r.Node
+// as returned by r.N lookup requests.
+type ForgetRequest struct {
+ Header `json:"-"`
+ N uint64
+}
+
+var _ = Request(&ForgetRequest{})
+
+func (r *ForgetRequest) String() string {
+ return fmt.Sprintf("Forget [%s] %d", &r.Header, r.N)
+}
+
+// Respond replies to the request, indicating that the forgetfulness has been recorded.
+func (r *ForgetRequest) Respond() {
+ // Don't reply to forget messages.
+ r.noResponse()
+}
+
+// A Dirent represents a single directory entry.
+type Dirent struct {
+ // Inode this entry names.
+ Inode uint64
+
+ // Type of the entry, for example DT_File.
+ //
+ // Setting this is optional. The zero value (DT_Unknown) means
+ // callers will just need to do a Getattr when the type is
+ // needed. Providing a type can speed up operations
+ // significantly.
+ Type DirentType
+
+ // Name of the entry
+ Name string
+}
+
+// Type of an entry in a directory listing.
+type DirentType uint32
+
+const (
+ // These don't quite match os.FileMode; especially there's an
+ // explicit unknown, instead of zero value meaning file. They
+ // are also not quite syscall.DT_*; nothing says the FUSE
+ // protocol follows those, and even if they were, we don't
+ // want each fs to fiddle with syscall.
+
+ // The shift by 12 is hardcoded in the FUSE userspace
+ // low-level C library, so it's safe here.
+
+ DT_Unknown DirentType = 0
+ DT_Socket DirentType = syscall.S_IFSOCK >> 12
+ DT_Link DirentType = syscall.S_IFLNK >> 12
+ DT_File DirentType = syscall.S_IFREG >> 12
+ DT_Block DirentType = syscall.S_IFBLK >> 12
+ DT_Dir DirentType = syscall.S_IFDIR >> 12
+ DT_Char DirentType = syscall.S_IFCHR >> 12
+ DT_FIFO DirentType = syscall.S_IFIFO >> 12
+)
+
+func (t DirentType) String() string {
+ switch t {
+ case DT_Unknown:
+ return "unknown"
+ case DT_Socket:
+ return "socket"
+ case DT_Link:
+ return "link"
+ case DT_File:
+ return "file"
+ case DT_Block:
+ return "block"
+ case DT_Dir:
+ return "dir"
+ case DT_Char:
+ return "char"
+ case DT_FIFO:
+ return "fifo"
+ }
+ return "invalid"
+}
+
+// AppendDirent appends the encoded form of a directory entry to data
+// and returns the resulting slice.
+func AppendDirent(data []byte, dir Dirent) []byte {
+ de := dirent{
+ Ino: dir.Inode,
+ Namelen: uint32(len(dir.Name)),
+ Type: uint32(dir.Type),
+ }
+ de.Off = uint64(len(data) + direntSize + (len(dir.Name)+7)&^7)
+ data = append(data, (*[direntSize]byte)(unsafe.Pointer(&de))[:]...)
+ data = append(data, dir.Name...)
+ n := direntSize + uintptr(len(dir.Name))
+ if n%8 != 0 {
+ var pad [8]byte
+ data = append(data, pad[:8-n%8]...)
+ }
+ return data
+}
+
+// A WriteRequest asks to write to an open file.
+type WriteRequest struct {
+ Header
+ Handle HandleID
+ Offset int64
+ Data []byte
+ Flags WriteFlags
+ LockOwner uint64
+ FileFlags OpenFlags
+}
+
+var _ = Request(&WriteRequest{})
+
+func (r *WriteRequest) String() string {
+ return fmt.Sprintf("Write [%s] %v %d @%d fl=%v lock=%d ffl=%v", &r.Header, r.Handle, len(r.Data), r.Offset, r.Flags, r.LockOwner, r.FileFlags)
+}
+
+type jsonWriteRequest struct {
+ Handle HandleID
+ Offset int64
+ Len uint64
+ Flags WriteFlags
+}
+
+func (r *WriteRequest) MarshalJSON() ([]byte, error) {
+ j := jsonWriteRequest{
+ Handle: r.Handle,
+ Offset: r.Offset,
+ Len: uint64(len(r.Data)),
+ Flags: r.Flags,
+ }
+ return json.Marshal(j)
+}
+
+// Respond replies to the request with the given response.
+func (r *WriteRequest) Respond(resp *WriteResponse) {
+ buf := newBuffer(unsafe.Sizeof(writeOut{}))
+ out := (*writeOut)(buf.alloc(unsafe.Sizeof(writeOut{})))
+ out.Size = uint32(resp.Size)
+ r.respond(buf)
+}
+
+// A WriteResponse replies to a write indicating how many bytes were written.
+type WriteResponse struct {
+ Size int
+}
+
+func (r *WriteResponse) String() string {
+ return fmt.Sprintf("Write %d", r.Size)
+}
+
+// A SetattrRequest asks to change one or more attributes associated with a file,
+// as indicated by Valid.
+type SetattrRequest struct {
+ Header `json:"-"`
+ Valid SetattrValid
+ Handle HandleID
+ Size uint64
+ Atime time.Time
+ Mtime time.Time
+ Mode os.FileMode
+ Uid uint32
+ Gid uint32
+
+ // OS X only
+ Bkuptime time.Time
+ Chgtime time.Time
+ Crtime time.Time
+ Flags uint32 // see chflags(2)
+}
+
+var _ = Request(&SetattrRequest{})
+
+func (r *SetattrRequest) String() string {
+ var buf bytes.Buffer
+ fmt.Fprintf(&buf, "Setattr [%s]", &r.Header)
+ if r.Valid.Mode() {
+ fmt.Fprintf(&buf, " mode=%v", r.Mode)
+ }
+ if r.Valid.Uid() {
+ fmt.Fprintf(&buf, " uid=%d", r.Uid)
+ }
+ if r.Valid.Gid() {
+ fmt.Fprintf(&buf, " gid=%d", r.Gid)
+ }
+ if r.Valid.Size() {
+ fmt.Fprintf(&buf, " size=%d", r.Size)
+ }
+ if r.Valid.Atime() {
+ fmt.Fprintf(&buf, " atime=%v", r.Atime)
+ }
+ if r.Valid.AtimeNow() {
+ fmt.Fprintf(&buf, " atime=now")
+ }
+ if r.Valid.Mtime() {
+ fmt.Fprintf(&buf, " mtime=%v", r.Mtime)
+ }
+ if r.Valid.MtimeNow() {
+ fmt.Fprintf(&buf, " mtime=now")
+ }
+ if r.Valid.Handle() {
+ fmt.Fprintf(&buf, " handle=%v", r.Handle)
+ } else {
+ fmt.Fprintf(&buf, " handle=INVALID-%v", r.Handle)
+ }
+ if r.Valid.LockOwner() {
+ fmt.Fprintf(&buf, " lockowner")
+ }
+ if r.Valid.Crtime() {
+ fmt.Fprintf(&buf, " crtime=%v", r.Crtime)
+ }
+ if r.Valid.Chgtime() {
+ fmt.Fprintf(&buf, " chgtime=%v", r.Chgtime)
+ }
+ if r.Valid.Bkuptime() {
+ fmt.Fprintf(&buf, " bkuptime=%v", r.Bkuptime)
+ }
+ if r.Valid.Flags() {
+ fmt.Fprintf(&buf, " flags=%v", r.Flags)
+ }
+ return buf.String()
+}
+
+// Respond replies to the request with the given response,
+// giving the updated attributes.
+func (r *SetattrRequest) Respond(resp *SetattrResponse) {
+ size := attrOutSize(r.Header.Conn.proto)
+ buf := newBuffer(size)
+ out := (*attrOut)(buf.alloc(size))
+ out.AttrValid = uint64(resp.Attr.Valid / time.Second)
+ out.AttrValidNsec = uint32(resp.Attr.Valid % time.Second / time.Nanosecond)
+ resp.Attr.attr(&out.Attr, r.Header.Conn.proto)
+ r.respond(buf)
+}
+
+// A SetattrResponse is the response to a SetattrRequest.
+type SetattrResponse struct {
+ Attr Attr // file attributes
+}
+
+func (r *SetattrResponse) String() string {
+ return fmt.Sprintf("Setattr %v", r.Attr)
+}
+
+// A FlushRequest asks for the current state of an open file to be flushed
+// to storage, as when a file descriptor is being closed. A single opened Handle
+// may receive multiple FlushRequests over its lifetime.
+type FlushRequest struct {
+ Header `json:"-"`
+ Handle HandleID
+ Flags uint32
+ LockOwner uint64
+}
+
+var _ = Request(&FlushRequest{})
+
+func (r *FlushRequest) String() string {
+ return fmt.Sprintf("Flush [%s] %v fl=%#x lk=%#x", &r.Header, r.Handle, r.Flags, r.LockOwner)
+}
+
+// Respond replies to the request, indicating that the flush succeeded.
+func (r *FlushRequest) Respond() {
+ buf := newBuffer(0)
+ r.respond(buf)
+}
+
+// A RemoveRequest asks to remove a file or directory from the
+// directory r.Node.
+type RemoveRequest struct {
+ Header `json:"-"`
+ Name string // name of the entry to remove
+ Dir bool // is this rmdir?
+}
+
+var _ = Request(&RemoveRequest{})
+
+func (r *RemoveRequest) String() string {
+ return fmt.Sprintf("Remove [%s] %q dir=%v", &r.Header, r.Name, r.Dir)
+}
+
+// Respond replies to the request, indicating that the file was removed.
+func (r *RemoveRequest) Respond() {
+ buf := newBuffer(0)
+ r.respond(buf)
+}
+
+// A SymlinkRequest is a request to create a symlink making NewName point to Target.
+type SymlinkRequest struct {
+ Header `json:"-"`
+ NewName, Target string
+}
+
+var _ = Request(&SymlinkRequest{})
+
+func (r *SymlinkRequest) String() string {
+ return fmt.Sprintf("Symlink [%s] from %q to target %q", &r.Header, r.NewName, r.Target)
+}
+
+// Respond replies to the request, indicating that the symlink was created.
+func (r *SymlinkRequest) Respond(resp *SymlinkResponse) {
+ size := entryOutSize(r.Header.Conn.proto)
+ buf := newBuffer(size)
+ out := (*entryOut)(buf.alloc(size))
+ out.Nodeid = uint64(resp.Node)
+ out.Generation = resp.Generation
+ out.EntryValid = uint64(resp.EntryValid / time.Second)
+ out.EntryValidNsec = uint32(resp.EntryValid % time.Second / time.Nanosecond)
+ out.AttrValid = uint64(resp.Attr.Valid / time.Second)
+ out.AttrValidNsec = uint32(resp.Attr.Valid % time.Second / time.Nanosecond)
+ resp.Attr.attr(&out.Attr, r.Header.Conn.proto)
+ r.respond(buf)
+}
+
+// A SymlinkResponse is the response to a SymlinkRequest.
+type SymlinkResponse struct {
+ LookupResponse
+}
+
+func (r *SymlinkResponse) String() string {
+ return fmt.Sprintf("Symlink %v", r.LookupResponse.string())
+}
+
+// A ReadlinkRequest is a request to read a symlink's target.
+type ReadlinkRequest struct {
+ Header `json:"-"`
+}
+
+var _ = Request(&ReadlinkRequest{})
+
+func (r *ReadlinkRequest) String() string {
+ return fmt.Sprintf("Readlink [%s]", &r.Header)
+}
+
+func (r *ReadlinkRequest) Respond(target string) {
+ buf := newBuffer(uintptr(len(target)))
+ buf = append(buf, target...)
+ r.respond(buf)
+}
+
+// A LinkRequest is a request to create a hard link.
+type LinkRequest struct {
+ Header `json:"-"`
+ OldNode NodeID
+ NewName string
+}
+
+var _ = Request(&LinkRequest{})
+
+func (r *LinkRequest) String() string {
+ return fmt.Sprintf("Link [%s] node %d to %q", &r.Header, r.OldNode, r.NewName)
+}
+
+func (r *LinkRequest) Respond(resp *LookupResponse) {
+ size := entryOutSize(r.Header.Conn.proto)
+ buf := newBuffer(size)
+ out := (*entryOut)(buf.alloc(size))
+ out.Nodeid = uint64(resp.Node)
+ out.Generation = resp.Generation
+ out.EntryValid = uint64(resp.EntryValid / time.Second)
+ out.EntryValidNsec = uint32(resp.EntryValid % time.Second / time.Nanosecond)
+ out.AttrValid = uint64(resp.Attr.Valid / time.Second)
+ out.AttrValidNsec = uint32(resp.Attr.Valid % time.Second / time.Nanosecond)
+ resp.Attr.attr(&out.Attr, r.Header.Conn.proto)
+ r.respond(buf)
+}
+
+// A RenameRequest is a request to rename a file.
+type RenameRequest struct {
+ Header `json:"-"`
+ NewDir NodeID
+ OldName, NewName string
+}
+
+var _ = Request(&RenameRequest{})
+
+func (r *RenameRequest) String() string {
+ return fmt.Sprintf("Rename [%s] from %q to dirnode %v %q", &r.Header, r.OldName, r.NewDir, r.NewName)
+}
+
+func (r *RenameRequest) Respond() {
+ buf := newBuffer(0)
+ r.respond(buf)
+}
+
+type MknodRequest struct {
+ Header `json:"-"`
+ Name string
+ Mode os.FileMode
+ Rdev uint32
+ // Umask of the request. Not supported on OS X.
+ Umask os.FileMode
+}
+
+var _ = Request(&MknodRequest{})
+
+func (r *MknodRequest) String() string {
+ return fmt.Sprintf("Mknod [%s] Name %q mode=%v umask=%v rdev=%d", &r.Header, r.Name, r.Mode, r.Umask, r.Rdev)
+}
+
+func (r *MknodRequest) Respond(resp *LookupResponse) {
+ size := entryOutSize(r.Header.Conn.proto)
+ buf := newBuffer(size)
+ out := (*entryOut)(buf.alloc(size))
+ out.Nodeid = uint64(resp.Node)
+ out.Generation = resp.Generation
+ out.EntryValid = uint64(resp.EntryValid / time.Second)
+ out.EntryValidNsec = uint32(resp.EntryValid % time.Second / time.Nanosecond)
+ out.AttrValid = uint64(resp.Attr.Valid / time.Second)
+ out.AttrValidNsec = uint32(resp.Attr.Valid % time.Second / time.Nanosecond)
+ resp.Attr.attr(&out.Attr, r.Header.Conn.proto)
+ r.respond(buf)
+}
+
+type FsyncRequest struct {
+ Header `json:"-"`
+ Handle HandleID
+ // TODO bit 1 is datasync, not well documented upstream
+ Flags uint32
+ Dir bool
+}
+
+var _ = Request(&FsyncRequest{})
+
+func (r *FsyncRequest) String() string {
+ return fmt.Sprintf("Fsync [%s] Handle %v Flags %v", &r.Header, r.Handle, r.Flags)
+}
+
+func (r *FsyncRequest) Respond() {
+ buf := newBuffer(0)
+ r.respond(buf)
+}
+
+// An InterruptRequest is a request to interrupt another pending request. The
+// response to that request should return an error status of EINTR.
+type InterruptRequest struct {
+ Header `json:"-"`
+ IntrID RequestID // ID of the request to be interrupt.
+}
+
+var _ = Request(&InterruptRequest{})
+
+func (r *InterruptRequest) Respond() {
+ // nothing to do here
+ r.noResponse()
+}
+
+func (r *InterruptRequest) String() string {
+ return fmt.Sprintf("Interrupt [%s] ID %v", &r.Header, r.IntrID)
+}
+
+// An ExchangeDataRequest is a request to exchange the contents of two
+// files, while leaving most metadata untouched.
+//
+// This request comes from OS X exchangedata(2) and represents its
+// specific semantics. Crucially, it is very different from Linux
+// renameat(2) RENAME_EXCHANGE.
+//
+// https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man2/exchangedata.2.html
+type ExchangeDataRequest struct {
+ Header `json:"-"`
+ OldDir, NewDir NodeID
+ OldName, NewName string
+ // TODO options
+}
+
+var _ = Request(&ExchangeDataRequest{})
+
+func (r *ExchangeDataRequest) String() string {
+ // TODO options
+ return fmt.Sprintf("ExchangeData [%s] %v %q and %v %q", &r.Header, r.OldDir, r.OldName, r.NewDir, r.NewName)
+}
+
+func (r *ExchangeDataRequest) Respond() {
+ buf := newBuffer(0)
+ r.respond(buf)
+}
diff --git a/vendor/bazil.org/fuse/fuse_darwin.go b/vendor/bazil.org/fuse/fuse_darwin.go
new file mode 100644
index 00000000..b58dca97
--- /dev/null
+++ b/vendor/bazil.org/fuse/fuse_darwin.go
@@ -0,0 +1,9 @@
+package fuse
+
+// Maximum file write size we are prepared to receive from the kernel.
+//
+// This value has to be >=16MB or OSXFUSE (3.4.0 observed) will
+// forcibly close the /dev/fuse file descriptor on a Setxattr with a
+// 16MB value. See TestSetxattr16MB and
+// https://github.com/bazil/fuse/issues/42
+const maxWrite = 16 * 1024 * 1024
diff --git a/vendor/bazil.org/fuse/fuse_freebsd.go b/vendor/bazil.org/fuse/fuse_freebsd.go
new file mode 100644
index 00000000..4aa83a0d
--- /dev/null
+++ b/vendor/bazil.org/fuse/fuse_freebsd.go
@@ -0,0 +1,6 @@
+package fuse
+
+// Maximum file write size we are prepared to receive from the kernel.
+//
+// This number is just a guess.
+const maxWrite = 128 * 1024
diff --git a/vendor/bazil.org/fuse/fuse_kernel.go b/vendor/bazil.org/fuse/fuse_kernel.go
new file mode 100644
index 00000000..87c5ca1d
--- /dev/null
+++ b/vendor/bazil.org/fuse/fuse_kernel.go
@@ -0,0 +1,774 @@
+// See the file LICENSE for copyright and licensing information.
+
+// Derived from FUSE's fuse_kernel.h, which carries this notice:
+/*
+ This file defines the kernel interface of FUSE
+ Copyright (C) 2001-2007 Miklos Szeredi
+
+
+ This -- and only this -- header file may also be distributed under
+ the terms of the BSD Licence as follows:
+
+ Copyright (C) 2001-2007 Miklos Szeredi. 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.
+
+ THIS SOFTWARE IS PROVIDED BY AUTHOR 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 AUTHOR 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 fuse
+
+import (
+ "fmt"
+ "syscall"
+ "unsafe"
+)
+
+// The FUSE version implemented by the package.
+const (
+ protoVersionMinMajor = 7
+ protoVersionMinMinor = 8
+ protoVersionMaxMajor = 7
+ protoVersionMaxMinor = 12
+)
+
+const (
+ rootID = 1
+)
+
+type kstatfs struct {
+ Blocks uint64
+ Bfree uint64
+ Bavail uint64
+ Files uint64
+ Ffree uint64
+ Bsize uint32
+ Namelen uint32
+ Frsize uint32
+ _ uint32
+ Spare [6]uint32
+}
+
+type fileLock struct {
+ Start uint64
+ End uint64
+ Type uint32
+ Pid uint32
+}
+
+// GetattrFlags are bit flags that can be seen in GetattrRequest.
+type GetattrFlags uint32
+
+const (
+ // Indicates the handle is valid.
+ GetattrFh GetattrFlags = 1 << 0
+)
+
+var getattrFlagsNames = []flagName{
+ {uint32(GetattrFh), "GetattrFh"},
+}
+
+func (fl GetattrFlags) String() string {
+ return flagString(uint32(fl), getattrFlagsNames)
+}
+
+// The SetattrValid are bit flags describing which fields in the SetattrRequest
+// are included in the change.
+type SetattrValid uint32
+
+const (
+ SetattrMode SetattrValid = 1 << 0
+ SetattrUid SetattrValid = 1 << 1
+ SetattrGid SetattrValid = 1 << 2
+ SetattrSize SetattrValid = 1 << 3
+ SetattrAtime SetattrValid = 1 << 4
+ SetattrMtime SetattrValid = 1 << 5
+ SetattrHandle SetattrValid = 1 << 6
+
+ // Linux only(?)
+ SetattrAtimeNow SetattrValid = 1 << 7
+ SetattrMtimeNow SetattrValid = 1 << 8
+ SetattrLockOwner SetattrValid = 1 << 9 // http://www.mail-archive.com/git-commits-head@vger.kernel.org/msg27852.html
+
+ // OS X only
+ SetattrCrtime SetattrValid = 1 << 28
+ SetattrChgtime SetattrValid = 1 << 29
+ SetattrBkuptime SetattrValid = 1 << 30
+ SetattrFlags SetattrValid = 1 << 31
+)
+
+func (fl SetattrValid) Mode() bool { return fl&SetattrMode != 0 }
+func (fl SetattrValid) Uid() bool { return fl&SetattrUid != 0 }
+func (fl SetattrValid) Gid() bool { return fl&SetattrGid != 0 }
+func (fl SetattrValid) Size() bool { return fl&SetattrSize != 0 }
+func (fl SetattrValid) Atime() bool { return fl&SetattrAtime != 0 }
+func (fl SetattrValid) Mtime() bool { return fl&SetattrMtime != 0 }
+func (fl SetattrValid) Handle() bool { return fl&SetattrHandle != 0 }
+func (fl SetattrValid) AtimeNow() bool { return fl&SetattrAtimeNow != 0 }
+func (fl SetattrValid) MtimeNow() bool { return fl&SetattrMtimeNow != 0 }
+func (fl SetattrValid) LockOwner() bool { return fl&SetattrLockOwner != 0 }
+func (fl SetattrValid) Crtime() bool { return fl&SetattrCrtime != 0 }
+func (fl SetattrValid) Chgtime() bool { return fl&SetattrChgtime != 0 }
+func (fl SetattrValid) Bkuptime() bool { return fl&SetattrBkuptime != 0 }
+func (fl SetattrValid) Flags() bool { return fl&SetattrFlags != 0 }
+
+func (fl SetattrValid) String() string {
+ return flagString(uint32(fl), setattrValidNames)
+}
+
+var setattrValidNames = []flagName{
+ {uint32(SetattrMode), "SetattrMode"},
+ {uint32(SetattrUid), "SetattrUid"},
+ {uint32(SetattrGid), "SetattrGid"},
+ {uint32(SetattrSize), "SetattrSize"},
+ {uint32(SetattrAtime), "SetattrAtime"},
+ {uint32(SetattrMtime), "SetattrMtime"},
+ {uint32(SetattrHandle), "SetattrHandle"},
+ {uint32(SetattrAtimeNow), "SetattrAtimeNow"},
+ {uint32(SetattrMtimeNow), "SetattrMtimeNow"},
+ {uint32(SetattrLockOwner), "SetattrLockOwner"},
+ {uint32(SetattrCrtime), "SetattrCrtime"},
+ {uint32(SetattrChgtime), "SetattrChgtime"},
+ {uint32(SetattrBkuptime), "SetattrBkuptime"},
+ {uint32(SetattrFlags), "SetattrFlags"},
+}
+
+// Flags that can be seen in OpenRequest.Flags.
+const (
+ // Access modes. These are not 1-bit flags, but alternatives where
+ // only one can be chosen. See the IsReadOnly etc convenience
+ // methods.
+ OpenReadOnly OpenFlags = syscall.O_RDONLY
+ OpenWriteOnly OpenFlags = syscall.O_WRONLY
+ OpenReadWrite OpenFlags = syscall.O_RDWR
+
+ // File was opened in append-only mode, all writes will go to end
+ // of file. OS X does not provide this information.
+ OpenAppend OpenFlags = syscall.O_APPEND
+ OpenCreate OpenFlags = syscall.O_CREAT
+ OpenDirectory OpenFlags = syscall.O_DIRECTORY
+ OpenExclusive OpenFlags = syscall.O_EXCL
+ OpenNonblock OpenFlags = syscall.O_NONBLOCK
+ OpenSync OpenFlags = syscall.O_SYNC
+ OpenTruncate OpenFlags = syscall.O_TRUNC
+)
+
+// OpenAccessModeMask is a bitmask that separates the access mode
+// from the other flags in OpenFlags.
+const OpenAccessModeMask OpenFlags = syscall.O_ACCMODE
+
+// OpenFlags are the O_FOO flags passed to open/create/etc calls. For
+// example, os.O_WRONLY | os.O_APPEND.
+type OpenFlags uint32
+
+func (fl OpenFlags) String() string {
+ // O_RDONLY, O_RWONLY, O_RDWR are not flags
+ s := accModeName(fl & OpenAccessModeMask)
+ flags := uint32(fl &^ OpenAccessModeMask)
+ if flags != 0 {
+ s = s + "+" + flagString(flags, openFlagNames)
+ }
+ return s
+}
+
+// Return true if OpenReadOnly is set.
+func (fl OpenFlags) IsReadOnly() bool {
+ return fl&OpenAccessModeMask == OpenReadOnly
+}
+
+// Return true if OpenWriteOnly is set.
+func (fl OpenFlags) IsWriteOnly() bool {
+ return fl&OpenAccessModeMask == OpenWriteOnly
+}
+
+// Return true if OpenReadWrite is set.
+func (fl OpenFlags) IsReadWrite() bool {
+ return fl&OpenAccessModeMask == OpenReadWrite
+}
+
+func accModeName(flags OpenFlags) string {
+ switch flags {
+ case OpenReadOnly:
+ return "OpenReadOnly"
+ case OpenWriteOnly:
+ return "OpenWriteOnly"
+ case OpenReadWrite:
+ return "OpenReadWrite"
+ default:
+ return ""
+ }
+}
+
+var openFlagNames = []flagName{
+ {uint32(OpenAppend), "OpenAppend"},
+ {uint32(OpenCreate), "OpenCreate"},
+ {uint32(OpenDirectory), "OpenDirectory"},
+ {uint32(OpenExclusive), "OpenExclusive"},
+ {uint32(OpenNonblock), "OpenNonblock"},
+ {uint32(OpenSync), "OpenSync"},
+ {uint32(OpenTruncate), "OpenTruncate"},
+}
+
+// The OpenResponseFlags are returned in the OpenResponse.
+type OpenResponseFlags uint32
+
+const (
+ OpenDirectIO OpenResponseFlags = 1 << 0 // bypass page cache for this open file
+ OpenKeepCache OpenResponseFlags = 1 << 1 // don't invalidate the data cache on open
+ OpenNonSeekable OpenResponseFlags = 1 << 2 // mark the file as non-seekable (not supported on OS X)
+
+ OpenPurgeAttr OpenResponseFlags = 1 << 30 // OS X
+ OpenPurgeUBC OpenResponseFlags = 1 << 31 // OS X
+)
+
+func (fl OpenResponseFlags) String() string {
+ return flagString(uint32(fl), openResponseFlagNames)
+}
+
+var openResponseFlagNames = []flagName{
+ {uint32(OpenDirectIO), "OpenDirectIO"},
+ {uint32(OpenKeepCache), "OpenKeepCache"},
+ {uint32(OpenNonSeekable), "OpenNonSeekable"},
+ {uint32(OpenPurgeAttr), "OpenPurgeAttr"},
+ {uint32(OpenPurgeUBC), "OpenPurgeUBC"},
+}
+
+// The InitFlags are used in the Init exchange.
+type InitFlags uint32
+
+const (
+ InitAsyncRead InitFlags = 1 << 0
+ InitPosixLocks InitFlags = 1 << 1
+ InitFileOps InitFlags = 1 << 2
+ InitAtomicTrunc InitFlags = 1 << 3
+ InitExportSupport InitFlags = 1 << 4
+ InitBigWrites InitFlags = 1 << 5
+ // Do not mask file access modes with umask. Not supported on OS X.
+ InitDontMask InitFlags = 1 << 6
+ InitSpliceWrite InitFlags = 1 << 7
+ InitSpliceMove InitFlags = 1 << 8
+ InitSpliceRead InitFlags = 1 << 9
+ InitFlockLocks InitFlags = 1 << 10
+ InitHasIoctlDir InitFlags = 1 << 11
+ InitAutoInvalData InitFlags = 1 << 12
+ InitDoReaddirplus InitFlags = 1 << 13
+ InitReaddirplusAuto InitFlags = 1 << 14
+ InitAsyncDIO InitFlags = 1 << 15
+ InitWritebackCache InitFlags = 1 << 16
+ InitNoOpenSupport InitFlags = 1 << 17
+
+ InitCaseSensitive InitFlags = 1 << 29 // OS X only
+ InitVolRename InitFlags = 1 << 30 // OS X only
+ InitXtimes InitFlags = 1 << 31 // OS X only
+)
+
+type flagName struct {
+ bit uint32
+ name string
+}
+
+var initFlagNames = []flagName{
+ {uint32(InitAsyncRead), "InitAsyncRead"},
+ {uint32(InitPosixLocks), "InitPosixLocks"},
+ {uint32(InitFileOps), "InitFileOps"},
+ {uint32(InitAtomicTrunc), "InitAtomicTrunc"},
+ {uint32(InitExportSupport), "InitExportSupport"},
+ {uint32(InitBigWrites), "InitBigWrites"},
+ {uint32(InitDontMask), "InitDontMask"},
+ {uint32(InitSpliceWrite), "InitSpliceWrite"},
+ {uint32(InitSpliceMove), "InitSpliceMove"},
+ {uint32(InitSpliceRead), "InitSpliceRead"},
+ {uint32(InitFlockLocks), "InitFlockLocks"},
+ {uint32(InitHasIoctlDir), "InitHasIoctlDir"},
+ {uint32(InitAutoInvalData), "InitAutoInvalData"},
+ {uint32(InitDoReaddirplus), "InitDoReaddirplus"},
+ {uint32(InitReaddirplusAuto), "InitReaddirplusAuto"},
+ {uint32(InitAsyncDIO), "InitAsyncDIO"},
+ {uint32(InitWritebackCache), "InitWritebackCache"},
+ {uint32(InitNoOpenSupport), "InitNoOpenSupport"},
+
+ {uint32(InitCaseSensitive), "InitCaseSensitive"},
+ {uint32(InitVolRename), "InitVolRename"},
+ {uint32(InitXtimes), "InitXtimes"},
+}
+
+func (fl InitFlags) String() string {
+ return flagString(uint32(fl), initFlagNames)
+}
+
+func flagString(f uint32, names []flagName) string {
+ var s string
+
+ if f == 0 {
+ return "0"
+ }
+
+ for _, n := range names {
+ if f&n.bit != 0 {
+ s += "+" + n.name
+ f &^= n.bit
+ }
+ }
+ if f != 0 {
+ s += fmt.Sprintf("%+#x", f)
+ }
+ return s[1:]
+}
+
+// The ReleaseFlags are used in the Release exchange.
+type ReleaseFlags uint32
+
+const (
+ ReleaseFlush ReleaseFlags = 1 << 0
+)
+
+func (fl ReleaseFlags) String() string {
+ return flagString(uint32(fl), releaseFlagNames)
+}
+
+var releaseFlagNames = []flagName{
+ {uint32(ReleaseFlush), "ReleaseFlush"},
+}
+
+// Opcodes
+const (
+ opLookup = 1
+ opForget = 2 // no reply
+ opGetattr = 3
+ opSetattr = 4
+ opReadlink = 5
+ opSymlink = 6
+ opMknod = 8
+ opMkdir = 9
+ opUnlink = 10
+ opRmdir = 11
+ opRename = 12
+ opLink = 13
+ opOpen = 14
+ opRead = 15
+ opWrite = 16
+ opStatfs = 17
+ opRelease = 18
+ opFsync = 20
+ opSetxattr = 21
+ opGetxattr = 22
+ opListxattr = 23
+ opRemovexattr = 24
+ opFlush = 25
+ opInit = 26
+ opOpendir = 27
+ opReaddir = 28
+ opReleasedir = 29
+ opFsyncdir = 30
+ opGetlk = 31
+ opSetlk = 32
+ opSetlkw = 33
+ opAccess = 34
+ opCreate = 35
+ opInterrupt = 36
+ opBmap = 37
+ opDestroy = 38
+ opIoctl = 39 // Linux?
+ opPoll = 40 // Linux?
+
+ // OS X
+ opSetvolname = 61
+ opGetxtimes = 62
+ opExchange = 63
+)
+
+type entryOut struct {
+ Nodeid uint64 // Inode ID
+ Generation uint64 // Inode generation
+ EntryValid uint64 // Cache timeout for the name
+ AttrValid uint64 // Cache timeout for the attributes
+ EntryValidNsec uint32
+ AttrValidNsec uint32
+ Attr attr
+}
+
+func entryOutSize(p Protocol) uintptr {
+ switch {
+ case p.LT(Protocol{7, 9}):
+ return unsafe.Offsetof(entryOut{}.Attr) + unsafe.Offsetof(entryOut{}.Attr.Blksize)
+ default:
+ return unsafe.Sizeof(entryOut{})
+ }
+}
+
+type forgetIn struct {
+ Nlookup uint64
+}
+
+type getattrIn struct {
+ GetattrFlags uint32
+ _ uint32
+ Fh uint64
+}
+
+type attrOut struct {
+ AttrValid uint64 // Cache timeout for the attributes
+ AttrValidNsec uint32
+ _ uint32
+ Attr attr
+}
+
+func attrOutSize(p Protocol) uintptr {
+ switch {
+ case p.LT(Protocol{7, 9}):
+ return unsafe.Offsetof(attrOut{}.Attr) + unsafe.Offsetof(attrOut{}.Attr.Blksize)
+ default:
+ return unsafe.Sizeof(attrOut{})
+ }
+}
+
+// OS X
+type getxtimesOut struct {
+ Bkuptime uint64
+ Crtime uint64
+ BkuptimeNsec uint32
+ CrtimeNsec uint32
+}
+
+type mknodIn struct {
+ Mode uint32
+ Rdev uint32
+ Umask uint32
+ _ uint32
+ // "filename\x00" follows.
+}
+
+func mknodInSize(p Protocol) uintptr {
+ switch {
+ case p.LT(Protocol{7, 12}):
+ return unsafe.Offsetof(mknodIn{}.Umask)
+ default:
+ return unsafe.Sizeof(mknodIn{})
+ }
+}
+
+type mkdirIn struct {
+ Mode uint32
+ Umask uint32
+ // filename follows
+}
+
+func mkdirInSize(p Protocol) uintptr {
+ switch {
+ case p.LT(Protocol{7, 12}):
+ return unsafe.Offsetof(mkdirIn{}.Umask) + 4
+ default:
+ return unsafe.Sizeof(mkdirIn{})
+ }
+}
+
+type renameIn struct {
+ Newdir uint64
+ // "oldname\x00newname\x00" follows
+}
+
+// OS X
+type exchangeIn struct {
+ Olddir uint64
+ Newdir uint64
+ Options uint64
+ // "oldname\x00newname\x00" follows
+}
+
+type linkIn struct {
+ Oldnodeid uint64
+}
+
+type setattrInCommon struct {
+ Valid uint32
+ _ uint32
+ Fh uint64
+ Size uint64
+ LockOwner uint64 // unused on OS X?
+ Atime uint64
+ Mtime uint64
+ Unused2 uint64
+ AtimeNsec uint32
+ MtimeNsec uint32
+ Unused3 uint32
+ Mode uint32
+ Unused4 uint32
+ Uid uint32
+ Gid uint32
+ Unused5 uint32
+}
+
+type openIn struct {
+ Flags uint32
+ Unused uint32
+}
+
+type openOut struct {
+ Fh uint64
+ OpenFlags uint32
+ _ uint32
+}
+
+type createIn struct {
+ Flags uint32
+ Mode uint32
+ Umask uint32
+ _ uint32
+}
+
+func createInSize(p Protocol) uintptr {
+ switch {
+ case p.LT(Protocol{7, 12}):
+ return unsafe.Offsetof(createIn{}.Umask)
+ default:
+ return unsafe.Sizeof(createIn{})
+ }
+}
+
+type releaseIn struct {
+ Fh uint64
+ Flags uint32
+ ReleaseFlags uint32
+ LockOwner uint32
+}
+
+type flushIn struct {
+ Fh uint64
+ FlushFlags uint32
+ _ uint32
+ LockOwner uint64
+}
+
+type readIn struct {
+ Fh uint64
+ Offset uint64
+ Size uint32
+ ReadFlags uint32
+ LockOwner uint64
+ Flags uint32
+ _ uint32
+}
+
+func readInSize(p Protocol) uintptr {
+ switch {
+ case p.LT(Protocol{7, 9}):
+ return unsafe.Offsetof(readIn{}.ReadFlags) + 4
+ default:
+ return unsafe.Sizeof(readIn{})
+ }
+}
+
+// The ReadFlags are passed in ReadRequest.
+type ReadFlags uint32
+
+const (
+ // LockOwner field is valid.
+ ReadLockOwner ReadFlags = 1 << 1
+)
+
+var readFlagNames = []flagName{
+ {uint32(ReadLockOwner), "ReadLockOwner"},
+}
+
+func (fl ReadFlags) String() string {
+ return flagString(uint32(fl), readFlagNames)
+}
+
+type writeIn struct {
+ Fh uint64
+ Offset uint64
+ Size uint32
+ WriteFlags uint32
+ LockOwner uint64
+ Flags uint32
+ _ uint32
+}
+
+func writeInSize(p Protocol) uintptr {
+ switch {
+ case p.LT(Protocol{7, 9}):
+ return unsafe.Offsetof(writeIn{}.LockOwner)
+ default:
+ return unsafe.Sizeof(writeIn{})
+ }
+}
+
+type writeOut struct {
+ Size uint32
+ _ uint32
+}
+
+// The WriteFlags are passed in WriteRequest.
+type WriteFlags uint32
+
+const (
+ WriteCache WriteFlags = 1 << 0
+ // LockOwner field is valid.
+ WriteLockOwner WriteFlags = 1 << 1
+)
+
+var writeFlagNames = []flagName{
+ {uint32(WriteCache), "WriteCache"},
+ {uint32(WriteLockOwner), "WriteLockOwner"},
+}
+
+func (fl WriteFlags) String() string {
+ return flagString(uint32(fl), writeFlagNames)
+}
+
+const compatStatfsSize = 48
+
+type statfsOut struct {
+ St kstatfs
+}
+
+type fsyncIn struct {
+ Fh uint64
+ FsyncFlags uint32
+ _ uint32
+}
+
+type setxattrInCommon struct {
+ Size uint32
+ Flags uint32
+}
+
+func (setxattrInCommon) position() uint32 {
+ return 0
+}
+
+type getxattrInCommon struct {
+ Size uint32
+ _ uint32
+}
+
+func (getxattrInCommon) position() uint32 {
+ return 0
+}
+
+type getxattrOut struct {
+ Size uint32
+ _ uint32
+}
+
+type lkIn struct {
+ Fh uint64
+ Owner uint64
+ Lk fileLock
+ LkFlags uint32
+ _ uint32
+}
+
+func lkInSize(p Protocol) uintptr {
+ switch {
+ case p.LT(Protocol{7, 9}):
+ return unsafe.Offsetof(lkIn{}.LkFlags)
+ default:
+ return unsafe.Sizeof(lkIn{})
+ }
+}
+
+type lkOut struct {
+ Lk fileLock
+}
+
+type accessIn struct {
+ Mask uint32
+ _ uint32
+}
+
+type initIn struct {
+ Major uint32
+ Minor uint32
+ MaxReadahead uint32
+ Flags uint32
+}
+
+const initInSize = int(unsafe.Sizeof(initIn{}))
+
+type initOut struct {
+ Major uint32
+ Minor uint32
+ MaxReadahead uint32
+ Flags uint32
+ Unused uint32
+ MaxWrite uint32
+}
+
+type interruptIn struct {
+ Unique uint64
+}
+
+type bmapIn struct {
+ Block uint64
+ BlockSize uint32
+ _ uint32
+}
+
+type bmapOut struct {
+ Block uint64
+}
+
+type inHeader struct {
+ Len uint32
+ Opcode uint32
+ Unique uint64
+ Nodeid uint64
+ Uid uint32
+ Gid uint32
+ Pid uint32
+ _ uint32
+}
+
+const inHeaderSize = int(unsafe.Sizeof(inHeader{}))
+
+type outHeader struct {
+ Len uint32
+ Error int32
+ Unique uint64
+}
+
+type dirent struct {
+ Ino uint64
+ Off uint64
+ Namelen uint32
+ Type uint32
+ Name [0]byte
+}
+
+const direntSize = 8 + 8 + 4 + 4
+
+const (
+ notifyCodePoll int32 = 1
+ notifyCodeInvalInode int32 = 2
+ notifyCodeInvalEntry int32 = 3
+)
+
+type notifyInvalInodeOut struct {
+ Ino uint64
+ Off int64
+ Len int64
+}
+
+type notifyInvalEntryOut struct {
+ Parent uint64
+ Namelen uint32
+ _ uint32
+}
diff --git a/vendor/bazil.org/fuse/fuse_kernel_darwin.go b/vendor/bazil.org/fuse/fuse_kernel_darwin.go
new file mode 100644
index 00000000..b9873fdf
--- /dev/null
+++ b/vendor/bazil.org/fuse/fuse_kernel_darwin.go
@@ -0,0 +1,88 @@
+package fuse
+
+import (
+ "time"
+)
+
+type attr struct {
+ Ino uint64
+ Size uint64
+ Blocks uint64
+ Atime uint64
+ Mtime uint64
+ Ctime uint64
+ Crtime_ uint64 // OS X only
+ AtimeNsec uint32
+ MtimeNsec uint32
+ CtimeNsec uint32
+ CrtimeNsec uint32 // OS X only
+ Mode uint32
+ Nlink uint32
+ Uid uint32
+ Gid uint32
+ Rdev uint32
+ Flags_ uint32 // OS X only; see chflags(2)
+ Blksize uint32
+ padding uint32
+}
+
+func (a *attr) SetCrtime(s uint64, ns uint32) {
+ a.Crtime_, a.CrtimeNsec = s, ns
+}
+
+func (a *attr) SetFlags(f uint32) {
+ a.Flags_ = f
+}
+
+type setattrIn struct {
+ setattrInCommon
+
+ // OS X only
+ Bkuptime_ uint64
+ Chgtime_ uint64
+ Crtime uint64
+ BkuptimeNsec uint32
+ ChgtimeNsec uint32
+ CrtimeNsec uint32
+ Flags_ uint32 // see chflags(2)
+}
+
+func (in *setattrIn) BkupTime() time.Time {
+ return time.Unix(int64(in.Bkuptime_), int64(in.BkuptimeNsec))
+}
+
+func (in *setattrIn) Chgtime() time.Time {
+ return time.Unix(int64(in.Chgtime_), int64(in.ChgtimeNsec))
+}
+
+func (in *setattrIn) Flags() uint32 {
+ return in.Flags_
+}
+
+func openFlags(flags uint32) OpenFlags {
+ return OpenFlags(flags)
+}
+
+type getxattrIn struct {
+ getxattrInCommon
+
+ // OS X only
+ Position uint32
+ Padding uint32
+}
+
+func (g *getxattrIn) position() uint32 {
+ return g.Position
+}
+
+type setxattrIn struct {
+ setxattrInCommon
+
+ // OS X only
+ Position uint32
+ Padding uint32
+}
+
+func (s *setxattrIn) position() uint32 {
+ return s.Position
+}
diff --git a/vendor/bazil.org/fuse/fuse_kernel_freebsd.go b/vendor/bazil.org/fuse/fuse_kernel_freebsd.go
new file mode 100644
index 00000000..b1141e41
--- /dev/null
+++ b/vendor/bazil.org/fuse/fuse_kernel_freebsd.go
@@ -0,0 +1,62 @@
+package fuse
+
+import "time"
+
+type attr struct {
+ Ino uint64
+ Size uint64
+ Blocks uint64
+ Atime uint64
+ Mtime uint64
+ Ctime uint64
+ AtimeNsec uint32
+ MtimeNsec uint32
+ CtimeNsec uint32
+ Mode uint32
+ Nlink uint32
+ Uid uint32
+ Gid uint32
+ Rdev uint32
+ Blksize uint32
+ padding uint32
+}
+
+func (a *attr) Crtime() time.Time {
+ return time.Time{}
+}
+
+func (a *attr) SetCrtime(s uint64, ns uint32) {
+ // ignored on freebsd
+}
+
+func (a *attr) SetFlags(f uint32) {
+ // ignored on freebsd
+}
+
+type setattrIn struct {
+ setattrInCommon
+}
+
+func (in *setattrIn) BkupTime() time.Time {
+ return time.Time{}
+}
+
+func (in *setattrIn) Chgtime() time.Time {
+ return time.Time{}
+}
+
+func (in *setattrIn) Flags() uint32 {
+ return 0
+}
+
+func openFlags(flags uint32) OpenFlags {
+ return OpenFlags(flags)
+}
+
+type getxattrIn struct {
+ getxattrInCommon
+}
+
+type setxattrIn struct {
+ setxattrInCommon
+}
diff --git a/vendor/bazil.org/fuse/fuse_kernel_linux.go b/vendor/bazil.org/fuse/fuse_kernel_linux.go
new file mode 100644
index 00000000..d3ba8661
--- /dev/null
+++ b/vendor/bazil.org/fuse/fuse_kernel_linux.go
@@ -0,0 +1,70 @@
+package fuse
+
+import "time"
+
+type attr struct {
+ Ino uint64
+ Size uint64
+ Blocks uint64
+ Atime uint64
+ Mtime uint64
+ Ctime uint64
+ AtimeNsec uint32
+ MtimeNsec uint32
+ CtimeNsec uint32
+ Mode uint32
+ Nlink uint32
+ Uid uint32
+ Gid uint32
+ Rdev uint32
+ Blksize uint32
+ padding uint32
+}
+
+func (a *attr) Crtime() time.Time {
+ return time.Time{}
+}
+
+func (a *attr) SetCrtime(s uint64, ns uint32) {
+ // Ignored on Linux.
+}
+
+func (a *attr) SetFlags(f uint32) {
+ // Ignored on Linux.
+}
+
+type setattrIn struct {
+ setattrInCommon
+}
+
+func (in *setattrIn) BkupTime() time.Time {
+ return time.Time{}
+}
+
+func (in *setattrIn) Chgtime() time.Time {
+ return time.Time{}
+}
+
+func (in *setattrIn) Flags() uint32 {
+ return 0
+}
+
+func openFlags(flags uint32) OpenFlags {
+ // on amd64, the 32-bit O_LARGEFILE flag is always seen;
+ // on i386, the flag probably depends on the app
+ // requesting, but in any case should be utterly
+ // uninteresting to us here; our kernel protocol messages
+ // are not directly related to the client app's kernel
+ // API/ABI
+ flags &^= 0x8000
+
+ return OpenFlags(flags)
+}
+
+type getxattrIn struct {
+ getxattrInCommon
+}
+
+type setxattrIn struct {
+ setxattrInCommon
+}
diff --git a/vendor/bazil.org/fuse/fuse_kernel_std.go b/vendor/bazil.org/fuse/fuse_kernel_std.go
new file mode 100644
index 00000000..074cfd32
--- /dev/null
+++ b/vendor/bazil.org/fuse/fuse_kernel_std.go
@@ -0,0 +1 @@
+package fuse
diff --git a/vendor/bazil.org/fuse/fuse_linux.go b/vendor/bazil.org/fuse/fuse_linux.go
new file mode 100644
index 00000000..5fb96f9a
--- /dev/null
+++ b/vendor/bazil.org/fuse/fuse_linux.go
@@ -0,0 +1,7 @@
+package fuse
+
+// Maximum file write size we are prepared to receive from the kernel.
+//
+// Linux 4.2.0 has been observed to cap this value at 128kB
+// (FUSE_MAX_PAGES_PER_REQ=32, 4kB pages).
+const maxWrite = 128 * 1024
diff --git a/vendor/bazil.org/fuse/fuseutil/fuseutil.go b/vendor/bazil.org/fuse/fuseutil/fuseutil.go
new file mode 100644
index 00000000..b3f52b73
--- /dev/null
+++ b/vendor/bazil.org/fuse/fuseutil/fuseutil.go
@@ -0,0 +1,20 @@
+package fuseutil // import "bazil.org/fuse/fuseutil"
+
+import (
+ "bazil.org/fuse"
+)
+
+// HandleRead handles a read request assuming that data is the entire file content.
+// It adjusts the amount returned in resp according to req.Offset and req.Size.
+func HandleRead(req *fuse.ReadRequest, resp *fuse.ReadResponse, data []byte) {
+ if req.Offset >= int64(len(data)) {
+ data = nil
+ } else {
+ data = data[req.Offset:]
+ }
+ if len(data) > req.Size {
+ data = data[:req.Size]
+ }
+ n := copy(resp.Data[:req.Size], data)
+ resp.Data = resp.Data[:n]
+}
diff --git a/vendor/bazil.org/fuse/mount.go b/vendor/bazil.org/fuse/mount.go
new file mode 100644
index 00000000..8054e902
--- /dev/null
+++ b/vendor/bazil.org/fuse/mount.go
@@ -0,0 +1,38 @@
+package fuse
+
+import (
+ "bufio"
+ "errors"
+ "io"
+ "log"
+ "sync"
+)
+
+var (
+ // ErrOSXFUSENotFound is returned from Mount when the OSXFUSE
+ // installation is not detected.
+ //
+ // Only happens on OS X. Make sure OSXFUSE is installed, or see
+ // OSXFUSELocations for customization.
+ ErrOSXFUSENotFound = errors.New("cannot locate OSXFUSE")
+)
+
+func neverIgnoreLine(line string) bool {
+ return false
+}
+
+func lineLogger(wg *sync.WaitGroup, prefix string, ignore func(line string) bool, r io.ReadCloser) {
+ defer wg.Done()
+
+ scanner := bufio.NewScanner(r)
+ for scanner.Scan() {
+ line := scanner.Text()
+ if ignore(line) {
+ continue
+ }
+ log.Printf("%s: %s", prefix, line)
+ }
+ if err := scanner.Err(); err != nil {
+ log.Printf("%s, error reading: %v", prefix, err)
+ }
+}
diff --git a/vendor/bazil.org/fuse/mount_darwin.go b/vendor/bazil.org/fuse/mount_darwin.go
new file mode 100644
index 00000000..c1c36e62
--- /dev/null
+++ b/vendor/bazil.org/fuse/mount_darwin.go
@@ -0,0 +1,208 @@
+package fuse
+
+import (
+ "errors"
+ "fmt"
+ "log"
+ "os"
+ "os/exec"
+ "path"
+ "strconv"
+ "strings"
+ "sync"
+ "syscall"
+)
+
+var (
+ errNoAvail = errors.New("no available fuse devices")
+ errNotLoaded = errors.New("osxfuse is not loaded")
+)
+
+func loadOSXFUSE(bin string) error {
+ cmd := exec.Command(bin)
+ cmd.Dir = "/"
+ cmd.Stdout = os.Stdout
+ cmd.Stderr = os.Stderr
+ err := cmd.Run()
+ return err
+}
+
+func openOSXFUSEDev(devPrefix string) (*os.File, error) {
+ var f *os.File
+ var err error
+ for i := uint64(0); ; i++ {
+ path := devPrefix + strconv.FormatUint(i, 10)
+ f, err = os.OpenFile(path, os.O_RDWR, 0000)
+ if os.IsNotExist(err) {
+ if i == 0 {
+ // not even the first device was found -> fuse is not loaded
+ return nil, errNotLoaded
+ }
+
+ // we've run out of kernel-provided devices
+ return nil, errNoAvail
+ }
+
+ if err2, ok := err.(*os.PathError); ok && err2.Err == syscall.EBUSY {
+ // try the next one
+ continue
+ }
+
+ if err != nil {
+ return nil, err
+ }
+ return f, nil
+ }
+}
+
+func handleMountOSXFUSE(helperName string, errCh chan<- error) func(line string) (ignore bool) {
+ var noMountpointPrefix = helperName + `: `
+ const noMountpointSuffix = `: No such file or directory`
+ return func(line string) (ignore bool) {
+ if strings.HasPrefix(line, noMountpointPrefix) && strings.HasSuffix(line, noMountpointSuffix) {
+ // re-extract it from the error message in case some layer
+ // changed the path
+ mountpoint := line[len(noMountpointPrefix) : len(line)-len(noMountpointSuffix)]
+ err := &MountpointDoesNotExistError{
+ Path: mountpoint,
+ }
+ select {
+ case errCh <- err:
+ return true
+ default:
+ // not the first error; fall back to logging it
+ return false
+ }
+ }
+
+ return false
+ }
+}
+
+// isBoringMountOSXFUSEError returns whether the Wait error is
+// uninteresting; exit status 64 is.
+func isBoringMountOSXFUSEError(err error) bool {
+ if err, ok := err.(*exec.ExitError); ok && err.Exited() {
+ if status, ok := err.Sys().(syscall.WaitStatus); ok && status.ExitStatus() == 64 {
+ return true
+ }
+ }
+ return false
+}
+
+func callMount(bin string, daemonVar string, dir string, conf *mountConfig, f *os.File, ready chan<- struct{}, errp *error) error {
+ for k, v := range conf.options {
+ if strings.Contains(k, ",") || strings.Contains(v, ",") {
+ // Silly limitation but the mount helper does not
+ // understand any escaping. See TestMountOptionCommaError.
+ return fmt.Errorf("mount options cannot contain commas on darwin: %q=%q", k, v)
+ }
+ }
+ cmd := exec.Command(
+ bin,
+ "-o", conf.getOptions(),
+ // Tell osxfuse-kext how large our buffer is. It must split
+ // writes larger than this into multiple writes.
+ //
+ // OSXFUSE seems to ignore InitResponse.MaxWrite, and uses
+ // this instead.
+ "-o", "iosize="+strconv.FormatUint(maxWrite, 10),
+ // refers to fd passed in cmd.ExtraFiles
+ "3",
+ dir,
+ )
+ cmd.ExtraFiles = []*os.File{f}
+ cmd.Env = os.Environ()
+ // OSXFUSE <3.3.0
+ cmd.Env = append(cmd.Env, "MOUNT_FUSEFS_CALL_BY_LIB=")
+ // OSXFUSE >=3.3.0
+ cmd.Env = append(cmd.Env, "MOUNT_OSXFUSE_CALL_BY_LIB=")
+
+ daemon := os.Args[0]
+ if daemonVar != "" {
+ cmd.Env = append(cmd.Env, daemonVar+"="+daemon)
+ }
+
+ stdout, err := cmd.StdoutPipe()
+ if err != nil {
+ return fmt.Errorf("setting up mount_osxfusefs stderr: %v", err)
+ }
+ stderr, err := cmd.StderrPipe()
+ if err != nil {
+ return fmt.Errorf("setting up mount_osxfusefs stderr: %v", err)
+ }
+
+ if err := cmd.Start(); err != nil {
+ return fmt.Errorf("mount_osxfusefs: %v", err)
+ }
+ helperErrCh := make(chan error, 1)
+ go func() {
+ var wg sync.WaitGroup
+ wg.Add(2)
+ go lineLogger(&wg, "mount helper output", neverIgnoreLine, stdout)
+ helperName := path.Base(bin)
+ go lineLogger(&wg, "mount helper error", handleMountOSXFUSE(helperName, helperErrCh), stderr)
+ wg.Wait()
+ if err := cmd.Wait(); err != nil {
+ // see if we have a better error to report
+ select {
+ case helperErr := <-helperErrCh:
+ // log the Wait error if it's not what we expected
+ if !isBoringMountOSXFUSEError(err) {
+ log.Printf("mount helper failed: %v", err)
+ }
+ // and now return what we grabbed from stderr as the real
+ // error
+ *errp = helperErr
+ close(ready)
+ return
+ default:
+ // nope, fall back to generic message
+ }
+
+ *errp = fmt.Errorf("mount_osxfusefs: %v", err)
+ close(ready)
+ return
+ }
+
+ *errp = nil
+ close(ready)
+ }()
+ return nil
+}
+
+func mount(dir string, conf *mountConfig, ready chan<- struct{}, errp *error) (*os.File, error) {
+ locations := conf.osxfuseLocations
+ if locations == nil {
+ locations = []OSXFUSEPaths{
+ OSXFUSELocationV3,
+ OSXFUSELocationV2,
+ }
+ }
+ for _, loc := range locations {
+ if _, err := os.Stat(loc.Mount); os.IsNotExist(err) {
+ // try the other locations
+ continue
+ }
+
+ f, err := openOSXFUSEDev(loc.DevicePrefix)
+ if err == errNotLoaded {
+ err = loadOSXFUSE(loc.Load)
+ if err != nil {
+ return nil, err
+ }
+ // try again
+ f, err = openOSXFUSEDev(loc.DevicePrefix)
+ }
+ if err != nil {
+ return nil, err
+ }
+ err = callMount(loc.Mount, loc.DaemonVar, dir, conf, f, ready, errp)
+ if err != nil {
+ f.Close()
+ return nil, err
+ }
+ return f, nil
+ }
+ return nil, ErrOSXFUSENotFound
+}
diff --git a/vendor/bazil.org/fuse/mount_freebsd.go b/vendor/bazil.org/fuse/mount_freebsd.go
new file mode 100644
index 00000000..70bb4102
--- /dev/null
+++ b/vendor/bazil.org/fuse/mount_freebsd.go
@@ -0,0 +1,111 @@
+package fuse
+
+import (
+ "fmt"
+ "log"
+ "os"
+ "os/exec"
+ "strings"
+ "sync"
+ "syscall"
+)
+
+func handleMountFusefsStderr(errCh chan<- error) func(line string) (ignore bool) {
+ return func(line string) (ignore bool) {
+ const (
+ noMountpointPrefix = `mount_fusefs: `
+ noMountpointSuffix = `: No such file or directory`
+ )
+ if strings.HasPrefix(line, noMountpointPrefix) && strings.HasSuffix(line, noMountpointSuffix) {
+ // re-extract it from the error message in case some layer
+ // changed the path
+ mountpoint := line[len(noMountpointPrefix) : len(line)-len(noMountpointSuffix)]
+ err := &MountpointDoesNotExistError{
+ Path: mountpoint,
+ }
+ select {
+ case errCh <- err:
+ return true
+ default:
+ // not the first error; fall back to logging it
+ return false
+ }
+ }
+
+ return false
+ }
+}
+
+// isBoringMountFusefsError returns whether the Wait error is
+// uninteresting; exit status 1 is.
+func isBoringMountFusefsError(err error) bool {
+ if err, ok := err.(*exec.ExitError); ok && err.Exited() {
+ if status, ok := err.Sys().(syscall.WaitStatus); ok && status.ExitStatus() == 1 {
+ return true
+ }
+ }
+ return false
+}
+
+func mount(dir string, conf *mountConfig, ready chan<- struct{}, errp *error) (*os.File, error) {
+ for k, v := range conf.options {
+ if strings.Contains(k, ",") || strings.Contains(v, ",") {
+ // Silly limitation but the mount helper does not
+ // understand any escaping. See TestMountOptionCommaError.
+ return nil, fmt.Errorf("mount options cannot contain commas on FreeBSD: %q=%q", k, v)
+ }
+ }
+
+ f, err := os.OpenFile("/dev/fuse", os.O_RDWR, 0000)
+ if err != nil {
+ *errp = err
+ return nil, err
+ }
+
+ cmd := exec.Command(
+ "/sbin/mount_fusefs",
+ "--safe",
+ "-o", conf.getOptions(),
+ "3",
+ dir,
+ )
+ cmd.ExtraFiles = []*os.File{f}
+
+ stdout, err := cmd.StdoutPipe()
+ if err != nil {
+ return nil, fmt.Errorf("setting up mount_fusefs stderr: %v", err)
+ }
+ stderr, err := cmd.StderrPipe()
+ if err != nil {
+ return nil, fmt.Errorf("setting up mount_fusefs stderr: %v", err)
+ }
+
+ if err := cmd.Start(); err != nil {
+ return nil, fmt.Errorf("mount_fusefs: %v", err)
+ }
+ helperErrCh := make(chan error, 1)
+ var wg sync.WaitGroup
+ wg.Add(2)
+ go lineLogger(&wg, "mount helper output", neverIgnoreLine, stdout)
+ go lineLogger(&wg, "mount helper error", handleMountFusefsStderr(helperErrCh), stderr)
+ wg.Wait()
+ if err := cmd.Wait(); err != nil {
+ // see if we have a better error to report
+ select {
+ case helperErr := <-helperErrCh:
+ // log the Wait error if it's not what we expected
+ if !isBoringMountFusefsError(err) {
+ log.Printf("mount helper failed: %v", err)
+ }
+ // and now return what we grabbed from stderr as the real
+ // error
+ return nil, helperErr
+ default:
+ // nope, fall back to generic message
+ }
+ return nil, fmt.Errorf("mount_fusefs: %v", err)
+ }
+
+ close(ready)
+ return f, nil
+}
diff --git a/vendor/bazil.org/fuse/mount_linux.go b/vendor/bazil.org/fuse/mount_linux.go
new file mode 100644
index 00000000..197d1044
--- /dev/null
+++ b/vendor/bazil.org/fuse/mount_linux.go
@@ -0,0 +1,150 @@
+package fuse
+
+import (
+ "fmt"
+ "log"
+ "net"
+ "os"
+ "os/exec"
+ "strings"
+ "sync"
+ "syscall"
+)
+
+func handleFusermountStderr(errCh chan<- error) func(line string) (ignore bool) {
+ return func(line string) (ignore bool) {
+ if line == `fusermount: failed to open /etc/fuse.conf: Permission denied` {
+ // Silence this particular message, it occurs way too
+ // commonly and isn't very relevant to whether the mount
+ // succeeds or not.
+ return true
+ }
+
+ const (
+ noMountpointPrefix = `fusermount: failed to access mountpoint `
+ noMountpointSuffix = `: No such file or directory`
+ )
+ if strings.HasPrefix(line, noMountpointPrefix) && strings.HasSuffix(line, noMountpointSuffix) {
+ // re-extract it from the error message in case some layer
+ // changed the path
+ mountpoint := line[len(noMountpointPrefix) : len(line)-len(noMountpointSuffix)]
+ err := &MountpointDoesNotExistError{
+ Path: mountpoint,
+ }
+ select {
+ case errCh <- err:
+ return true
+ default:
+ // not the first error; fall back to logging it
+ return false
+ }
+ }
+
+ return false
+ }
+}
+
+// isBoringFusermountError returns whether the Wait error is
+// uninteresting; exit status 1 is.
+func isBoringFusermountError(err error) bool {
+ if err, ok := err.(*exec.ExitError); ok && err.Exited() {
+ if status, ok := err.Sys().(syscall.WaitStatus); ok && status.ExitStatus() == 1 {
+ return true
+ }
+ }
+ return false
+}
+
+func mount(dir string, conf *mountConfig, ready chan<- struct{}, errp *error) (fusefd *os.File, err error) {
+ // linux mount is never delayed
+ close(ready)
+
+ fds, err := syscall.Socketpair(syscall.AF_FILE, syscall.SOCK_STREAM, 0)
+ if err != nil {
+ return nil, fmt.Errorf("socketpair error: %v", err)
+ }
+
+ writeFile := os.NewFile(uintptr(fds[0]), "fusermount-child-writes")
+ defer writeFile.Close()
+
+ readFile := os.NewFile(uintptr(fds[1]), "fusermount-parent-reads")
+ defer readFile.Close()
+
+ cmd := exec.Command(
+ "fusermount",
+ "-o", conf.getOptions(),
+ "--",
+ dir,
+ )
+ cmd.Env = append(os.Environ(), "_FUSE_COMMFD=3")
+
+ cmd.ExtraFiles = []*os.File{writeFile}
+
+ var wg sync.WaitGroup
+ stdout, err := cmd.StdoutPipe()
+ if err != nil {
+ return nil, fmt.Errorf("setting up fusermount stderr: %v", err)
+ }
+ stderr, err := cmd.StderrPipe()
+ if err != nil {
+ return nil, fmt.Errorf("setting up fusermount stderr: %v", err)
+ }
+
+ if err := cmd.Start(); err != nil {
+ return nil, fmt.Errorf("fusermount: %v", err)
+ }
+ helperErrCh := make(chan error, 1)
+ wg.Add(2)
+ go lineLogger(&wg, "mount helper output", neverIgnoreLine, stdout)
+ go lineLogger(&wg, "mount helper error", handleFusermountStderr(helperErrCh), stderr)
+ wg.Wait()
+ if err := cmd.Wait(); err != nil {
+ // see if we have a better error to report
+ select {
+ case helperErr := <-helperErrCh:
+ // log the Wait error if it's not what we expected
+ if !isBoringFusermountError(err) {
+ log.Printf("mount helper failed: %v", err)
+ }
+ // and now return what we grabbed from stderr as the real
+ // error
+ return nil, helperErr
+ default:
+ // nope, fall back to generic message
+ }
+
+ return nil, fmt.Errorf("fusermount: %v", err)
+ }
+
+ c, err := net.FileConn(readFile)
+ if err != nil {
+ return nil, fmt.Errorf("FileConn from fusermount socket: %v", err)
+ }
+ defer c.Close()
+
+ uc, ok := c.(*net.UnixConn)
+ if !ok {
+ return nil, fmt.Errorf("unexpected FileConn type; expected UnixConn, got %T", c)
+ }
+
+ buf := make([]byte, 32) // expect 1 byte
+ oob := make([]byte, 32) // expect 24 bytes
+ _, oobn, _, _, err := uc.ReadMsgUnix(buf, oob)
+ scms, err := syscall.ParseSocketControlMessage(oob[:oobn])
+ if err != nil {
+ return nil, fmt.Errorf("ParseSocketControlMessage: %v", err)
+ }
+ if len(scms) != 1 {
+ return nil, fmt.Errorf("expected 1 SocketControlMessage; got scms = %#v", scms)
+ }
+ scm := scms[0]
+ gotFds, err := syscall.ParseUnixRights(&scm)
+ if err != nil {
+ return nil, fmt.Errorf("syscall.ParseUnixRights: %v", err)
+ }
+ if len(gotFds) != 1 {
+ return nil, fmt.Errorf("wanted 1 fd; got %#v", gotFds)
+ }
+ f := os.NewFile(uintptr(gotFds[0]), "/dev/fuse")
+ return f, nil
+}
diff --git a/vendor/bazil.org/fuse/options.go b/vendor/bazil.org/fuse/options.go
new file mode 100644
index 00000000..65ce8a54
--- /dev/null
+++ b/vendor/bazil.org/fuse/options.go
@@ -0,0 +1,310 @@
+package fuse
+
+import (
+ "errors"
+ "strings"
+)
+
+func dummyOption(conf *mountConfig) error {
+ return nil
+}
+
+// mountConfig holds the configuration for a mount operation.
+// Use it by passing MountOption values to Mount.
+type mountConfig struct {
+ options map[string]string
+ maxReadahead uint32
+ initFlags InitFlags
+ osxfuseLocations []OSXFUSEPaths
+}
+
+func escapeComma(s string) string {
+ s = strings.Replace(s, `\`, `\\`, -1)
+ s = strings.Replace(s, `,`, `\,`, -1)
+ return s
+}
+
+// getOptions makes a string of options suitable for passing to FUSE
+// mount flag `-o`. Returns an empty string if no options were set.
+// Any platform specific adjustments should happen before the call.
+func (m *mountConfig) getOptions() string {
+ var opts []string
+ for k, v := range m.options {
+ k = escapeComma(k)
+ if v != "" {
+ k += "=" + escapeComma(v)
+ }
+ opts = append(opts, k)
+ }
+ return strings.Join(opts, ",")
+}
+
+type mountOption func(*mountConfig) error
+
+// MountOption is passed to Mount to change the behavior of the mount.
+type MountOption mountOption
+
+// FSName sets the file system name (also called source) that is
+// visible in the list of mounted file systems.
+//
+// FreeBSD ignores this option.
+func FSName(name string) MountOption {
+ return func(conf *mountConfig) error {
+ conf.options["fsname"] = name
+ return nil
+ }
+}
+
+// Subtype sets the subtype of the mount. The main type is always
+// `fuse`. The type in a list of mounted file systems will look like
+// `fuse.foo`.
+//
+// OS X ignores this option.
+// FreeBSD ignores this option.
+func Subtype(fstype string) MountOption {
+ return func(conf *mountConfig) error {
+ conf.options["subtype"] = fstype
+ return nil
+ }
+}
+
+// LocalVolume sets the volume to be local (instead of network),
+// changing the behavior of Finder, Spotlight, and such.
+//
+// OS X only. Others ignore this option.
+func LocalVolume() MountOption {
+ return localVolume
+}
+
+// VolumeName sets the volume name shown in Finder.
+//
+// OS X only. Others ignore this option.
+func VolumeName(name string) MountOption {
+ return volumeName(name)
+}
+
+// NoAppleDouble makes OSXFUSE disallow files with names used by OS X
+// to store extended attributes on file systems that do not support
+// them natively.
+//
+// Such file names are:
+//
+// ._*
+// .DS_Store
+//
+// OS X only. Others ignore this option.
+func NoAppleDouble() MountOption {
+ return noAppleDouble
+}
+
+// NoAppleXattr makes OSXFUSE disallow extended attributes with the
+// prefix "com.apple.". This disables persistent Finder state and
+// other such information.
+//
+// OS X only. Others ignore this option.
+func NoAppleXattr() MountOption {
+ return noAppleXattr
+}
+
+// ExclCreate causes O_EXCL flag to be set for only "truly" exclusive creates,
+// i.e. create calls for which the initiator explicitly set the O_EXCL flag.
+//
+// OSXFUSE expects all create calls to return EEXIST in case the file
+// already exists, regardless of whether O_EXCL was specified or not.
+// To ensure this behavior, it normally sets OpenExclusive for all
+// Create calls, regardless of whether the original call had it set.
+// For distributed filesystems, that may force every file create to be
+// a distributed consensus action, causing undesirable delays.
+//
+// This option makes the FUSE filesystem see the original flag value,
+// and better decide when to ensure global consensus.
+//
+// Note that returning EEXIST on existing file create is still
+// expected with OSXFUSE, regardless of the presence of the
+// OpenExclusive flag.
+//
+// For more information, see
+// https://github.com/osxfuse/osxfuse/issues/209
+//
+// OS X only. Others ignore this options.
+// Requires OSXFUSE 3.4.1 or newer.
+func ExclCreate() MountOption {
+ return exclCreate
+}
+
+// DaemonTimeout sets the time in seconds between a request and a reply before
+// the FUSE mount is declared dead.
+//
+// OS X and FreeBSD only. Others ignore this option.
+func DaemonTimeout(name string) MountOption {
+ return daemonTimeout(name)
+}
+
+var ErrCannotCombineAllowOtherAndAllowRoot = errors.New("cannot combine AllowOther and AllowRoot")
+
+// AllowOther allows other users to access the file system.
+//
+// Only one of AllowOther or AllowRoot can be used.
+func AllowOther() MountOption {
+ return func(conf *mountConfig) error {
+ if _, ok := conf.options["allow_root"]; ok {
+ return ErrCannotCombineAllowOtherAndAllowRoot
+ }
+ conf.options["allow_other"] = ""
+ return nil
+ }
+}
+
+// AllowRoot allows other users to access the file system.
+//
+// Only one of AllowOther or AllowRoot can be used.
+//
+// FreeBSD ignores this option.
+func AllowRoot() MountOption {
+ return func(conf *mountConfig) error {
+ if _, ok := conf.options["allow_other"]; ok {
+ return ErrCannotCombineAllowOtherAndAllowRoot
+ }
+ conf.options["allow_root"] = ""
+ return nil
+ }
+}
+
+// AllowDev enables interpreting character or block special devices on the
+// filesystem.
+func AllowDev() MountOption {
+ return func(conf *mountConfig) error {
+ conf.options["dev"] = ""
+ return nil
+ }
+}
+
+// AllowSUID allows set-user-identifier or set-group-identifier bits to take
+// effect.
+func AllowSUID() MountOption {
+ return func(conf *mountConfig) error {
+ conf.options["suid"] = ""
+ return nil
+ }
+}
+
+// DefaultPermissions makes the kernel enforce access control based on
+// the file mode (as in chmod).
+//
+// Without this option, the Node itself decides what is and is not
+// allowed. This is normally ok because FUSE file systems cannot be
+// accessed by other users without AllowOther/AllowRoot.
+//
+// FreeBSD ignores this option.
+func DefaultPermissions() MountOption {
+ return func(conf *mountConfig) error {
+ conf.options["default_permissions"] = ""
+ return nil
+ }
+}
+
+// ReadOnly makes the mount read-only.
+func ReadOnly() MountOption {
+ return func(conf *mountConfig) error {
+ conf.options["ro"] = ""
+ return nil
+ }
+}
+
+// MaxReadahead sets the number of bytes that can be prefetched for
+// sequential reads. The kernel can enforce a maximum value lower than
+// this.
+//
+// This setting makes the kernel perform speculative reads that do not
+// originate from any client process. This usually tremendously
+// improves read performance.
+func MaxReadahead(n uint32) MountOption {
+ return func(conf *mountConfig) error {
+ conf.maxReadahead = n
+ return nil
+ }
+}
+
+// AsyncRead enables multiple outstanding read requests for the same
+// handle. Without this, there is at most one request in flight at a
+// time.
+func AsyncRead() MountOption {
+ return func(conf *mountConfig) error {
+ conf.initFlags |= InitAsyncRead
+ return nil
+ }
+}
+
+// WritebackCache enables the kernel to buffer writes before sending
+// them to the FUSE server. Without this, writethrough caching is
+// used.
+func WritebackCache() MountOption {
+ return func(conf *mountConfig) error {
+ conf.initFlags |= InitWritebackCache
+ return nil
+ }
+}
+
+// OSXFUSEPaths describes the paths used by an installed OSXFUSE
+// version. See OSXFUSELocationV3 for typical values.
+type OSXFUSEPaths struct {
+ // Prefix for the device file. At mount time, an incrementing
+ // number is suffixed until a free FUSE device is found.
+ DevicePrefix string
+ // Path of the load helper, used to load the kernel extension if
+ // no device files are found.
+ Load string
+ // Path of the mount helper, used for the actual mount operation.
+ Mount string
+ // Environment variable used to pass the path to the executable
+ // calling the mount helper.
+ DaemonVar string
+}
+
+// Default paths for OSXFUSE. See OSXFUSELocations.
+var (
+ OSXFUSELocationV3 = OSXFUSEPaths{
+ DevicePrefix: "/dev/osxfuse",
+ Load: "/Library/Filesystems/osxfuse.fs/Contents/Resources/load_osxfuse",
+ Mount: "/Library/Filesystems/osxfuse.fs/Contents/Resources/mount_osxfuse",
+ DaemonVar: "MOUNT_OSXFUSE_DAEMON_PATH",
+ }
+ OSXFUSELocationV2 = OSXFUSEPaths{
+ DevicePrefix: "/dev/osxfuse",
+ Load: "/Library/Filesystems/osxfusefs.fs/Support/load_osxfusefs",
+ Mount: "/Library/Filesystems/osxfusefs.fs/Support/mount_osxfusefs",
+ DaemonVar: "MOUNT_FUSEFS_DAEMON_PATH",
+ }
+)
+
+// OSXFUSELocations sets where to look for OSXFUSE files. The
+// arguments are all the possible locations. The previous locations
+// are replaced.
+//
+// Without this option, OSXFUSELocationV3 and OSXFUSELocationV2 are
+// used.
+//
+// OS X only. Others ignore this option.
+func OSXFUSELocations(paths ...OSXFUSEPaths) MountOption {
+ return func(conf *mountConfig) error {
+ if len(paths) == 0 {
+ return errors.New("must specify at least one location for OSXFUSELocations")
+ }
+ // replace previous values, but make a copy so there's no
+ // worries about caller mutating their slice
+ conf.osxfuseLocations = append(conf.osxfuseLocations[:0], paths...)
+ return nil
+ }
+}
+
+// AllowNonEmptyMount allows the mounting over a non-empty directory.
+//
+// The files in it will be shadowed by the freshly created mount. By
+// default these mounts are rejected to prevent accidental covering up
+// of data, which could for example prevent automatic backup.
+func AllowNonEmptyMount() MountOption {
+ return func(conf *mountConfig) error {
+ conf.options["nonempty"] = ""
+ return nil
+ }
+}
diff --git a/vendor/bazil.org/fuse/options_darwin.go b/vendor/bazil.org/fuse/options_darwin.go
new file mode 100644
index 00000000..faa9d78e
--- /dev/null
+++ b/vendor/bazil.org/fuse/options_darwin.go
@@ -0,0 +1,35 @@
+package fuse
+
+func localVolume(conf *mountConfig) error {
+ conf.options["local"] = ""
+ return nil
+}
+
+func volumeName(name string) MountOption {
+ return func(conf *mountConfig) error {
+ conf.options["volname"] = name
+ return nil
+ }
+}
+
+func daemonTimeout(name string) MountOption {
+ return func(conf *mountConfig) error {
+ conf.options["daemon_timeout"] = name
+ return nil
+ }
+}
+
+func noAppleXattr(conf *mountConfig) error {
+ conf.options["noapplexattr"] = ""
+ return nil
+}
+
+func noAppleDouble(conf *mountConfig) error {
+ conf.options["noappledouble"] = ""
+ return nil
+}
+
+func exclCreate(conf *mountConfig) error {
+ conf.options["excl_create"] = ""
+ return nil
+}
diff --git a/vendor/bazil.org/fuse/options_freebsd.go b/vendor/bazil.org/fuse/options_freebsd.go
new file mode 100644
index 00000000..7c164b13
--- /dev/null
+++ b/vendor/bazil.org/fuse/options_freebsd.go
@@ -0,0 +1,28 @@
+package fuse
+
+func localVolume(conf *mountConfig) error {
+ return nil
+}
+
+func volumeName(name string) MountOption {
+ return dummyOption
+}
+
+func daemonTimeout(name string) MountOption {
+ return func(conf *mountConfig) error {
+ conf.options["timeout"] = name
+ return nil
+ }
+}
+
+func noAppleXattr(conf *mountConfig) error {
+ return nil
+}
+
+func noAppleDouble(conf *mountConfig) error {
+ return nil
+}
+
+func exclCreate(conf *mountConfig) error {
+ return nil
+}
diff --git a/vendor/bazil.org/fuse/options_linux.go b/vendor/bazil.org/fuse/options_linux.go
new file mode 100644
index 00000000..13f0896d
--- /dev/null
+++ b/vendor/bazil.org/fuse/options_linux.go
@@ -0,0 +1,25 @@
+package fuse
+
+func localVolume(conf *mountConfig) error {
+ return nil
+}
+
+func volumeName(name string) MountOption {
+ return dummyOption
+}
+
+func daemonTimeout(name string) MountOption {
+ return dummyOption
+}
+
+func noAppleXattr(conf *mountConfig) error {
+ return nil
+}
+
+func noAppleDouble(conf *mountConfig) error {
+ return nil
+}
+
+func exclCreate(conf *mountConfig) error {
+ return nil
+}
diff --git a/vendor/bazil.org/fuse/protocol.go b/vendor/bazil.org/fuse/protocol.go
new file mode 100644
index 00000000..a77bbf72
--- /dev/null
+++ b/vendor/bazil.org/fuse/protocol.go
@@ -0,0 +1,75 @@
+package fuse
+
+import (
+ "fmt"
+)
+
+// Protocol is a FUSE protocol version number.
+type Protocol struct {
+ Major uint32
+ Minor uint32
+}
+
+func (p Protocol) String() string {
+ return fmt.Sprintf("%d.%d", p.Major, p.Minor)
+}
+
+// LT returns whether a is less than b.
+func (a Protocol) LT(b Protocol) bool {
+ return a.Major < b.Major ||
+ (a.Major == b.Major && a.Minor < b.Minor)
+}
+
+// GE returns whether a is greater than or equal to b.
+func (a Protocol) GE(b Protocol) bool {
+ return a.Major > b.Major ||
+ (a.Major == b.Major && a.Minor >= b.Minor)
+}
+
+func (a Protocol) is79() bool {
+ return a.GE(Protocol{7, 9})
+}
+
+// HasAttrBlockSize returns whether Attr.BlockSize is respected by the
+// kernel.
+func (a Protocol) HasAttrBlockSize() bool {
+ return a.is79()
+}
+
+// HasReadWriteFlags returns whether ReadRequest/WriteRequest
+// fields Flags and FileFlags are valid.
+func (a Protocol) HasReadWriteFlags() bool {
+ return a.is79()
+}
+
+// HasGetattrFlags returns whether GetattrRequest field Flags is
+// valid.
+func (a Protocol) HasGetattrFlags() bool {
+ return a.is79()
+}
+
+func (a Protocol) is710() bool {
+ return a.GE(Protocol{7, 10})
+}
+
+// HasOpenNonSeekable returns whether OpenResponse field Flags flag
+// OpenNonSeekable is supported.
+func (a Protocol) HasOpenNonSeekable() bool {
+ return a.is710()
+}
+
+func (a Protocol) is712() bool {
+ return a.GE(Protocol{7, 12})
+}
+
+// HasUmask returns whether CreateRequest/MkdirRequest/MknodRequest
+// field Umask is valid.
+func (a Protocol) HasUmask() bool {
+ return a.is712()
+}
+
+// HasInvalidate returns whether InvalidateNode/InvalidateEntry are
+// supported.
+func (a Protocol) HasInvalidate() bool {
+ return a.is712()
+}
diff --git a/vendor/bazil.org/fuse/unmount.go b/vendor/bazil.org/fuse/unmount.go
new file mode 100644
index 00000000..ffe3f155
--- /dev/null
+++ b/vendor/bazil.org/fuse/unmount.go
@@ -0,0 +1,6 @@
+package fuse
+
+// Unmount tries to unmount the filesystem mounted at dir.
+func Unmount(dir string) error {
+ return unmount(dir)
+}
diff --git a/vendor/bazil.org/fuse/unmount_linux.go b/vendor/bazil.org/fuse/unmount_linux.go
new file mode 100644
index 00000000..088f0cfe
--- /dev/null
+++ b/vendor/bazil.org/fuse/unmount_linux.go
@@ -0,0 +1,21 @@
+package fuse
+
+import (
+ "bytes"
+ "errors"
+ "os/exec"
+)
+
+func unmount(dir string) error {
+ cmd := exec.Command("fusermount", "-u", dir)
+ output, err := cmd.CombinedOutput()
+ if err != nil {
+ if len(output) > 0 {
+ output = bytes.TrimRight(output, "\n")
+ msg := err.Error() + ": " + string(output)
+ err = errors.New(msg)
+ }
+ return err
+ }
+ return nil
+}
diff --git a/vendor/bazil.org/fuse/unmount_std.go b/vendor/bazil.org/fuse/unmount_std.go
new file mode 100644
index 00000000..d6efe276
--- /dev/null
+++ b/vendor/bazil.org/fuse/unmount_std.go
@@ -0,0 +1,17 @@
+// +build !linux
+
+package fuse
+
+import (
+ "os"
+ "syscall"
+)
+
+func unmount(dir string) error {
+ err := syscall.Unmount(dir, 0)
+ if err != nil {
+ err = &os.PathError{Op: "unmount", Path: dir, Err: err}
+ return err
+ }
+ return nil
+}
diff --git a/vendor/github.com/Stebalien/go-bitfield/LICENSE b/vendor/github.com/Stebalien/go-bitfield/LICENSE
new file mode 100644
index 00000000..a55967e0
--- /dev/null
+++ b/vendor/github.com/Stebalien/go-bitfield/LICENSE
@@ -0,0 +1,21 @@
+The MIT License
+
+Copyright (c) 2018 Steven Allen
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/vendor/github.com/Stebalien/go-bitfield/README.md b/vendor/github.com/Stebalien/go-bitfield/README.md
new file mode 100644
index 00000000..ea3037cb
--- /dev/null
+++ b/vendor/github.com/Stebalien/go-bitfield/README.md
@@ -0,0 +1,5 @@
+# go-bitfield
+
+This is a simple bitfield package that's about 2-3x faster than using `big.Int`s
+from the standard library. It also has a better interface (and, e.g., supports
+counting ones).
diff --git a/vendor/github.com/Stebalien/go-bitfield/bitfield.go b/vendor/github.com/Stebalien/go-bitfield/bitfield.go
new file mode 100644
index 00000000..d6f12b06
--- /dev/null
+++ b/vendor/github.com/Stebalien/go-bitfield/bitfield.go
@@ -0,0 +1,114 @@
+package bitfield
+
+// NOTE: Don't bother replacing the divisions/modulo with shifts/ands, go is smart.
+
+import (
+ "math/bits"
+)
+
+// NewBitfield creates a new fixed-sized Bitfield (allocated up-front).
+//
+// Panics if size is not a multiple of 8.
+func NewBitfield(size int) Bitfield {
+ if size%8 != 0 {
+ panic("Bitfield size must be a multiple of 8")
+ }
+ return make([]byte, size/8)
+}
+
+// FromBytes constructs a new bitfield from a serialized bitfield.
+func FromBytes(size int, bits []byte) Bitfield {
+ bf := NewBitfield(size)
+ start := len(bf) - len(bits)
+ if start < 0 {
+ panic("bitfield too small")
+ }
+ copy(bf[start:], bits)
+ return bf
+}
+
+func (bf Bitfield) offset(i int) (uint, uint8) {
+ return uint(len(bf)) - (uint(i) / 8) - 1, uint8(i) % 8
+}
+
+// Bitfield is, well, a bitfield.
+type Bitfield []byte
+
+// Bytes returns the Bitfield as a byte string.
+//
+// This function *does not* copy.
+func (bf Bitfield) Bytes() []byte {
+ for i, b := range bf {
+ if b != 0 {
+ return bf[i:]
+ }
+ }
+ return nil
+}
+
+// Bit returns the ith bit.
+//
+// Panics if the bit is out of bounds.
+func (bf Bitfield) Bit(i int) bool {
+ idx, off := bf.offset(i)
+ return (bf[idx]>>off)&0x1 != 0
+}
+
+// SetBit sets the ith bit.
+//
+// Panics if the bit is out of bounds.
+func (bf Bitfield) SetBit(i int) {
+ idx, off := bf.offset(i)
+ bf[idx] |= 1 << off
+}
+
+// UnsetBit unsets the ith bit.
+//
+// Panics if the bit is out of bounds.
+func (bf Bitfield) UnsetBit(i int) {
+ idx, off := bf.offset(i)
+ bf[idx] &= 0xFF ^ (1 << off)
+}
+
+// SetBytes sets the bits to the given byte array.
+//
+// Panics if 'b' is larger than the bitfield.
+func (bf Bitfield) SetBytes(b []byte) {
+ start := len(bf) - len(b)
+ if start < 0 {
+ panic("bitfield too small")
+ }
+ for i := range bf[:start] {
+ bf[i] = 0
+ }
+ copy(bf[start:], b)
+}
+
+// Ones returns the number of bits set.
+func (bf Bitfield) Ones() int {
+ cnt := 0
+ for _, b := range bf {
+ cnt += bits.OnesCount8(b)
+ }
+ return cnt
+}
+
+// OnesBefore returns the number of bits set *before* this bit.
+func (bf Bitfield) OnesBefore(i int) int {
+ idx, off := bf.offset(i)
+ cnt := bits.OnesCount8(bf[idx] << (8 - off))
+ for _, b := range bf[idx+1:] {
+ cnt += bits.OnesCount8(b)
+ }
+ return cnt
+}
+
+// OnesAfter returns the number of bits set *after* this bit.
+func (bf Bitfield) OnesAfter(i int) int {
+ idx, off := bf.offset(i)
+ cnt := bits.OnesCount8(bf[idx] >> off)
+ for _, b := range bf[:idx] {
+ cnt += bits.OnesCount8(b)
+ }
+ return cnt
+}
diff --git a/vendor/github.com/Stebalien/go-bitfield/package.json b/vendor/github.com/Stebalien/go-bitfield/package.json
new file mode 100644
index 00000000..a8045cb2
--- /dev/null
+++ b/vendor/github.com/Stebalien/go-bitfield/package.json
@@ -0,0 +1,16 @@
+{
+ "author": "Stebalien",
+ "bugs": {
+ "url": "https://github.com/Stebalien/go-bitfield"
+ },
+ "gx": {
+ "dvcsimport": "github.com/Stebalien/go-bitfield"
+ },
+ "gxVersion": "0.12.1",
+ "language": "go",
+ "license": "MIT",
+ "name": "go-bitfield",
+ "releaseCmd": "git commit -a -m \"gx publish $VERSION\"",
+ "version": "0.1.3"
+}
+
diff --git a/vendor/github.com/bren2010/proquint/LICENSE.md b/vendor/github.com/bren2010/proquint/LICENSE.md
new file mode 100644
index 00000000..e5d49487
--- /dev/null
+++ b/vendor/github.com/bren2010/proquint/LICENSE.md
@@ -0,0 +1,19 @@
+Copyright (c) 2014 Brendan McMillion
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/vendor/github.com/bren2010/proquint/README.md b/vendor/github.com/bren2010/proquint/README.md
new file mode 100644
index 00000000..13e7b0b5
--- /dev/null
+++ b/vendor/github.com/bren2010/proquint/README.md
@@ -0,0 +1,6 @@
+Proquint
+-------
+
+Golang implementation of [Proquint Pronounceable Identifiers](https://github.com/deoxxa/proquint).
+
+
diff --git a/vendor/github.com/bren2010/proquint/proquint.go b/vendor/github.com/bren2010/proquint/proquint.go
new file mode 100644
index 00000000..60e1cf98
--- /dev/null
+++ b/vendor/github.com/bren2010/proquint/proquint.go
@@ -0,0 +1,123 @@
+/*
+Copyright (c) 2014 Brendan McMillion
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+package proquint
+
+import (
+ "bytes"
+ "strings"
+ "regexp"
+)
+
+var (
+ conse = [...]byte{'b', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'm', 'n',
+ 'p', 'r', 's', 't', 'v', 'z'}
+ vowse = [...]byte{'a', 'i', 'o', 'u'}
+
+ consd = map[byte] uint16 {
+ 'b' : 0, 'd' : 1, 'f' : 2, 'g' : 3,
+ 'h' : 4, 'j' : 5, 'k' : 6, 'l' : 7,
+ 'm' : 8, 'n' : 9, 'p' : 10, 'r' : 11,
+ 's' : 12, 't' : 13, 'v' : 14, 'z' : 15,
+ }
+
+ vowsd = map[byte] uint16 {
+ 'a' : 0, 'i' : 1, 'o' : 2, 'u' : 3,
+ }
+)
+
+/**
+* Tests if a given string is a Proquint identifier
+*
+* @param {string} str The candidate string.
+*
+* @return {bool} Whether or not it qualifies.
+* @return {error} Error
+*/
+func IsProquint(str string) (bool, error) {
+ exp := "^([abdfghijklmnoprstuvz]{5}-)*[abdfghijklmnoprstuvz]{5}$"
+ ok, err := regexp.MatchString(exp, str)
+
+ return ok, err
+}
+
+/**
+* Encodes an arbitrary byte slice into an identifier.
+*
+* @param {[]byte} buf Slice of bytes to encode.
+*
+* @return {string} The given byte slice as an identifier.
+*/
+func Encode(buf []byte) string {
+ var out bytes.Buffer
+
+ for i := 0; i < len(buf); i = i + 2 {
+ var n uint16 = (uint16(buf[i]) * 256) + uint16(buf[i + 1])
+
+ var (
+ c1 = n & 0x0f
+ v1 = (n >> 4) & 0x03
+ c2 = (n >> 6) & 0x0f
+ v2 = (n >> 10) & 0x03
+ c3 = (n >> 12) & 0x0f
+ )
+
+ out.WriteByte(conse[c1])
+ out.WriteByte(vowse[v1])
+ out.WriteByte(conse[c2])
+ out.WriteByte(vowse[v2])
+ out.WriteByte(conse[c3])
+
+ if (i + 2) < len(buf) {
+ out.WriteByte('-')
+ }
+ }
+
+ return out.String()
+}
+
+/**
+* Decodes an identifier into its corresponding byte slice.
+*
+* @param {string} str Identifier to convert.
+*
+* @return {[]byte} The identifier as a byte slice.
+*/
+func Decode(str string) []byte {
+ var (
+ out bytes.Buffer
+ bits []string = strings.Split(str, "-")
+ )
+
+ for i := 0; i < len(bits); i++ {
+ var x uint16 = consd[bits[i][0]] +
+ (vowsd[bits[i][1]] << 4) +
+ (consd[bits[i][2]] << 6) +
+ (vowsd[bits[i][3]] << 10) +
+ (consd[bits[i][4]] << 12)
+
+ out.WriteByte(byte(x >> 8))
+ out.WriteByte(byte(x))
+ }
+
+ return out.Bytes()
+}
diff --git a/vendor/github.com/davecgh/go-spew/.gitignore b/vendor/github.com/cenkalti/backoff/.gitignore
similarity index 100%
rename from vendor/github.com/davecgh/go-spew/.gitignore
rename to vendor/github.com/cenkalti/backoff/.gitignore
diff --git a/vendor/github.com/cenkalti/backoff/.travis.yml b/vendor/github.com/cenkalti/backoff/.travis.yml
new file mode 100644
index 00000000..47a6a46e
--- /dev/null
+++ b/vendor/github.com/cenkalti/backoff/.travis.yml
@@ -0,0 +1,10 @@
+language: go
+go:
+ - 1.7
+ - 1.x
+ - tip
+before_install:
+ - go get github.com/mattn/goveralls
+ - go get golang.org/x/tools/cmd/cover
+script:
+ - $HOME/gopath/bin/goveralls -service=travis-ci
diff --git a/vendor/github.com/cenkalti/backoff/LICENSE b/vendor/github.com/cenkalti/backoff/LICENSE
new file mode 100644
index 00000000..89b81799
--- /dev/null
+++ b/vendor/github.com/cenkalti/backoff/LICENSE
@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Copyright (c) 2014 Cenk Altı
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/vendor/github.com/cenkalti/backoff/README.md b/vendor/github.com/cenkalti/backoff/README.md
new file mode 100644
index 00000000..55ebc98f
--- /dev/null
+++ b/vendor/github.com/cenkalti/backoff/README.md
@@ -0,0 +1,30 @@
+# Exponential Backoff [![GoDoc][godoc image]][godoc] [![Build Status][travis image]][travis] [![Coverage Status][coveralls image]][coveralls]
+
+This is a Go port of the exponential backoff algorithm from [Google's HTTP Client Library for Java][google-http-java-client].
+
+[Exponential backoff][exponential backoff wiki]
+is an algorithm that uses feedback to multiplicatively decrease the rate of some process,
+in order to gradually find an acceptable rate.
+The retries exponentially increase and stop increasing when a certain threshold is met.
+
+## Usage
+
+See https://godoc.org/github.com/cenkalti/backoff#pkg-examples
+
+## Contributing
+
+* I would like to keep this library as small as possible.
+* Please don't send a PR without opening an issue and discussing it first.
+* If proposed change is not a common use case, I will probably not accept it.
+
+[godoc]: https://godoc.org/github.com/cenkalti/backoff
+[godoc image]: https://godoc.org/github.com/cenkalti/backoff?status.png
+[travis]: https://travis-ci.org/cenkalti/backoff
+[travis image]: https://travis-ci.org/cenkalti/backoff.png?branch=master
+[coveralls]: https://coveralls.io/github/cenkalti/backoff?branch=master
+[coveralls image]: https://coveralls.io/repos/github/cenkalti/backoff/badge.svg?branch=master
+
+[google-http-java-client]: https://github.com/google/google-http-java-client/blob/da1aa993e90285ec18579f1553339b00e19b3ab5/google-http-client/src/main/java/com/google/api/client/util/ExponentialBackOff.java
+[exponential backoff wiki]: http://en.wikipedia.org/wiki/Exponential_backoff
+
+[advanced example]: https://godoc.org/github.com/cenkalti/backoff#example_
diff --git a/vendor/github.com/cenkalti/backoff/backoff.go b/vendor/github.com/cenkalti/backoff/backoff.go
new file mode 100644
index 00000000..3676ee40
--- /dev/null
+++ b/vendor/github.com/cenkalti/backoff/backoff.go
@@ -0,0 +1,66 @@
+// Package backoff implements backoff algorithms for retrying operations.
+//
+// Use Retry function for retrying operations that may fail.
+// If Retry does not meet your needs,
+// copy/paste the function into your project and modify as you wish.
+//
+// There is also Ticker type similar to time.Ticker.
+// You can use it if you need to work with channels.
+//
+// See Examples section below for usage examples.
+package backoff
+
+import "time"
+
+// BackOff is a backoff policy for retrying an operation.
+type BackOff interface {
+ // NextBackOff returns the duration to wait before retrying the operation,
+ // or backoff. Stop to indicate that no more retries should be made.
+ //
+ // Example usage:
+ //
+ // duration := backoff.NextBackOff();
+ // if (duration == backoff.Stop) {
+ // // Do not retry operation.
+ // } else {
+ // // Sleep for duration and retry operation.
+ // }
+ //
+ NextBackOff() time.Duration
+
+ // Reset to initial state.
+ Reset()
+}
+
+// Stop indicates that no more retries should be made for use in NextBackOff().
+const Stop time.Duration = -1
+
+// ZeroBackOff is a fixed backoff policy whose backoff time is always zero,
+// meaning that the operation is retried immediately without waiting, indefinitely.
+type ZeroBackOff struct{}
+
+func (b *ZeroBackOff) Reset() {}
+
+func (b *ZeroBackOff) NextBackOff() time.Duration { return 0 }
+
+// StopBackOff is a fixed backoff policy that always returns backoff.Stop for
+// NextBackOff(), meaning that the operation should never be retried.
+type StopBackOff struct{}
+
+func (b *StopBackOff) Reset() {}
+
+func (b *StopBackOff) NextBackOff() time.Duration { return Stop }
+
+// ConstantBackOff is a backoff policy that always returns the same backoff delay.
+// This is in contrast to an exponential backoff policy,
+// which returns a delay that grows longer as you call NextBackOff() over and over again.
+type ConstantBackOff struct {
+ Interval time.Duration
+}
+
+func (b *ConstantBackOff) Reset() {}
+func (b *ConstantBackOff) NextBackOff() time.Duration { return b.Interval }
+
+func NewConstantBackOff(d time.Duration) *ConstantBackOff {
+ return &ConstantBackOff{Interval: d}
+}
diff --git a/vendor/github.com/cenkalti/backoff/context.go b/vendor/github.com/cenkalti/backoff/context.go
new file mode 100644
index 00000000..7706faa2
--- /dev/null
+++ b/vendor/github.com/cenkalti/backoff/context.go
@@ -0,0 +1,63 @@
+package backoff
+
+import (
+ "context"
+ "time"
+)
+
+// BackOffContext is a backoff policy that stops retrying after the context
+// is canceled.
+type BackOffContext interface {
+ BackOff
+ Context() context.Context
+}
+
+type backOffContext struct {
+ BackOff
+ ctx context.Context
+}
+
+// WithContext returns a BackOffContext with context ctx
+//
+// ctx must not be nil
+func WithContext(b BackOff, ctx context.Context) BackOffContext {
+ if ctx == nil {
+ panic("nil context")
+ }
+
+ if b, ok := b.(*backOffContext); ok {
+ return &backOffContext{
+ BackOff: b.BackOff,
+ ctx: ctx,
+ }
+ }
+
+ return &backOffContext{
+ BackOff: b,
+ ctx: ctx,
+ }
+}
+
+func ensureContext(b BackOff) BackOffContext {
+ if cb, ok := b.(BackOffContext); ok {
+ return cb
+ }
+ return WithContext(b, context.Background())
+}
+
+func (b *backOffContext) Context() context.Context {
+ return b.ctx
+}
+
+func (b *backOffContext) NextBackOff() time.Duration {
+ select {
+ case <-b.ctx.Done():
+ return Stop
+ default:
+ }
+ next := b.BackOff.NextBackOff()
+ if deadline, ok := b.ctx.Deadline(); ok && deadline.Sub(time.Now()) < next {
+ return Stop
+ }
+ return next
+}
diff --git a/vendor/github.com/cenkalti/backoff/exponential.go b/vendor/github.com/cenkalti/backoff/exponential.go
new file mode 100644
index 00000000..a031a659
--- /dev/null
+++ b/vendor/github.com/cenkalti/backoff/exponential.go
@@ -0,0 +1,153 @@
+package backoff
+
+import (
+ "math/rand"
+ "time"
+)
+
+/*
+ExponentialBackOff is a backoff implementation that increases the backoff
+period for each retry attempt using a randomization function that grows exponentially.
+
+NextBackOff() is calculated using the following formula:
+
+ randomized interval =
+ RetryInterval * (random value in range [1 - RandomizationFactor, 1 + RandomizationFactor])
+
+In other words NextBackOff() will range between the randomization factor
+percentage below and above the retry interval.
+
+For example, given the following parameters:
+
+ RetryInterval = 2
+ RandomizationFactor = 0.5
+ Multiplier = 2
+
+the actual backoff period used in the next retry attempt will range between 1 and 3 seconds,
+multiplied by the exponential, that is, between 2 and 6 seconds.
+
+Note: MaxInterval caps the RetryInterval and not the randomized interval.
+
+If the time elapsed since an ExponentialBackOff instance is created goes past the
+MaxElapsedTime, then the method NextBackOff() starts returning backoff.Stop.
+
+The elapsed time can be reset by calling Reset().
+
+Example: Given the following default arguments, for 10 tries the sequence will be,
+and assuming we go over the MaxElapsedTime on the 10th try:
+
+ Request # RetryInterval (seconds) Randomized Interval (seconds)
+
+ 1 0.5 [0.25, 0.75]
+ 2 0.75 [0.375, 1.125]
+ 3 1.125 [0.562, 1.687]
+ 4 1.687 [0.8435, 2.53]
+ 5 2.53 [1.265, 3.795]
+ 6 3.795 [1.897, 5.692]
+ 7 5.692 [2.846, 8.538]
+ 8 8.538 [4.269, 12.807]
+ 9 12.807 [6.403, 19.210]
+ 10 19.210 backoff.Stop
+
+Note: Implementation is not thread-safe.
+*/
+type ExponentialBackOff struct {
+ InitialInterval time.Duration
+ RandomizationFactor float64
+ Multiplier float64
+ MaxInterval time.Duration
+ // After MaxElapsedTime the ExponentialBackOff stops.
+ // It never stops if MaxElapsedTime == 0.
+ MaxElapsedTime time.Duration
+ Clock Clock
+
+ currentInterval time.Duration
+ startTime time.Time
+}
+
+// Clock is an interface that returns current time for BackOff.
+type Clock interface {
+ Now() time.Time
+}
+
+// Default values for ExponentialBackOff.
+const (
+ DefaultInitialInterval = 500 * time.Millisecond
+ DefaultRandomizationFactor = 0.5
+ DefaultMultiplier = 1.5
+ DefaultMaxInterval = 60 * time.Second
+ DefaultMaxElapsedTime = 15 * time.Minute
+)
+
+// NewExponentialBackOff creates an instance of ExponentialBackOff using default values.
+func NewExponentialBackOff() *ExponentialBackOff {
+ b := &ExponentialBackOff{
+ InitialInterval: DefaultInitialInterval,
+ RandomizationFactor: DefaultRandomizationFactor,
+ Multiplier: DefaultMultiplier,
+ MaxInterval: DefaultMaxInterval,
+ MaxElapsedTime: DefaultMaxElapsedTime,
+ Clock: SystemClock,
+ }
+ b.Reset()
+ return b
+}
+
+type systemClock struct{}
+
+func (t systemClock) Now() time.Time {
+ return time.Now()
+}
+
+// SystemClock implements Clock interface that uses time.Now().
+var SystemClock = systemClock{}
+
+// Reset the interval back to the initial retry interval and restarts the timer.
+func (b *ExponentialBackOff) Reset() {
+ b.currentInterval = b.InitialInterval
+ b.startTime = b.Clock.Now()
+}
+
+// NextBackOff calculates the next backoff interval using the formula:
+// Randomized interval = RetryInterval +/- (RandomizationFactor * RetryInterval)
+func (b *ExponentialBackOff) NextBackOff() time.Duration {
+ // Make sure we have not gone over the maximum elapsed time.
+ if b.MaxElapsedTime != 0 && b.GetElapsedTime() > b.MaxElapsedTime {
+ return Stop
+ }
+ defer b.incrementCurrentInterval()
+ return getRandomValueFromInterval(b.RandomizationFactor, rand.Float64(), b.currentInterval)
+}
+
+// GetElapsedTime returns the elapsed time since an ExponentialBackOff instance
+// is created and is reset when Reset() is called.
+//
+// The elapsed time is computed using time.Now().UnixNano(). It is
+// safe to call even while the backoff policy is used by a running
+// ticker.
+func (b *ExponentialBackOff) GetElapsedTime() time.Duration {
+ return b.Clock.Now().Sub(b.startTime)
+}
+
+// Increments the current interval by multiplying it with the multiplier.
+func (b *ExponentialBackOff) incrementCurrentInterval() {
+ // Check for overflow, if overflow is detected set the current interval to the max interval.
+ if float64(b.currentInterval) >= float64(b.MaxInterval)/b.Multiplier {
+ b.currentInterval = b.MaxInterval
+ } else {
+ b.currentInterval = time.Duration(float64(b.currentInterval) * b.Multiplier)
+ }
+}
+
+// Returns a random value from the following interval:
+// [randomizationFactor * currentInterval, randomizationFactor * currentInterval].
+func getRandomValueFromInterval(randomizationFactor, random float64, currentInterval time.Duration) time.Duration {
+ var delta = randomizationFactor * float64(currentInterval)
+ var minInterval = float64(currentInterval) - delta
+ var maxInterval = float64(currentInterval) + delta
+
+ // Get a random value from the range [minInterval, maxInterval].
+ // The formula used below has a +1 because if the minInterval is 1 and the maxInterval is 3 then
+ // we want a 33% chance for selecting either 1, 2 or 3.
+ return time.Duration(minInterval + (random * (maxInterval - minInterval + 1)))
+}
diff --git a/vendor/github.com/cenkalti/backoff/retry.go b/vendor/github.com/cenkalti/backoff/retry.go
new file mode 100644
index 00000000..e936a506
--- /dev/null
+++ b/vendor/github.com/cenkalti/backoff/retry.go
@@ -0,0 +1,82 @@
+package backoff
+
+import "time"
+
+// An Operation is executing by Retry() or RetryNotify().
+// The operation will be retried using a backoff policy if it returns an error.
+type Operation func() error
+
+// Notify is a notify-on-error function. It receives an operation error and
+// backoff delay if the operation failed (with an error).
+//
+// NOTE that if the backoff policy stated to stop retrying,
+// the notify function isn't called.
+type Notify func(error, time.Duration)
+
+// Retry the operation o until it does not return error or BackOff stops.
+// o is guaranteed to be run at least once.
+//
+// If o returns a *PermanentError, the operation is not retried, and the
+// wrapped error is returned.
+//
+// Retry sleeps the goroutine for the duration returned by BackOff after a
+// failed operation returns.
+func Retry(o Operation, b BackOff) error { return RetryNotify(o, b, nil) }
+
+// RetryNotify calls notify function with the error and wait duration
+// for each failed attempt before sleep.
+func RetryNotify(operation Operation, b BackOff, notify Notify) error {
+ var err error
+ var next time.Duration
+ var t *time.Timer
+
+ cb := ensureContext(b)
+
+ b.Reset()
+ for {
+ if err = operation(); err == nil {
+ return nil
+ }
+
+ if permanent, ok := err.(*PermanentError); ok {
+ return permanent.Err
+ }
+
+ if next = cb.NextBackOff(); next == Stop {
+ return err
+ }
+
+ if notify != nil {
+ notify(err, next)
+ }
+
+ if t == nil {
+ t = time.NewTimer(next)
+ defer t.Stop()
+ } else {
+ t.Reset(next)
+ }
+
+ select {
+ case <-cb.Context().Done():
+ return err
+ case <-t.C:
+ }
+ }
+}
+
+// PermanentError signals that the operation should not be retried.
+type PermanentError struct {
+ Err error
+}
+
+func (e *PermanentError) Error() string {
+ return e.Err.Error()
+}
+
+// Permanent wraps the given err in a *PermanentError.
+func Permanent(err error) *PermanentError {
+ return &PermanentError{
+ Err: err,
+ }
+}
diff --git a/vendor/github.com/cenkalti/backoff/ticker.go b/vendor/github.com/cenkalti/backoff/ticker.go
new file mode 100644
index 00000000..e41084b0
--- /dev/null
+++ b/vendor/github.com/cenkalti/backoff/ticker.go
@@ -0,0 +1,82 @@
+package backoff
+
+import (
+ "sync"
+ "time"
+)
+
+// Ticker holds a channel that delivers `ticks' of a clock at times reported by a BackOff.
+//
+// Ticks will continue to arrive when the previous operation is still running,
+// so operations that take a while to fail could run in quick succession.
+type Ticker struct {
+ C <-chan time.Time
+ c chan time.Time
+ b BackOffContext
+ stop chan struct{}
+ stopOnce sync.Once
+}
+
+// NewTicker returns a new Ticker containing a channel that will send
+// the time at times specified by the BackOff argument. Ticker is
+// guaranteed to tick at least once. The channel is closed when Stop
+// method is called or BackOff stops. It is not safe to manipulate the
+// provided backoff policy (notably calling NextBackOff or Reset)
+// while the ticker is running.
+func NewTicker(b BackOff) *Ticker {
+ c := make(chan time.Time)
+ t := &Ticker{
+ C: c,
+ c: c,
+ b: ensureContext(b),
+ stop: make(chan struct{}),
+ }
+ t.b.Reset()
+ go t.run()
+ return t
+}
+
+// Stop turns off a ticker. After Stop, no more ticks will be sent.
+func (t *Ticker) Stop() {
+ t.stopOnce.Do(func() { close(t.stop) })
+}
+
+func (t *Ticker) run() {
+ c := t.c
+ defer close(c)
+
+ // Ticker is guaranteed to tick at least once.
+ afterC := t.send(time.Now())
+
+ for {
+ if afterC == nil {
+ return
+ }
+
+ select {
+ case tick := <-afterC:
+ afterC = t.send(tick)
+ case <-t.stop:
+ t.c = nil // Prevent future ticks from being sent to the channel.
+ return
+ case <-t.b.Context().Done():
+ return
+ }
+ }
+}
+
+func (t *Ticker) send(tick time.Time) <-chan time.Time {
+ select {
+ case t.c <- tick:
+ case <-t.stop:
+ return nil
+ }
+
+ next := t.b.NextBackOff()
+ if next == Stop {
+ t.Stop()
+ return nil
+ }
+
+ return time.After(next)
+}
diff --git a/vendor/github.com/cenkalti/backoff/tries.go b/vendor/github.com/cenkalti/backoff/tries.go
new file mode 100644
index 00000000..cfeefd9b
--- /dev/null
+++ b/vendor/github.com/cenkalti/backoff/tries.go
@@ -0,0 +1,35 @@
+package backoff
+
+import "time"
+
+/*
+WithMaxRetries creates a wrapper around another BackOff, which will
+return Stop if NextBackOff() has been called too many times since
+the last time Reset() was called
+
+Note: Implementation is not thread-safe.
+*/
+func WithMaxRetries(b BackOff, max uint64) BackOff {
+ return &backOffTries{delegate: b, maxTries: max}
+}
+
+type backOffTries struct {
+ delegate BackOff
+ maxTries uint64
+ numTries uint64
+}
+
+func (b *backOffTries) NextBackOff() time.Duration {
+ if b.maxTries > 0 {
+ if b.maxTries <= b.numTries {
+ return Stop
+ }
+ b.numTries++
+ }
+ return b.delegate.NextBackOff()
+}
+
+func (b *backOffTries) Reset() {
+ b.numTries = 0
+ b.delegate.Reset()
+}
diff --git a/vendor/github.com/cheekybits/genny/LICENSE b/vendor/github.com/cheekybits/genny/LICENSE
new file mode 100644
index 00000000..519d7f22
--- /dev/null
+++ b/vendor/github.com/cheekybits/genny/LICENSE
@@ -0,0 +1,22 @@
+The MIT License (MIT)
+
+Copyright (c) 2014 cheekybits
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
diff --git a/vendor/github.com/cheekybits/genny/generic/doc.go b/vendor/github.com/cheekybits/genny/generic/doc.go
new file mode 100644
index 00000000..3bd6c869
--- /dev/null
+++ b/vendor/github.com/cheekybits/genny/generic/doc.go
@@ -0,0 +1,2 @@
+// Package generic contains the generic marker types.
+package generic
diff --git a/vendor/github.com/cheekybits/genny/generic/generic.go b/vendor/github.com/cheekybits/genny/generic/generic.go
new file mode 100644
index 00000000..04a2306c
--- /dev/null
+++ b/vendor/github.com/cheekybits/genny/generic/generic.go
@@ -0,0 +1,13 @@
+package generic
+
+// Type is the placeholder type that indicates a generic value.
+// When genny is executed, variables of this type will be replaced with
+// references to the specific types.
+// var GenericType generic.Type
+type Type interface{}
+
+// Number is the placehoder type that indiccates a generic numerical value.
+// When genny is executed, variables of this type will be replaced with
+// references to the specific types.
+// var GenericType generic.Number
+type Number float64
diff --git a/vendor/github.com/coreos/go-semver/LICENSE b/vendor/github.com/coreos/go-semver/LICENSE
new file mode 100644
index 00000000..d6456956
--- /dev/null
+++ b/vendor/github.com/coreos/go-semver/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/vendor/github.com/coreos/go-semver/NOTICE b/vendor/github.com/coreos/go-semver/NOTICE
new file mode 100644
index 00000000..23a0ada2
--- /dev/null
+++ b/vendor/github.com/coreos/go-semver/NOTICE
@@ -0,0 +1,5 @@
+CoreOS Project
+Copyright 2018 CoreOS, Inc
+
+This product includes software developed at CoreOS, Inc.
+(http://www.coreos.com/).
diff --git a/vendor/github.com/coreos/go-semver/semver/semver.go b/vendor/github.com/coreos/go-semver/semver/semver.go
new file mode 100644
index 00000000..76cf4852
--- /dev/null
+++ b/vendor/github.com/coreos/go-semver/semver/semver.go
@@ -0,0 +1,296 @@
+// Copyright 2013-2015 CoreOS, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Semantic Versions http://semver.org
+package semver
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "regexp"
+ "strconv"
+ "strings"
+)
+
+type Version struct {
+ Major int64
+ Minor int64
+ Patch int64
+ PreRelease PreRelease
+ Metadata string
+}
+
+type PreRelease string
+
+func splitOff(input *string, delim string) (val string) {
+ parts := strings.SplitN(*input, delim, 2)
+
+ if len(parts) == 2 {
+ *input = parts[0]
+ val = parts[1]
+ }
+
+ return val
+}
+
+func New(version string) *Version {
+ return Must(NewVersion(version))
+}
+
+func NewVersion(version string) (*Version, error) {
+ v := Version{}
+
+ if err := v.Set(version); err != nil {
+ return nil, err
+ }
+
+ return &v, nil
+}
+
+// Must is a helper for wrapping NewVersion and will panic if err is not nil.
+func Must(v *Version, err error) *Version {
+ if err != nil {
+ panic(err)
+ }
+ return v
+}
+
+// Set parses and updates v from the given version string. Implements flag.Value
+func (v *Version) Set(version string) error {
+ metadata := splitOff(&version, "+")
+ preRelease := PreRelease(splitOff(&version, "-"))
+ dotParts := strings.SplitN(version, ".", 3)
+
+ if len(dotParts) != 3 {
+ return fmt.Errorf("%s is not in dotted-tri format", version)
+ }
+
+ if err := validateIdentifier(string(preRelease)); err != nil {
+ return fmt.Errorf("failed to validate pre-release: %v", err)
+ }
+
+ if err := validateIdentifier(metadata); err != nil {
+ return fmt.Errorf("failed to validate metadata: %v", err)
+ }
+
+ parsed := make([]int64, 3, 3)
+
+ for i, v := range dotParts[:3] {
+ val, err := strconv.ParseInt(v, 10, 64)
+ parsed[i] = val
+ if err != nil {
+ return err
+ }
+ }
+
+ v.Metadata = metadata
+ v.PreRelease = preRelease
+ v.Major = parsed[0]
+ v.Minor = parsed[1]
+ v.Patch = parsed[2]
+ return nil
+}
+
+func (v Version) String() string {
+ var buffer bytes.Buffer
+
+ fmt.Fprintf(&buffer, "%d.%d.%d", v.Major, v.Minor, v.Patch)
+
+ if v.PreRelease != "" {
+ fmt.Fprintf(&buffer, "-%s", v.PreRelease)
+ }
+
+ if v.Metadata != "" {
+ fmt.Fprintf(&buffer, "+%s", v.Metadata)
+ }
+
+ return buffer.String()
+}
+
+func (v *Version) UnmarshalYAML(unmarshal func(interface{}) error) error {
+ var data string
+ if err := unmarshal(&data); err != nil {
+ return err
+ }
+ return v.Set(data)
+}
+
+func (v Version) MarshalJSON() ([]byte, error) {
+ return []byte(`"` + v.String() + `"`), nil
+}
+
+func (v *Version) UnmarshalJSON(data []byte) error {
+ l := len(data)
+ if l == 0 || string(data) == `""` {
+ return nil
+ }
+ if l < 2 || data[0] != '"' || data[l-1] != '"' {
+ return errors.New("invalid semver string")
+ }
+ return v.Set(string(data[1 : l-1]))
+}
+
+// Compare tests if v is less than, equal to, or greater than versionB,
+// returning -1, 0, or +1 respectively.
+func (v Version) Compare(versionB Version) int {
+ if cmp := recursiveCompare(v.Slice(), versionB.Slice()); cmp != 0 {
+ return cmp
+ }
+ return preReleaseCompare(v, versionB)
+}
+
+// Equal tests if v is equal to versionB.
+func (v Version) Equal(versionB Version) bool {
+ return v.Compare(versionB) == 0
+}
+
+// LessThan tests if v is less than versionB.
+func (v Version) LessThan(versionB Version) bool {
+ return v.Compare(versionB) < 0
+}
+
+// Slice converts the comparable parts of the semver into a slice of integers.
+func (v Version) Slice() []int64 {
+ return []int64{v.Major, v.Minor, v.Patch}
+}
+
+func (p PreRelease) Slice() []string {
+ preRelease := string(p)
+ return strings.Split(preRelease, ".")
+}
+
+func preReleaseCompare(versionA Version, versionB Version) int {
+ a := versionA.PreRelease
+ b := versionB.PreRelease
+
+ /* Handle the case where if two versions are otherwise equal it is the
+ * one without a PreRelease that is greater */
+ if len(a) == 0 && (len(b) > 0) {
+ return 1
+ } else if len(b) == 0 && (len(a) > 0) {
+ return -1
+ }
+
+ // If there is a prerelease, check and compare each part.
+ return recursivePreReleaseCompare(a.Slice(), b.Slice())
+}
+
+func recursiveCompare(versionA []int64, versionB []int64) int {
+ if len(versionA) == 0 {
+ return 0
+ }
+
+ a := versionA[0]
+ b := versionB[0]
+
+ if a > b {
+ return 1
+ } else if a < b {
+ return -1
+ }
+
+ return recursiveCompare(versionA[1:], versionB[1:])
+}
+
+func recursivePreReleaseCompare(versionA []string, versionB []string) int {
+ // A larger set of pre-release fields has a higher precedence than a smaller set,
+ // if all of the preceding identifiers are equal.
+ if len(versionA) == 0 {
+ if len(versionB) > 0 {
+ return -1
+ }
+ return 0
+ } else if len(versionB) == 0 {
+ // We're longer than versionB so return 1.
+ return 1
+ }
+
+ a := versionA[0]
+ b := versionB[0]
+
+ aInt := false
+ bInt := false
+
+ aI, err := strconv.Atoi(versionA[0])
+ if err == nil {
+ aInt = true
+ }
+
+ bI, err := strconv.Atoi(versionB[0])
+ if err == nil {
+ bInt = true
+ }
+
+ // Numeric identifiers always have lower precedence than non-numeric identifiers.
+ if aInt && !bInt {
+ return -1
+ } else if !aInt && bInt {
+ return 1
+ }
+
+ // Handle Integer Comparison
+ if aInt && bInt {
+ if aI > bI {
+ return 1
+ } else if aI < bI {
+ return -1
+ }
+ }
+
+ // Handle String Comparison
+ if a > b {
+ return 1
+ } else if a < b {
+ return -1
+ }
+
+ return recursivePreReleaseCompare(versionA[1:], versionB[1:])
+}
+
+// BumpMajor increments the Major field by 1 and resets all other fields to their default values
+func (v *Version) BumpMajor() {
+ v.Major += 1
+ v.Minor = 0
+ v.Patch = 0
+ v.PreRelease = PreRelease("")
+ v.Metadata = ""
+}
+
+// BumpMinor increments the Minor field by 1 and resets all other fields to their default values
+func (v *Version) BumpMinor() {
+ v.Minor += 1
+ v.Patch = 0
+ v.PreRelease = PreRelease("")
+ v.Metadata = ""
+}
+
+// BumpPatch increments the Patch field by 1 and resets all other fields to their default values
+func (v *Version) BumpPatch() {
+ v.Patch += 1
+ v.PreRelease = PreRelease("")
+ v.Metadata = ""
+}
+
+// validateIdentifier makes sure the provided identifier satisfies semver spec
+func validateIdentifier(id string) error {
+ if id != "" && !reIdentifier.MatchString(id) {
+ return fmt.Errorf("%s is not a valid semver identifier", id)
+ }
+ return nil
+}
+
+// reIdentifier is a regular expression used to check that pre-release and metadata
+// identifiers satisfy the spec requirements
+var reIdentifier = regexp.MustCompile(`^[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*$`)
diff --git a/vendor/github.com/coreos/go-semver/semver/sort.go b/vendor/github.com/coreos/go-semver/semver/sort.go
new file mode 100644
index 00000000..e256b41a
--- /dev/null
+++ b/vendor/github.com/coreos/go-semver/semver/sort.go
@@ -0,0 +1,38 @@
+// Copyright 2013-2015 CoreOS, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package semver
+
+import (
+ "sort"
+)
+
+type Versions []*Version
+
+func (s Versions) Len() int {
+ return len(s)
+}
+
+func (s Versions) Swap(i, j int) {
+ s[i], s[j] = s[j], s[i]
+}
+
+func (s Versions) Less(i, j int) bool {
+ return s[i].LessThan(*s[j])
+}
+
+// Sort sorts the given slice of Version
+func Sort(versions []*Version) {
+ sort.Sort(Versions(versions))
+}
diff --git a/vendor/github.com/cskr/pubsub/LICENSE b/vendor/github.com/cskr/pubsub/LICENSE
new file mode 100644
index 00000000..ae195b47
--- /dev/null
+++ b/vendor/github.com/cskr/pubsub/LICENSE
@@ -0,0 +1,22 @@
+Copyright (c) 2013, Chandra Sekar S
+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.
+
+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.
diff --git a/vendor/github.com/cskr/pubsub/README.md b/vendor/github.com/cskr/pubsub/README.md
new file mode 100644
index 00000000..8ec08386
--- /dev/null
+++ b/vendor/github.com/cskr/pubsub/README.md
@@ -0,0 +1,13 @@
+[![GoDoc](https://godoc.org/github.com/cskr/pubsub?status.svg)](https://godoc.org/github.com/cskr/pubsub)
+
+Package pubsub implements a simple multi-topic pub-sub library.
+
+Install pubsub with,
+
+ go get github.com/cskr/pubsub
+
+This repository is a go module and contains tagged releases. Please pin a
+version for production use.
+
+Use of this module is governed by a BSD-style license that can be found in the
+[LICENSE](LICENSE) file.
diff --git a/vendor/github.com/cskr/pubsub/go.mod b/vendor/github.com/cskr/pubsub/go.mod
new file mode 100644
index 00000000..18dbec9b
--- /dev/null
+++ b/vendor/github.com/cskr/pubsub/go.mod
@@ -0,0 +1,3 @@
+module github.com/cskr/pubsub
+
+go 1.12
diff --git a/vendor/github.com/cskr/pubsub/pubsub.go b/vendor/github.com/cskr/pubsub/pubsub.go
new file mode 100644
index 00000000..352ef6ff
--- /dev/null
+++ b/vendor/github.com/cskr/pubsub/pubsub.go
@@ -0,0 +1,267 @@
+// Copyright 2013, Chandra Sekar S. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package pubsub implements a simple multi-topic pub-sub
+// library.
+//
+// Topics must be strings and messages of any type can be
+// published. A topic can have any number of subcribers and
+// all of them receive messages published on the topic.
+package pubsub
+
+type operation int
+
+const (
+ sub operation = iota
+ subOnce
+ subOnceEach
+ pub
+ tryPub
+ unsub
+ unsubAll
+ closeTopic
+ shutdown
+)
+
+// PubSub is a collection of topics.
+type PubSub struct {
+ cmdChan chan cmd
+ capacity int
+}
+
+type cmd struct {
+ op operation
+ topics []string
+ ch chan interface{}
+ msg interface{}
+}
+
+// New creates a new PubSub and starts a goroutine for handling operations.
+// The capacity of the channels created by Sub and SubOnce will be as specified.
+func New(capacity int) *PubSub {
+ ps := &PubSub{make(chan cmd), capacity}
+ go ps.start()
+ return ps
+}
+
+// Sub returns a channel on which messages published on any of
+// the specified topics can be received.
+func (ps *PubSub) Sub(topics ...string) chan interface{} {
+ return ps.sub(sub, topics...)
+}
+
+// SubOnce is similar to Sub, but only the first message published, after subscription,
+// on any of the specified topics can be received.
+func (ps *PubSub) SubOnce(topics ...string) chan interface{} {
+ return ps.sub(subOnce, topics...)
+}
+
+// SubOnceEach returns a channel on which callers receive, at most, one message
+// for each topic.
+func (ps *PubSub) SubOnceEach(topics ...string) chan interface{} {
+ return ps.sub(subOnceEach, topics...)
+}
+
+func (ps *PubSub) sub(op operation, topics ...string) chan interface{} {
+ ch := make(chan interface{}, ps.capacity)
+ ps.cmdChan <- cmd{op: op, topics: topics, ch: ch}
+ return ch
+}
+
+// AddSub adds subscriptions to an existing channel.
+func (ps *PubSub) AddSub(ch chan interface{}, topics ...string) {
+ ps.cmdChan <- cmd{op: sub, topics: topics, ch: ch}
+}
+
+// AddSubOnceEach adds subscriptions to an existing channel with SubOnceEach
+// behavior.
+func (ps *PubSub) AddSubOnceEach(ch chan interface{}, topics ...string) {
+ ps.cmdChan <- cmd{op: subOnceEach, topics: topics, ch: ch}
+}
+
+// Pub publishes the given message to all subscribers of
+// the specified topics.
+func (ps *PubSub) Pub(msg interface{}, topics ...string) {
+ ps.cmdChan <- cmd{op: pub, topics: topics, msg: msg}
+}
+
+// TryPub publishes the given message to all subscribers of
+// the specified topics if the topic has buffer space.
+func (ps *PubSub) TryPub(msg interface{}, topics ...string) {
+ ps.cmdChan <- cmd{op: tryPub, topics: topics, msg: msg}
+}
+
+// Unsub unsubscribes the given channel from the specified
+// topics. If no topic is specified, it is unsubscribed
+// from all topics.
+//
+// Unsub must be called from a goroutine that is different from the subscriber.
+// The subscriber must consume messages from the channel until it reaches the
+// end. Not doing so can result in a deadlock.
+func (ps *PubSub) Unsub(ch chan interface{}, topics ...string) {
+ if len(topics) == 0 {
+ ps.cmdChan <- cmd{op: unsubAll, ch: ch}
+ return
+ }
+
+ ps.cmdChan <- cmd{op: unsub, topics: topics, ch: ch}
+}
+
+// Close closes all channels currently subscribed to the specified topics.
+// If a channel is subscribed to multiple topics, some of which is
+// not specified, it is not closed.
+func (ps *PubSub) Close(topics ...string) {
+ ps.cmdChan <- cmd{op: closeTopic, topics: topics}
+}
+
+// Shutdown closes all subscribed channels and terminates the goroutine.
+func (ps *PubSub) Shutdown() {
+ ps.cmdChan <- cmd{op: shutdown}
+}
+
+func (ps *PubSub) start() {
+ reg := registry{
+ topics: make(map[string]map[chan interface{}]subType),
+ revTopics: make(map[chan interface{}]map[string]bool),
+ }
+
+loop:
+ for cmd := range ps.cmdChan {
+ if cmd.topics == nil {
+ switch cmd.op {
+ case unsubAll:
+ reg.removeChannel(cmd.ch)
+
+ case shutdown:
+ break loop
+ }
+
+ continue loop
+ }
+
+ for _, topic := range cmd.topics {
+ switch cmd.op {
+ case sub:
+ reg.add(topic, cmd.ch, normal)
+
+ case subOnce:
+ reg.add(topic, cmd.ch, onceAny)
+
+ case subOnceEach:
+ reg.add(topic, cmd.ch, onceEach)
+
+ case tryPub:
+ reg.sendNoWait(topic, cmd.msg)
+
+ case pub:
+ reg.send(topic, cmd.msg)
+
+ case unsub:
+ reg.remove(topic, cmd.ch)
+
+ case closeTopic:
+ reg.removeTopic(topic)
+ }
+ }
+ }
+
+ for topic, chans := range reg.topics {
+ for ch := range chans {
+ reg.remove(topic, ch)
+ }
+ }
+}
+
+// registry maintains the current subscription state. It's not
+// safe to access a registry from multiple goroutines simultaneously.
+type registry struct {
+ topics map[string]map[chan interface{}]subType
+ revTopics map[chan interface{}]map[string]bool
+}
+
+type subType int
+
+const (
+ onceAny subType = iota
+ onceEach
+ normal
+)
+
+func (reg *registry) add(topic string, ch chan interface{}, st subType) {
+ if reg.topics[topic] == nil {
+ reg.topics[topic] = make(map[chan interface{}]subType)
+ }
+ reg.topics[topic][ch] = st
+
+ if reg.revTopics[ch] == nil {
+ reg.revTopics[ch] = make(map[string]bool)
+ }
+ reg.revTopics[ch][topic] = true
+}
+
+func (reg *registry) send(topic string, msg interface{}) {
+ for ch, st := range reg.topics[topic] {
+ ch <- msg
+ switch st {
+ case onceAny:
+ for topic := range reg.revTopics[ch] {
+ reg.remove(topic, ch)
+ }
+ case onceEach:
+ reg.remove(topic, ch)
+ }
+ }
+}
+
+func (reg *registry) sendNoWait(topic string, msg interface{}) {
+ for ch, st := range reg.topics[topic] {
+ select {
+ case ch <- msg:
+ switch st {
+ case onceAny:
+ for topic := range reg.revTopics[ch] {
+ reg.remove(topic, ch)
+ }
+ case onceEach:
+ reg.remove(topic, ch)
+ }
+ default:
+ }
+
+ }
+}
+
+func (reg *registry) removeTopic(topic string) {
+ for ch := range reg.topics[topic] {
+ reg.remove(topic, ch)
+ }
+}
+
+func (reg *registry) removeChannel(ch chan interface{}) {
+ for topic := range reg.revTopics[ch] {
+ reg.remove(topic, ch)
+ }
+}
+
+func (reg *registry) remove(topic string, ch chan interface{}) {
+ if _, ok := reg.topics[topic]; !ok {
+ return
+ }
+
+ if _, ok := reg.topics[topic][ch]; !ok {
+ return
+ }
+
+ delete(reg.topics[topic], ch)
+ delete(reg.revTopics[ch], topic)
+
+ if len(reg.topics[topic]) == 0 {
+ delete(reg.topics, topic)
+ }
+
+ if len(reg.revTopics[ch]) == 0 {
+ close(ch)
+ delete(reg.revTopics, ch)
+ }
+}
diff --git a/vendor/github.com/davecgh/go-spew/.travis.yml b/vendor/github.com/davecgh/go-spew/.travis.yml
deleted file mode 100644
index 1f4cbf54..00000000
--- a/vendor/github.com/davecgh/go-spew/.travis.yml
+++ /dev/null
@@ -1,28 +0,0 @@
-language: go
-go_import_path: github.com/davecgh/go-spew
-go:
- - 1.6.x
- - 1.7.x
- - 1.8.x
- - 1.9.x
- - 1.10.x
- - tip
-sudo: false
-install:
- - go get -v github.com/alecthomas/gometalinter
- - gometalinter --install
-script:
- - export PATH=$PATH:$HOME/gopath/bin
- - export GORACE="halt_on_error=1"
- - test -z "$(gometalinter --disable-all
- --enable=gofmt
- --enable=golint
- --enable=vet
- --enable=gosimple
- --enable=unconvert
- --deadline=4m ./spew | tee /dev/stderr)"
- - go test -v -race -tags safe ./spew
- - go test -v -race -tags testcgo ./spew -covermode=atomic -coverprofile=profile.cov
-after_success:
- - go get -v github.com/mattn/goveralls
- - goveralls -coverprofile=profile.cov -service=travis-ci
diff --git a/vendor/github.com/davecgh/go-spew/README.md b/vendor/github.com/davecgh/go-spew/README.md
deleted file mode 100644
index f6ed02c3..00000000
--- a/vendor/github.com/davecgh/go-spew/README.md
+++ /dev/null
@@ -1,201 +0,0 @@
-go-spew
-=======
-
-[![Build Status](https://img.shields.io/travis/davecgh/go-spew.svg)](https://travis-ci.org/davecgh/go-spew)
-[![ISC License](http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org)
-[![Coverage Status](https://img.shields.io/coveralls/davecgh/go-spew.svg)](https://coveralls.io/r/davecgh/go-spew?branch=master)
-
-Go-spew implements a deep pretty printer for Go data structures to aid in
-debugging. A comprehensive suite of tests with 100% test coverage is provided
-to ensure proper functionality. See `test_coverage.txt` for the gocov coverage
-report. Go-spew is licensed under the liberal ISC license, so it may be used in
-open source or commercial projects.
-
-If you're interested in reading about how this package came to life and some
-of the challenges involved in providing a deep pretty printer, there is a blog
-post about it
-[here](https://web.archive.org/web/20160304013555/https://blog.cyphertite.com/go-spew-a-journey-into-dumping-go-data-structures/).
-
-## Documentation
-
-[![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)](http://godoc.org/github.com/davecgh/go-spew/spew)
-
-Full `go doc` style documentation for the project can be viewed online without
-installing this package by using the excellent GoDoc site here:
-http://godoc.org/github.com/davecgh/go-spew/spew
-
-You can also view the documentation locally once the package is installed with
-the `godoc` tool by running `godoc -http=":6060"` and pointing your browser to
-http://localhost:6060/pkg/github.com/davecgh/go-spew/spew
-
-## Installation
-
-```bash
-$ go get -u github.com/davecgh/go-spew/spew
-```
-
-## Quick Start
-
-Add this import line to the file you're working in:
-
-```Go
-import "github.com/davecgh/go-spew/spew"
-```
-
-To dump a variable with full newlines, indentation, type, and pointer
-information use Dump, Fdump, or Sdump:
-
-```Go
-spew.Dump(myVar1, myVar2, ...)
-spew.Fdump(someWriter, myVar1, myVar2, ...)
-str := spew.Sdump(myVar1, myVar2, ...)
-```
-
-Alternatively, if you would prefer to use format strings with a compacted inline
-printing style, use the convenience wrappers Printf, Fprintf, etc with %v (most
-compact), %+v (adds pointer addresses), %#v (adds types), or %#+v (adds types
-and pointer addresses):
-
-```Go
-spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2)
-spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
-spew.Fprintf(someWriter, "myVar1: %v -- myVar2: %+v", myVar1, myVar2)
-spew.Fprintf(someWriter, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
-```
-
-## Debugging a Web Application Example
-
-Here is an example of how you can use `spew.Sdump()` to help debug a web application. Please be sure to wrap your output using the `html.EscapeString()` function for safety reasons. You should also only use this debugging technique in a development environment, never in production.
-
-```Go
-package main
-
-import (
- "fmt"
- "html"
- "net/http"
-
- "github.com/davecgh/go-spew/spew"
-)
-
-func handler(w http.ResponseWriter, r *http.Request) {
- w.Header().Set("Content-Type", "text/html")
- fmt.Fprintf(w, "Hi there, %s!", r.URL.Path[1:])
- fmt.Fprintf(w, "")
-}
-
-func main() {
- http.HandleFunc("/", handler)
- http.ListenAndServe(":8080", nil)
-}
-```
-
-## Sample Dump Output
-
-```
-(main.Foo) {
- unexportedField: (*main.Bar)(0xf84002e210)({
- flag: (main.Flag) flagTwo,
- data: (uintptr)
- }),
- ExportedField: (map[interface {}]interface {}) {
- (string) "one": (bool) true
- }
-}
-([]uint8) {
- 00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 |............... |
- 00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 |!"#$%&'()*+,-./0|
- 00000020 31 32 |12|
-}
-```
-
-## Sample Formatter Output
-
-Double pointer to a uint8:
-```
- %v: <**>5
- %+v: <**>(0xf8400420d0->0xf8400420c8)5
- %#v: (**uint8)5
- %#+v: (**uint8)(0xf8400420d0->0xf8400420c8)5
-```
-
-Pointer to circular struct with a uint8 field and a pointer to itself:
-```
- %v: <*>{1 <*>}
- %+v: <*>(0xf84003e260){ui8:1 c:<*>(0xf84003e260)}
- %#v: (*main.circular){ui8:(uint8)1 c:(*main.circular)}
- %#+v: (*main.circular)(0xf84003e260){ui8:(uint8)1 c:(*main.circular)(0xf84003e260)}
-```
-
-## Configuration Options
-
-Configuration of spew is handled by fields in the ConfigState type. For
-convenience, all of the top-level functions use a global state available via the
-spew.Config global.
-
-It is also possible to create a ConfigState instance that provides methods
-equivalent to the top-level functions. This allows concurrent configuration
-options. See the ConfigState documentation for more details.
-
-```
-* Indent
- String to use for each indentation level for Dump functions.
- It is a single space by default. A popular alternative is "\t".
-
-* MaxDepth
- Maximum number of levels to descend into nested data structures.
- There is no limit by default.
-
-* DisableMethods
- Disables invocation of error and Stringer interface methods.
- Method invocation is enabled by default.
-
-* DisablePointerMethods
- Disables invocation of error and Stringer interface methods on types
- which only accept pointer receivers from non-pointer variables. This option
- relies on access to the unsafe package, so it will not have any effect when
- running in environments without access to the unsafe package such as Google
- App Engine or with the "safe" build tag specified.
- Pointer method invocation is enabled by default.
-
-* DisablePointerAddresses
- DisablePointerAddresses specifies whether to disable the printing of
- pointer addresses. This is useful when diffing data structures in tests.
-
-* DisableCapacities
- DisableCapacities specifies whether to disable the printing of capacities
- for arrays, slices, maps and channels. This is useful when diffing data
- structures in tests.
-
-* ContinueOnMethod
- Enables recursion into types after invoking error and Stringer interface
- methods. Recursion after method invocation is disabled by default.
-
-* SortKeys
- Specifies map keys should be sorted before being printed. Use
- this to have a more deterministic, diffable output. Note that
- only native types (bool, int, uint, floats, uintptr and string)
- and types which implement error or Stringer interfaces are supported,
- with other types sorted according to the reflect.Value.String() output
- which guarantees display stability. Natural map order is used by
- default.
-
-* SpewKeys
- SpewKeys specifies that, as a last resort attempt, map keys should be
- spewed to strings and sorted by those strings. This is only considered
- if SortKeys is true.
-
-```
-
-## Unsafe Package Dependency
-
-This package relies on the unsafe package to perform some of the more advanced
-features, however it also supports a "limited" mode which allows it to work in
-environments where the unsafe package is not available. By default, it will
-operate in this mode on Google App Engine and when compiled with GopherJS. The
-"safe" build tag may also be specified to force the package to build without
-using the unsafe package.
-
-## License
-
-Go-spew is licensed under the [copyfree](http://copyfree.org) ISC License.
diff --git a/vendor/github.com/davecgh/go-spew/cov_report.sh b/vendor/github.com/davecgh/go-spew/cov_report.sh
deleted file mode 100644
index 9579497e..00000000
--- a/vendor/github.com/davecgh/go-spew/cov_report.sh
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/bin/sh
-
-# This script uses gocov to generate a test coverage report.
-# The gocov tool my be obtained with the following command:
-# go get github.com/axw/gocov/gocov
-#
-# It will be installed to $GOPATH/bin, so ensure that location is in your $PATH.
-
-# Check for gocov.
-if ! type gocov >/dev/null 2>&1; then
- echo >&2 "This script requires the gocov tool."
- echo >&2 "You may obtain it with the following command:"
- echo >&2 "go get github.com/axw/gocov/gocov"
- exit 1
-fi
-
-# Only run the cgo tests if gcc is installed.
-if type gcc >/dev/null 2>&1; then
- (cd spew && gocov test -tags testcgo | gocov report)
-else
- (cd spew && gocov test | gocov report)
-fi
diff --git a/vendor/github.com/davecgh/go-spew/spew/common_test.go b/vendor/github.com/davecgh/go-spew/spew/common_test.go
deleted file mode 100644
index 0f5ce47d..00000000
--- a/vendor/github.com/davecgh/go-spew/spew/common_test.go
+++ /dev/null
@@ -1,298 +0,0 @@
-/*
- * Copyright (c) 2013-2016 Dave Collins
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-package spew_test
-
-import (
- "fmt"
- "reflect"
- "testing"
-
- "github.com/davecgh/go-spew/spew"
-)
-
-// custom type to test Stinger interface on non-pointer receiver.
-type stringer string
-
-// String implements the Stringer interface for testing invocation of custom
-// stringers on types with non-pointer receivers.
-func (s stringer) String() string {
- return "stringer " + string(s)
-}
-
-// custom type to test Stinger interface on pointer receiver.
-type pstringer string
-
-// String implements the Stringer interface for testing invocation of custom
-// stringers on types with only pointer receivers.
-func (s *pstringer) String() string {
- return "stringer " + string(*s)
-}
-
-// xref1 and xref2 are cross referencing structs for testing circular reference
-// detection.
-type xref1 struct {
- ps2 *xref2
-}
-type xref2 struct {
- ps1 *xref1
-}
-
-// indirCir1, indirCir2, and indirCir3 are used to generate an indirect circular
-// reference for testing detection.
-type indirCir1 struct {
- ps2 *indirCir2
-}
-type indirCir2 struct {
- ps3 *indirCir3
-}
-type indirCir3 struct {
- ps1 *indirCir1
-}
-
-// embed is used to test embedded structures.
-type embed struct {
- a string
-}
-
-// embedwrap is used to test embedded structures.
-type embedwrap struct {
- *embed
- e *embed
-}
-
-// panicer is used to intentionally cause a panic for testing spew properly
-// handles them
-type panicer int
-
-func (p panicer) String() string {
- panic("test panic")
-}
-
-// customError is used to test custom error interface invocation.
-type customError int
-
-func (e customError) Error() string {
- return fmt.Sprintf("error: %d", int(e))
-}
-
-// stringizeWants converts a slice of wanted test output into a format suitable
-// for a test error message.
-func stringizeWants(wants []string) string {
- s := ""
- for i, want := range wants {
- if i > 0 {
- s += fmt.Sprintf("want%d: %s", i+1, want)
- } else {
- s += "want: " + want
- }
- }
- return s
-}
-
-// testFailed returns whether or not a test failed by checking if the result
-// of the test is in the slice of wanted strings.
-func testFailed(result string, wants []string) bool {
- for _, want := range wants {
- if result == want {
- return false
- }
- }
- return true
-}
-
-type sortableStruct struct {
- x int
-}
-
-func (ss sortableStruct) String() string {
- return fmt.Sprintf("ss.%d", ss.x)
-}
-
-type unsortableStruct struct {
- x int
-}
-
-type sortTestCase struct {
- input []reflect.Value
- expected []reflect.Value
-}
-
-func helpTestSortValues(tests []sortTestCase, cs *spew.ConfigState, t *testing.T) {
- getInterfaces := func(values []reflect.Value) []interface{} {
- interfaces := []interface{}{}
- for _, v := range values {
- interfaces = append(interfaces, v.Interface())
- }
- return interfaces
- }
-
- for _, test := range tests {
- spew.SortValues(test.input, cs)
- // reflect.DeepEqual cannot really make sense of reflect.Value,
- // probably because of all the pointer tricks. For instance,
- // v(2.0) != v(2.0) on a 32-bits system. Turn them into interface{}
- // instead.
- input := getInterfaces(test.input)
- expected := getInterfaces(test.expected)
- if !reflect.DeepEqual(input, expected) {
- t.Errorf("Sort mismatch:\n %v != %v", input, expected)
- }
- }
-}
-
-// TestSortValues ensures the sort functionality for relect.Value based sorting
-// works as intended.
-func TestSortValues(t *testing.T) {
- v := reflect.ValueOf
-
- a := v("a")
- b := v("b")
- c := v("c")
- embedA := v(embed{"a"})
- embedB := v(embed{"b"})
- embedC := v(embed{"c"})
- tests := []sortTestCase{
- // No values.
- {
- []reflect.Value{},
- []reflect.Value{},
- },
- // Bools.
- {
- []reflect.Value{v(false), v(true), v(false)},
- []reflect.Value{v(false), v(false), v(true)},
- },
- // Ints.
- {
- []reflect.Value{v(2), v(1), v(3)},
- []reflect.Value{v(1), v(2), v(3)},
- },
- // Uints.
- {
- []reflect.Value{v(uint8(2)), v(uint8(1)), v(uint8(3))},
- []reflect.Value{v(uint8(1)), v(uint8(2)), v(uint8(3))},
- },
- // Floats.
- {
- []reflect.Value{v(2.0), v(1.0), v(3.0)},
- []reflect.Value{v(1.0), v(2.0), v(3.0)},
- },
- // Strings.
- {
- []reflect.Value{b, a, c},
- []reflect.Value{a, b, c},
- },
- // Array
- {
- []reflect.Value{v([3]int{3, 2, 1}), v([3]int{1, 3, 2}), v([3]int{1, 2, 3})},
- []reflect.Value{v([3]int{1, 2, 3}), v([3]int{1, 3, 2}), v([3]int{3, 2, 1})},
- },
- // Uintptrs.
- {
- []reflect.Value{v(uintptr(2)), v(uintptr(1)), v(uintptr(3))},
- []reflect.Value{v(uintptr(1)), v(uintptr(2)), v(uintptr(3))},
- },
- // SortableStructs.
- {
- // Note: not sorted - DisableMethods is set.
- []reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})},
- []reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})},
- },
- // UnsortableStructs.
- {
- // Note: not sorted - SpewKeys is false.
- []reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})},
- []reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})},
- },
- // Invalid.
- {
- []reflect.Value{embedB, embedA, embedC},
- []reflect.Value{embedB, embedA, embedC},
- },
- }
- cs := spew.ConfigState{DisableMethods: true, SpewKeys: false}
- helpTestSortValues(tests, &cs, t)
-}
-
-// TestSortValuesWithMethods ensures the sort functionality for relect.Value
-// based sorting works as intended when using string methods.
-func TestSortValuesWithMethods(t *testing.T) {
- v := reflect.ValueOf
-
- a := v("a")
- b := v("b")
- c := v("c")
- tests := []sortTestCase{
- // Ints.
- {
- []reflect.Value{v(2), v(1), v(3)},
- []reflect.Value{v(1), v(2), v(3)},
- },
- // Strings.
- {
- []reflect.Value{b, a, c},
- []reflect.Value{a, b, c},
- },
- // SortableStructs.
- {
- []reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})},
- []reflect.Value{v(sortableStruct{1}), v(sortableStruct{2}), v(sortableStruct{3})},
- },
- // UnsortableStructs.
- {
- // Note: not sorted - SpewKeys is false.
- []reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})},
- []reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})},
- },
- }
- cs := spew.ConfigState{DisableMethods: false, SpewKeys: false}
- helpTestSortValues(tests, &cs, t)
-}
-
-// TestSortValuesWithSpew ensures the sort functionality for relect.Value
-// based sorting works as intended when using spew to stringify keys.
-func TestSortValuesWithSpew(t *testing.T) {
- v := reflect.ValueOf
-
- a := v("a")
- b := v("b")
- c := v("c")
- tests := []sortTestCase{
- // Ints.
- {
- []reflect.Value{v(2), v(1), v(3)},
- []reflect.Value{v(1), v(2), v(3)},
- },
- // Strings.
- {
- []reflect.Value{b, a, c},
- []reflect.Value{a, b, c},
- },
- // SortableStructs.
- {
- []reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})},
- []reflect.Value{v(sortableStruct{1}), v(sortableStruct{2}), v(sortableStruct{3})},
- },
- // UnsortableStructs.
- {
- []reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})},
- []reflect.Value{v(unsortableStruct{1}), v(unsortableStruct{2}), v(unsortableStruct{3})},
- },
- }
- cs := spew.ConfigState{DisableMethods: true, SpewKeys: true}
- helpTestSortValues(tests, &cs, t)
-}
diff --git a/vendor/github.com/davecgh/go-spew/spew/dump_test.go b/vendor/github.com/davecgh/go-spew/spew/dump_test.go
deleted file mode 100644
index 4a31a2ee..00000000
--- a/vendor/github.com/davecgh/go-spew/spew/dump_test.go
+++ /dev/null
@@ -1,1042 +0,0 @@
-/*
- * Copyright (c) 2013-2016 Dave Collins
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-/*
-Test Summary:
-NOTE: For each test, a nil pointer, a single pointer and double pointer to the
-base test element are also tested to ensure proper indirection across all types.
-
-- Max int8, int16, int32, int64, int
-- Max uint8, uint16, uint32, uint64, uint
-- Boolean true and false
-- Standard complex64 and complex128
-- Array containing standard ints
-- Array containing type with custom formatter on pointer receiver only
-- Array containing interfaces
-- Array containing bytes
-- Slice containing standard float32 values
-- Slice containing type with custom formatter on pointer receiver only
-- Slice containing interfaces
-- Slice containing bytes
-- Nil slice
-- Standard string
-- Nil interface
-- Sub-interface
-- Map with string keys and int vals
-- Map with custom formatter type on pointer receiver only keys and vals
-- Map with interface keys and values
-- Map with nil interface value
-- Struct with primitives
-- Struct that contains another struct
-- Struct that contains custom type with Stringer pointer interface via both
- exported and unexported fields
-- Struct that contains embedded struct and field to same struct
-- Uintptr to 0 (null pointer)
-- Uintptr address of real variable
-- Unsafe.Pointer to 0 (null pointer)
-- Unsafe.Pointer to address of real variable
-- Nil channel
-- Standard int channel
-- Function with no params and no returns
-- Function with param and no returns
-- Function with multiple params and multiple returns
-- Struct that is circular through self referencing
-- Structs that are circular through cross referencing
-- Structs that are indirectly circular
-- Type that panics in its Stringer interface
-*/
-
-package spew_test
-
-import (
- "bytes"
- "fmt"
- "testing"
- "unsafe"
-
- "github.com/davecgh/go-spew/spew"
-)
-
-// dumpTest is used to describe a test to be performed against the Dump method.
-type dumpTest struct {
- in interface{}
- wants []string
-}
-
-// dumpTests houses all of the tests to be performed against the Dump method.
-var dumpTests = make([]dumpTest, 0)
-
-// addDumpTest is a helper method to append the passed input and desired result
-// to dumpTests
-func addDumpTest(in interface{}, wants ...string) {
- test := dumpTest{in, wants}
- dumpTests = append(dumpTests, test)
-}
-
-func addIntDumpTests() {
- // Max int8.
- v := int8(127)
- nv := (*int8)(nil)
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "int8"
- vs := "127"
- addDumpTest(v, "("+vt+") "+vs+"\n")
- addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
- addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
- addDumpTest(nv, "(*"+vt+")()\n")
-
- // Max int16.
- v2 := int16(32767)
- nv2 := (*int16)(nil)
- pv2 := &v2
- v2Addr := fmt.Sprintf("%p", pv2)
- pv2Addr := fmt.Sprintf("%p", &pv2)
- v2t := "int16"
- v2s := "32767"
- addDumpTest(v2, "("+v2t+") "+v2s+"\n")
- addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
- addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
- addDumpTest(nv2, "(*"+v2t+")()\n")
-
- // Max int32.
- v3 := int32(2147483647)
- nv3 := (*int32)(nil)
- pv3 := &v3
- v3Addr := fmt.Sprintf("%p", pv3)
- pv3Addr := fmt.Sprintf("%p", &pv3)
- v3t := "int32"
- v3s := "2147483647"
- addDumpTest(v3, "("+v3t+") "+v3s+"\n")
- addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n")
- addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n")
- addDumpTest(nv3, "(*"+v3t+")()\n")
-
- // Max int64.
- v4 := int64(9223372036854775807)
- nv4 := (*int64)(nil)
- pv4 := &v4
- v4Addr := fmt.Sprintf("%p", pv4)
- pv4Addr := fmt.Sprintf("%p", &pv4)
- v4t := "int64"
- v4s := "9223372036854775807"
- addDumpTest(v4, "("+v4t+") "+v4s+"\n")
- addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n")
- addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n")
- addDumpTest(nv4, "(*"+v4t+")()\n")
-
- // Max int.
- v5 := int(2147483647)
- nv5 := (*int)(nil)
- pv5 := &v5
- v5Addr := fmt.Sprintf("%p", pv5)
- pv5Addr := fmt.Sprintf("%p", &pv5)
- v5t := "int"
- v5s := "2147483647"
- addDumpTest(v5, "("+v5t+") "+v5s+"\n")
- addDumpTest(pv5, "(*"+v5t+")("+v5Addr+")("+v5s+")\n")
- addDumpTest(&pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")("+v5s+")\n")
- addDumpTest(nv5, "(*"+v5t+")()\n")
-}
-
-func addUintDumpTests() {
- // Max uint8.
- v := uint8(255)
- nv := (*uint8)(nil)
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "uint8"
- vs := "255"
- addDumpTest(v, "("+vt+") "+vs+"\n")
- addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
- addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
- addDumpTest(nv, "(*"+vt+")()\n")
-
- // Max uint16.
- v2 := uint16(65535)
- nv2 := (*uint16)(nil)
- pv2 := &v2
- v2Addr := fmt.Sprintf("%p", pv2)
- pv2Addr := fmt.Sprintf("%p", &pv2)
- v2t := "uint16"
- v2s := "65535"
- addDumpTest(v2, "("+v2t+") "+v2s+"\n")
- addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
- addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
- addDumpTest(nv2, "(*"+v2t+")()\n")
-
- // Max uint32.
- v3 := uint32(4294967295)
- nv3 := (*uint32)(nil)
- pv3 := &v3
- v3Addr := fmt.Sprintf("%p", pv3)
- pv3Addr := fmt.Sprintf("%p", &pv3)
- v3t := "uint32"
- v3s := "4294967295"
- addDumpTest(v3, "("+v3t+") "+v3s+"\n")
- addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n")
- addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n")
- addDumpTest(nv3, "(*"+v3t+")()\n")
-
- // Max uint64.
- v4 := uint64(18446744073709551615)
- nv4 := (*uint64)(nil)
- pv4 := &v4
- v4Addr := fmt.Sprintf("%p", pv4)
- pv4Addr := fmt.Sprintf("%p", &pv4)
- v4t := "uint64"
- v4s := "18446744073709551615"
- addDumpTest(v4, "("+v4t+") "+v4s+"\n")
- addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n")
- addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n")
- addDumpTest(nv4, "(*"+v4t+")()\n")
-
- // Max uint.
- v5 := uint(4294967295)
- nv5 := (*uint)(nil)
- pv5 := &v5
- v5Addr := fmt.Sprintf("%p", pv5)
- pv5Addr := fmt.Sprintf("%p", &pv5)
- v5t := "uint"
- v5s := "4294967295"
- addDumpTest(v5, "("+v5t+") "+v5s+"\n")
- addDumpTest(pv5, "(*"+v5t+")("+v5Addr+")("+v5s+")\n")
- addDumpTest(&pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")("+v5s+")\n")
- addDumpTest(nv5, "(*"+v5t+")()\n")
-}
-
-func addBoolDumpTests() {
- // Boolean true.
- v := bool(true)
- nv := (*bool)(nil)
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "bool"
- vs := "true"
- addDumpTest(v, "("+vt+") "+vs+"\n")
- addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
- addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
- addDumpTest(nv, "(*"+vt+")()\n")
-
- // Boolean false.
- v2 := bool(false)
- pv2 := &v2
- v2Addr := fmt.Sprintf("%p", pv2)
- pv2Addr := fmt.Sprintf("%p", &pv2)
- v2t := "bool"
- v2s := "false"
- addDumpTest(v2, "("+v2t+") "+v2s+"\n")
- addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
- addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
-}
-
-func addFloatDumpTests() {
- // Standard float32.
- v := float32(3.1415)
- nv := (*float32)(nil)
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "float32"
- vs := "3.1415"
- addDumpTest(v, "("+vt+") "+vs+"\n")
- addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
- addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
- addDumpTest(nv, "(*"+vt+")()\n")
-
- // Standard float64.
- v2 := float64(3.1415926)
- nv2 := (*float64)(nil)
- pv2 := &v2
- v2Addr := fmt.Sprintf("%p", pv2)
- pv2Addr := fmt.Sprintf("%p", &pv2)
- v2t := "float64"
- v2s := "3.1415926"
- addDumpTest(v2, "("+v2t+") "+v2s+"\n")
- addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
- addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
- addDumpTest(nv2, "(*"+v2t+")()\n")
-}
-
-func addComplexDumpTests() {
- // Standard complex64.
- v := complex(float32(6), -2)
- nv := (*complex64)(nil)
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "complex64"
- vs := "(6-2i)"
- addDumpTest(v, "("+vt+") "+vs+"\n")
- addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
- addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
- addDumpTest(nv, "(*"+vt+")()\n")
-
- // Standard complex128.
- v2 := complex(float64(-6), 2)
- nv2 := (*complex128)(nil)
- pv2 := &v2
- v2Addr := fmt.Sprintf("%p", pv2)
- pv2Addr := fmt.Sprintf("%p", &pv2)
- v2t := "complex128"
- v2s := "(-6+2i)"
- addDumpTest(v2, "("+v2t+") "+v2s+"\n")
- addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
- addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
- addDumpTest(nv2, "(*"+v2t+")()\n")
-}
-
-func addArrayDumpTests() {
- // Array containing standard ints.
- v := [3]int{1, 2, 3}
- vLen := fmt.Sprintf("%d", len(v))
- vCap := fmt.Sprintf("%d", cap(v))
- nv := (*[3]int)(nil)
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "int"
- vs := "(len=" + vLen + " cap=" + vCap + ") {\n (" + vt + ") 1,\n (" +
- vt + ") 2,\n (" + vt + ") 3\n}"
- addDumpTest(v, "([3]"+vt+") "+vs+"\n")
- addDumpTest(pv, "(*[3]"+vt+")("+vAddr+")("+vs+")\n")
- addDumpTest(&pv, "(**[3]"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
- addDumpTest(nv, "(*[3]"+vt+")()\n")
-
- // Array containing type with custom formatter on pointer receiver only.
- v2i0 := pstringer("1")
- v2i1 := pstringer("2")
- v2i2 := pstringer("3")
- v2 := [3]pstringer{v2i0, v2i1, v2i2}
- v2i0Len := fmt.Sprintf("%d", len(v2i0))
- v2i1Len := fmt.Sprintf("%d", len(v2i1))
- v2i2Len := fmt.Sprintf("%d", len(v2i2))
- v2Len := fmt.Sprintf("%d", len(v2))
- v2Cap := fmt.Sprintf("%d", cap(v2))
- nv2 := (*[3]pstringer)(nil)
- pv2 := &v2
- v2Addr := fmt.Sprintf("%p", pv2)
- pv2Addr := fmt.Sprintf("%p", &pv2)
- v2t := "spew_test.pstringer"
- v2sp := "(len=" + v2Len + " cap=" + v2Cap + ") {\n (" + v2t +
- ") (len=" + v2i0Len + ") stringer 1,\n (" + v2t +
- ") (len=" + v2i1Len + ") stringer 2,\n (" + v2t +
- ") (len=" + v2i2Len + ") " + "stringer 3\n}"
- v2s := v2sp
- if spew.UnsafeDisabled {
- v2s = "(len=" + v2Len + " cap=" + v2Cap + ") {\n (" + v2t +
- ") (len=" + v2i0Len + ") \"1\",\n (" + v2t + ") (len=" +
- v2i1Len + ") \"2\",\n (" + v2t + ") (len=" + v2i2Len +
- ") " + "\"3\"\n}"
- }
- addDumpTest(v2, "([3]"+v2t+") "+v2s+"\n")
- addDumpTest(pv2, "(*[3]"+v2t+")("+v2Addr+")("+v2sp+")\n")
- addDumpTest(&pv2, "(**[3]"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2sp+")\n")
- addDumpTest(nv2, "(*[3]"+v2t+")()\n")
-
- // Array containing interfaces.
- v3i0 := "one"
- v3 := [3]interface{}{v3i0, int(2), uint(3)}
- v3i0Len := fmt.Sprintf("%d", len(v3i0))
- v3Len := fmt.Sprintf("%d", len(v3))
- v3Cap := fmt.Sprintf("%d", cap(v3))
- nv3 := (*[3]interface{})(nil)
- pv3 := &v3
- v3Addr := fmt.Sprintf("%p", pv3)
- pv3Addr := fmt.Sprintf("%p", &pv3)
- v3t := "[3]interface {}"
- v3t2 := "string"
- v3t3 := "int"
- v3t4 := "uint"
- v3s := "(len=" + v3Len + " cap=" + v3Cap + ") {\n (" + v3t2 + ") " +
- "(len=" + v3i0Len + ") \"one\",\n (" + v3t3 + ") 2,\n (" +
- v3t4 + ") 3\n}"
- addDumpTest(v3, "("+v3t+") "+v3s+"\n")
- addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n")
- addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n")
- addDumpTest(nv3, "(*"+v3t+")()\n")
-
- // Array containing bytes.
- v4 := [34]byte{
- 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
- 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
- 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
- 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
- 0x31, 0x32,
- }
- v4Len := fmt.Sprintf("%d", len(v4))
- v4Cap := fmt.Sprintf("%d", cap(v4))
- nv4 := (*[34]byte)(nil)
- pv4 := &v4
- v4Addr := fmt.Sprintf("%p", pv4)
- pv4Addr := fmt.Sprintf("%p", &pv4)
- v4t := "[34]uint8"
- v4s := "(len=" + v4Len + " cap=" + v4Cap + ") " +
- "{\n 00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20" +
- " |............... |\n" +
- " 00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30" +
- " |!\"#$%&'()*+,-./0|\n" +
- " 00000020 31 32 " +
- " |12|\n}"
- addDumpTest(v4, "("+v4t+") "+v4s+"\n")
- addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n")
- addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n")
- addDumpTest(nv4, "(*"+v4t+")()\n")
-}
-
-func addSliceDumpTests() {
- // Slice containing standard float32 values.
- v := []float32{3.14, 6.28, 12.56}
- vLen := fmt.Sprintf("%d", len(v))
- vCap := fmt.Sprintf("%d", cap(v))
- nv := (*[]float32)(nil)
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "float32"
- vs := "(len=" + vLen + " cap=" + vCap + ") {\n (" + vt + ") 3.14,\n (" +
- vt + ") 6.28,\n (" + vt + ") 12.56\n}"
- addDumpTest(v, "([]"+vt+") "+vs+"\n")
- addDumpTest(pv, "(*[]"+vt+")("+vAddr+")("+vs+")\n")
- addDumpTest(&pv, "(**[]"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
- addDumpTest(nv, "(*[]"+vt+")()\n")
-
- // Slice containing type with custom formatter on pointer receiver only.
- v2i0 := pstringer("1")
- v2i1 := pstringer("2")
- v2i2 := pstringer("3")
- v2 := []pstringer{v2i0, v2i1, v2i2}
- v2i0Len := fmt.Sprintf("%d", len(v2i0))
- v2i1Len := fmt.Sprintf("%d", len(v2i1))
- v2i2Len := fmt.Sprintf("%d", len(v2i2))
- v2Len := fmt.Sprintf("%d", len(v2))
- v2Cap := fmt.Sprintf("%d", cap(v2))
- nv2 := (*[]pstringer)(nil)
- pv2 := &v2
- v2Addr := fmt.Sprintf("%p", pv2)
- pv2Addr := fmt.Sprintf("%p", &pv2)
- v2t := "spew_test.pstringer"
- v2s := "(len=" + v2Len + " cap=" + v2Cap + ") {\n (" + v2t + ") (len=" +
- v2i0Len + ") stringer 1,\n (" + v2t + ") (len=" + v2i1Len +
- ") stringer 2,\n (" + v2t + ") (len=" + v2i2Len + ") " +
- "stringer 3\n}"
- addDumpTest(v2, "([]"+v2t+") "+v2s+"\n")
- addDumpTest(pv2, "(*[]"+v2t+")("+v2Addr+")("+v2s+")\n")
- addDumpTest(&pv2, "(**[]"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
- addDumpTest(nv2, "(*[]"+v2t+")()\n")
-
- // Slice containing interfaces.
- v3i0 := "one"
- v3 := []interface{}{v3i0, int(2), uint(3), nil}
- v3i0Len := fmt.Sprintf("%d", len(v3i0))
- v3Len := fmt.Sprintf("%d", len(v3))
- v3Cap := fmt.Sprintf("%d", cap(v3))
- nv3 := (*[]interface{})(nil)
- pv3 := &v3
- v3Addr := fmt.Sprintf("%p", pv3)
- pv3Addr := fmt.Sprintf("%p", &pv3)
- v3t := "[]interface {}"
- v3t2 := "string"
- v3t3 := "int"
- v3t4 := "uint"
- v3t5 := "interface {}"
- v3s := "(len=" + v3Len + " cap=" + v3Cap + ") {\n (" + v3t2 + ") " +
- "(len=" + v3i0Len + ") \"one\",\n (" + v3t3 + ") 2,\n (" +
- v3t4 + ") 3,\n (" + v3t5 + ") \n}"
- addDumpTest(v3, "("+v3t+") "+v3s+"\n")
- addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n")
- addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n")
- addDumpTest(nv3, "(*"+v3t+")()\n")
-
- // Slice containing bytes.
- v4 := []byte{
- 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
- 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
- 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
- 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
- 0x31, 0x32,
- }
- v4Len := fmt.Sprintf("%d", len(v4))
- v4Cap := fmt.Sprintf("%d", cap(v4))
- nv4 := (*[]byte)(nil)
- pv4 := &v4
- v4Addr := fmt.Sprintf("%p", pv4)
- pv4Addr := fmt.Sprintf("%p", &pv4)
- v4t := "[]uint8"
- v4s := "(len=" + v4Len + " cap=" + v4Cap + ") " +
- "{\n 00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20" +
- " |............... |\n" +
- " 00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30" +
- " |!\"#$%&'()*+,-./0|\n" +
- " 00000020 31 32 " +
- " |12|\n}"
- addDumpTest(v4, "("+v4t+") "+v4s+"\n")
- addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n")
- addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n")
- addDumpTest(nv4, "(*"+v4t+")()\n")
-
- // Nil slice.
- v5 := []int(nil)
- nv5 := (*[]int)(nil)
- pv5 := &v5
- v5Addr := fmt.Sprintf("%p", pv5)
- pv5Addr := fmt.Sprintf("%p", &pv5)
- v5t := "[]int"
- v5s := ""
- addDumpTest(v5, "("+v5t+") "+v5s+"\n")
- addDumpTest(pv5, "(*"+v5t+")("+v5Addr+")("+v5s+")\n")
- addDumpTest(&pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")("+v5s+")\n")
- addDumpTest(nv5, "(*"+v5t+")()\n")
-}
-
-func addStringDumpTests() {
- // Standard string.
- v := "test"
- vLen := fmt.Sprintf("%d", len(v))
- nv := (*string)(nil)
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "string"
- vs := "(len=" + vLen + ") \"test\""
- addDumpTest(v, "("+vt+") "+vs+"\n")
- addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
- addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
- addDumpTest(nv, "(*"+vt+")()\n")
-}
-
-func addInterfaceDumpTests() {
- // Nil interface.
- var v interface{}
- nv := (*interface{})(nil)
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "interface {}"
- vs := ""
- addDumpTest(v, "("+vt+") "+vs+"\n")
- addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
- addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
- addDumpTest(nv, "(*"+vt+")()\n")
-
- // Sub-interface.
- v2 := interface{}(uint16(65535))
- pv2 := &v2
- v2Addr := fmt.Sprintf("%p", pv2)
- pv2Addr := fmt.Sprintf("%p", &pv2)
- v2t := "uint16"
- v2s := "65535"
- addDumpTest(v2, "("+v2t+") "+v2s+"\n")
- addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
- addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
-}
-
-func addMapDumpTests() {
- // Map with string keys and int vals.
- k := "one"
- kk := "two"
- m := map[string]int{k: 1, kk: 2}
- klen := fmt.Sprintf("%d", len(k)) // not kLen to shut golint up
- kkLen := fmt.Sprintf("%d", len(kk))
- mLen := fmt.Sprintf("%d", len(m))
- nilMap := map[string]int(nil)
- nm := (*map[string]int)(nil)
- pm := &m
- mAddr := fmt.Sprintf("%p", pm)
- pmAddr := fmt.Sprintf("%p", &pm)
- mt := "map[string]int"
- mt1 := "string"
- mt2 := "int"
- ms := "(len=" + mLen + ") {\n (" + mt1 + ") (len=" + klen + ") " +
- "\"one\": (" + mt2 + ") 1,\n (" + mt1 + ") (len=" + kkLen +
- ") \"two\": (" + mt2 + ") 2\n}"
- ms2 := "(len=" + mLen + ") {\n (" + mt1 + ") (len=" + kkLen + ") " +
- "\"two\": (" + mt2 + ") 2,\n (" + mt1 + ") (len=" + klen +
- ") \"one\": (" + mt2 + ") 1\n}"
- addDumpTest(m, "("+mt+") "+ms+"\n", "("+mt+") "+ms2+"\n")
- addDumpTest(pm, "(*"+mt+")("+mAddr+")("+ms+")\n",
- "(*"+mt+")("+mAddr+")("+ms2+")\n")
- addDumpTest(&pm, "(**"+mt+")("+pmAddr+"->"+mAddr+")("+ms+")\n",
- "(**"+mt+")("+pmAddr+"->"+mAddr+")("+ms2+")\n")
- addDumpTest(nm, "(*"+mt+")()\n")
- addDumpTest(nilMap, "("+mt+") \n")
-
- // Map with custom formatter type on pointer receiver only keys and vals.
- k2 := pstringer("one")
- v2 := pstringer("1")
- m2 := map[pstringer]pstringer{k2: v2}
- k2Len := fmt.Sprintf("%d", len(k2))
- v2Len := fmt.Sprintf("%d", len(v2))
- m2Len := fmt.Sprintf("%d", len(m2))
- nilMap2 := map[pstringer]pstringer(nil)
- nm2 := (*map[pstringer]pstringer)(nil)
- pm2 := &m2
- m2Addr := fmt.Sprintf("%p", pm2)
- pm2Addr := fmt.Sprintf("%p", &pm2)
- m2t := "map[spew_test.pstringer]spew_test.pstringer"
- m2t1 := "spew_test.pstringer"
- m2t2 := "spew_test.pstringer"
- m2s := "(len=" + m2Len + ") {\n (" + m2t1 + ") (len=" + k2Len + ") " +
- "stringer one: (" + m2t2 + ") (len=" + v2Len + ") stringer 1\n}"
- if spew.UnsafeDisabled {
- m2s = "(len=" + m2Len + ") {\n (" + m2t1 + ") (len=" + k2Len +
- ") " + "\"one\": (" + m2t2 + ") (len=" + v2Len +
- ") \"1\"\n}"
- }
- addDumpTest(m2, "("+m2t+") "+m2s+"\n")
- addDumpTest(pm2, "(*"+m2t+")("+m2Addr+")("+m2s+")\n")
- addDumpTest(&pm2, "(**"+m2t+")("+pm2Addr+"->"+m2Addr+")("+m2s+")\n")
- addDumpTest(nm2, "(*"+m2t+")()\n")
- addDumpTest(nilMap2, "("+m2t+") \n")
-
- // Map with interface keys and values.
- k3 := "one"
- k3Len := fmt.Sprintf("%d", len(k3))
- m3 := map[interface{}]interface{}{k3: 1}
- m3Len := fmt.Sprintf("%d", len(m3))
- nilMap3 := map[interface{}]interface{}(nil)
- nm3 := (*map[interface{}]interface{})(nil)
- pm3 := &m3
- m3Addr := fmt.Sprintf("%p", pm3)
- pm3Addr := fmt.Sprintf("%p", &pm3)
- m3t := "map[interface {}]interface {}"
- m3t1 := "string"
- m3t2 := "int"
- m3s := "(len=" + m3Len + ") {\n (" + m3t1 + ") (len=" + k3Len + ") " +
- "\"one\": (" + m3t2 + ") 1\n}"
- addDumpTest(m3, "("+m3t+") "+m3s+"\n")
- addDumpTest(pm3, "(*"+m3t+")("+m3Addr+")("+m3s+")\n")
- addDumpTest(&pm3, "(**"+m3t+")("+pm3Addr+"->"+m3Addr+")("+m3s+")\n")
- addDumpTest(nm3, "(*"+m3t+")()\n")
- addDumpTest(nilMap3, "("+m3t+") \n")
-
- // Map with nil interface value.
- k4 := "nil"
- k4Len := fmt.Sprintf("%d", len(k4))
- m4 := map[string]interface{}{k4: nil}
- m4Len := fmt.Sprintf("%d", len(m4))
- nilMap4 := map[string]interface{}(nil)
- nm4 := (*map[string]interface{})(nil)
- pm4 := &m4
- m4Addr := fmt.Sprintf("%p", pm4)
- pm4Addr := fmt.Sprintf("%p", &pm4)
- m4t := "map[string]interface {}"
- m4t1 := "string"
- m4t2 := "interface {}"
- m4s := "(len=" + m4Len + ") {\n (" + m4t1 + ") (len=" + k4Len + ")" +
- " \"nil\": (" + m4t2 + ") \n}"
- addDumpTest(m4, "("+m4t+") "+m4s+"\n")
- addDumpTest(pm4, "(*"+m4t+")("+m4Addr+")("+m4s+")\n")
- addDumpTest(&pm4, "(**"+m4t+")("+pm4Addr+"->"+m4Addr+")("+m4s+")\n")
- addDumpTest(nm4, "(*"+m4t+")()\n")
- addDumpTest(nilMap4, "("+m4t+") \n")
-}
-
-func addStructDumpTests() {
- // Struct with primitives.
- type s1 struct {
- a int8
- b uint8
- }
- v := s1{127, 255}
- nv := (*s1)(nil)
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "spew_test.s1"
- vt2 := "int8"
- vt3 := "uint8"
- vs := "{\n a: (" + vt2 + ") 127,\n b: (" + vt3 + ") 255\n}"
- addDumpTest(v, "("+vt+") "+vs+"\n")
- addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
- addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
- addDumpTest(nv, "(*"+vt+")()\n")
-
- // Struct that contains another struct.
- type s2 struct {
- s1 s1
- b bool
- }
- v2 := s2{s1{127, 255}, true}
- nv2 := (*s2)(nil)
- pv2 := &v2
- v2Addr := fmt.Sprintf("%p", pv2)
- pv2Addr := fmt.Sprintf("%p", &pv2)
- v2t := "spew_test.s2"
- v2t2 := "spew_test.s1"
- v2t3 := "int8"
- v2t4 := "uint8"
- v2t5 := "bool"
- v2s := "{\n s1: (" + v2t2 + ") {\n a: (" + v2t3 + ") 127,\n b: (" +
- v2t4 + ") 255\n },\n b: (" + v2t5 + ") true\n}"
- addDumpTest(v2, "("+v2t+") "+v2s+"\n")
- addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
- addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
- addDumpTest(nv2, "(*"+v2t+")()\n")
-
- // Struct that contains custom type with Stringer pointer interface via both
- // exported and unexported fields.
- type s3 struct {
- s pstringer
- S pstringer
- }
- v3 := s3{"test", "test2"}
- nv3 := (*s3)(nil)
- pv3 := &v3
- v3Addr := fmt.Sprintf("%p", pv3)
- pv3Addr := fmt.Sprintf("%p", &pv3)
- v3t := "spew_test.s3"
- v3t2 := "spew_test.pstringer"
- v3s := "{\n s: (" + v3t2 + ") (len=4) stringer test,\n S: (" + v3t2 +
- ") (len=5) stringer test2\n}"
- v3sp := v3s
- if spew.UnsafeDisabled {
- v3s = "{\n s: (" + v3t2 + ") (len=4) \"test\",\n S: (" +
- v3t2 + ") (len=5) \"test2\"\n}"
- v3sp = "{\n s: (" + v3t2 + ") (len=4) \"test\",\n S: (" +
- v3t2 + ") (len=5) stringer test2\n}"
- }
- addDumpTest(v3, "("+v3t+") "+v3s+"\n")
- addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3sp+")\n")
- addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3sp+")\n")
- addDumpTest(nv3, "(*"+v3t+")()\n")
-
- // Struct that contains embedded struct and field to same struct.
- e := embed{"embedstr"}
- eLen := fmt.Sprintf("%d", len("embedstr"))
- v4 := embedwrap{embed: &e, e: &e}
- nv4 := (*embedwrap)(nil)
- pv4 := &v4
- eAddr := fmt.Sprintf("%p", &e)
- v4Addr := fmt.Sprintf("%p", pv4)
- pv4Addr := fmt.Sprintf("%p", &pv4)
- v4t := "spew_test.embedwrap"
- v4t2 := "spew_test.embed"
- v4t3 := "string"
- v4s := "{\n embed: (*" + v4t2 + ")(" + eAddr + ")({\n a: (" + v4t3 +
- ") (len=" + eLen + ") \"embedstr\"\n }),\n e: (*" + v4t2 +
- ")(" + eAddr + ")({\n a: (" + v4t3 + ") (len=" + eLen + ")" +
- " \"embedstr\"\n })\n}"
- addDumpTest(v4, "("+v4t+") "+v4s+"\n")
- addDumpTest(pv4, "(*"+v4t+")("+v4Addr+")("+v4s+")\n")
- addDumpTest(&pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")("+v4s+")\n")
- addDumpTest(nv4, "(*"+v4t+")()\n")
-}
-
-func addUintptrDumpTests() {
- // Null pointer.
- v := uintptr(0)
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "uintptr"
- vs := ""
- addDumpTest(v, "("+vt+") "+vs+"\n")
- addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
- addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
-
- // Address of real variable.
- i := 1
- v2 := uintptr(unsafe.Pointer(&i))
- nv2 := (*uintptr)(nil)
- pv2 := &v2
- v2Addr := fmt.Sprintf("%p", pv2)
- pv2Addr := fmt.Sprintf("%p", &pv2)
- v2t := "uintptr"
- v2s := fmt.Sprintf("%p", &i)
- addDumpTest(v2, "("+v2t+") "+v2s+"\n")
- addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
- addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
- addDumpTest(nv2, "(*"+v2t+")()\n")
-}
-
-func addUnsafePointerDumpTests() {
- // Null pointer.
- v := unsafe.Pointer(nil)
- nv := (*unsafe.Pointer)(nil)
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "unsafe.Pointer"
- vs := ""
- addDumpTest(v, "("+vt+") "+vs+"\n")
- addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
- addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
- addDumpTest(nv, "(*"+vt+")()\n")
-
- // Address of real variable.
- i := 1
- v2 := unsafe.Pointer(&i)
- pv2 := &v2
- v2Addr := fmt.Sprintf("%p", pv2)
- pv2Addr := fmt.Sprintf("%p", &pv2)
- v2t := "unsafe.Pointer"
- v2s := fmt.Sprintf("%p", &i)
- addDumpTest(v2, "("+v2t+") "+v2s+"\n")
- addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
- addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
- addDumpTest(nv, "(*"+vt+")()\n")
-}
-
-func addChanDumpTests() {
- // Nil channel.
- var v chan int
- pv := &v
- nv := (*chan int)(nil)
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "chan int"
- vs := ""
- addDumpTest(v, "("+vt+") "+vs+"\n")
- addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
- addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
- addDumpTest(nv, "(*"+vt+")()\n")
-
- // Real channel.
- v2 := make(chan int)
- pv2 := &v2
- v2Addr := fmt.Sprintf("%p", pv2)
- pv2Addr := fmt.Sprintf("%p", &pv2)
- v2t := "chan int"
- v2s := fmt.Sprintf("%p", v2)
- addDumpTest(v2, "("+v2t+") "+v2s+"\n")
- addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
- addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
-}
-
-func addFuncDumpTests() {
- // Function with no params and no returns.
- v := addIntDumpTests
- nv := (*func())(nil)
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "func()"
- vs := fmt.Sprintf("%p", v)
- addDumpTest(v, "("+vt+") "+vs+"\n")
- addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
- addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
- addDumpTest(nv, "(*"+vt+")()\n")
-
- // Function with param and no returns.
- v2 := TestDump
- nv2 := (*func(*testing.T))(nil)
- pv2 := &v2
- v2Addr := fmt.Sprintf("%p", pv2)
- pv2Addr := fmt.Sprintf("%p", &pv2)
- v2t := "func(*testing.T)"
- v2s := fmt.Sprintf("%p", v2)
- addDumpTest(v2, "("+v2t+") "+v2s+"\n")
- addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s+")\n")
- addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s+")\n")
- addDumpTest(nv2, "(*"+v2t+")()\n")
-
- // Function with multiple params and multiple returns.
- var v3 = func(i int, s string) (b bool, err error) {
- return true, nil
- }
- nv3 := (*func(int, string) (bool, error))(nil)
- pv3 := &v3
- v3Addr := fmt.Sprintf("%p", pv3)
- pv3Addr := fmt.Sprintf("%p", &pv3)
- v3t := "func(int, string) (bool, error)"
- v3s := fmt.Sprintf("%p", v3)
- addDumpTest(v3, "("+v3t+") "+v3s+"\n")
- addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s+")\n")
- addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s+")\n")
- addDumpTest(nv3, "(*"+v3t+")()\n")
-}
-
-func addCircularDumpTests() {
- // Struct that is circular through self referencing.
- type circular struct {
- c *circular
- }
- v := circular{nil}
- v.c = &v
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "spew_test.circular"
- vs := "{\n c: (*" + vt + ")(" + vAddr + ")({\n c: (*" + vt + ")(" +
- vAddr + ")()\n })\n}"
- vs2 := "{\n c: (*" + vt + ")(" + vAddr + ")()\n}"
- addDumpTest(v, "("+vt+") "+vs+"\n")
- addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs2+")\n")
- addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs2+")\n")
-
- // Structs that are circular through cross referencing.
- v2 := xref1{nil}
- ts2 := xref2{&v2}
- v2.ps2 = &ts2
- pv2 := &v2
- ts2Addr := fmt.Sprintf("%p", &ts2)
- v2Addr := fmt.Sprintf("%p", pv2)
- pv2Addr := fmt.Sprintf("%p", &pv2)
- v2t := "spew_test.xref1"
- v2t2 := "spew_test.xref2"
- v2s := "{\n ps2: (*" + v2t2 + ")(" + ts2Addr + ")({\n ps1: (*" + v2t +
- ")(" + v2Addr + ")({\n ps2: (*" + v2t2 + ")(" + ts2Addr +
- ")()\n })\n })\n}"
- v2s2 := "{\n ps2: (*" + v2t2 + ")(" + ts2Addr + ")({\n ps1: (*" + v2t +
- ")(" + v2Addr + ")()\n })\n}"
- addDumpTest(v2, "("+v2t+") "+v2s+"\n")
- addDumpTest(pv2, "(*"+v2t+")("+v2Addr+")("+v2s2+")\n")
- addDumpTest(&pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")("+v2s2+")\n")
-
- // Structs that are indirectly circular.
- v3 := indirCir1{nil}
- tic2 := indirCir2{nil}
- tic3 := indirCir3{&v3}
- tic2.ps3 = &tic3
- v3.ps2 = &tic2
- pv3 := &v3
- tic2Addr := fmt.Sprintf("%p", &tic2)
- tic3Addr := fmt.Sprintf("%p", &tic3)
- v3Addr := fmt.Sprintf("%p", pv3)
- pv3Addr := fmt.Sprintf("%p", &pv3)
- v3t := "spew_test.indirCir1"
- v3t2 := "spew_test.indirCir2"
- v3t3 := "spew_test.indirCir3"
- v3s := "{\n ps2: (*" + v3t2 + ")(" + tic2Addr + ")({\n ps3: (*" + v3t3 +
- ")(" + tic3Addr + ")({\n ps1: (*" + v3t + ")(" + v3Addr +
- ")({\n ps2: (*" + v3t2 + ")(" + tic2Addr +
- ")()\n })\n })\n })\n}"
- v3s2 := "{\n ps2: (*" + v3t2 + ")(" + tic2Addr + ")({\n ps3: (*" + v3t3 +
- ")(" + tic3Addr + ")({\n ps1: (*" + v3t + ")(" + v3Addr +
- ")()\n })\n })\n}"
- addDumpTest(v3, "("+v3t+") "+v3s+"\n")
- addDumpTest(pv3, "(*"+v3t+")("+v3Addr+")("+v3s2+")\n")
- addDumpTest(&pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")("+v3s2+")\n")
-}
-
-func addPanicDumpTests() {
- // Type that panics in its Stringer interface.
- v := panicer(127)
- nv := (*panicer)(nil)
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "spew_test.panicer"
- vs := "(PANIC=test panic)127"
- addDumpTest(v, "("+vt+") "+vs+"\n")
- addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
- addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
- addDumpTest(nv, "(*"+vt+")()\n")
-}
-
-func addErrorDumpTests() {
- // Type that has a custom Error interface.
- v := customError(127)
- nv := (*customError)(nil)
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "spew_test.customError"
- vs := "error: 127"
- addDumpTest(v, "("+vt+") "+vs+"\n")
- addDumpTest(pv, "(*"+vt+")("+vAddr+")("+vs+")\n")
- addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")("+vs+")\n")
- addDumpTest(nv, "(*"+vt+")()\n")
-}
-
-// TestDump executes all of the tests described by dumpTests.
-func TestDump(t *testing.T) {
- // Setup tests.
- addIntDumpTests()
- addUintDumpTests()
- addBoolDumpTests()
- addFloatDumpTests()
- addComplexDumpTests()
- addArrayDumpTests()
- addSliceDumpTests()
- addStringDumpTests()
- addInterfaceDumpTests()
- addMapDumpTests()
- addStructDumpTests()
- addUintptrDumpTests()
- addUnsafePointerDumpTests()
- addChanDumpTests()
- addFuncDumpTests()
- addCircularDumpTests()
- addPanicDumpTests()
- addErrorDumpTests()
- addCgoDumpTests()
-
- t.Logf("Running %d tests", len(dumpTests))
- for i, test := range dumpTests {
- buf := new(bytes.Buffer)
- spew.Fdump(buf, test.in)
- s := buf.String()
- if testFailed(s, test.wants) {
- t.Errorf("Dump #%d\n got: %s %s", i, s, stringizeWants(test.wants))
- continue
- }
- }
-}
-
-func TestDumpSortedKeys(t *testing.T) {
- cfg := spew.ConfigState{SortKeys: true}
- s := cfg.Sdump(map[int]string{1: "1", 3: "3", 2: "2"})
- expected := "(map[int]string) (len=3) {\n(int) 1: (string) (len=1) " +
- "\"1\",\n(int) 2: (string) (len=1) \"2\",\n(int) 3: (string) " +
- "(len=1) \"3\"\n" +
- "}\n"
- if s != expected {
- t.Errorf("Sorted keys mismatch:\n %v %v", s, expected)
- }
-
- s = cfg.Sdump(map[stringer]int{"1": 1, "3": 3, "2": 2})
- expected = "(map[spew_test.stringer]int) (len=3) {\n" +
- "(spew_test.stringer) (len=1) stringer 1: (int) 1,\n" +
- "(spew_test.stringer) (len=1) stringer 2: (int) 2,\n" +
- "(spew_test.stringer) (len=1) stringer 3: (int) 3\n" +
- "}\n"
- if s != expected {
- t.Errorf("Sorted keys mismatch:\n %v %v", s, expected)
- }
-
- s = cfg.Sdump(map[pstringer]int{pstringer("1"): 1, pstringer("3"): 3, pstringer("2"): 2})
- expected = "(map[spew_test.pstringer]int) (len=3) {\n" +
- "(spew_test.pstringer) (len=1) stringer 1: (int) 1,\n" +
- "(spew_test.pstringer) (len=1) stringer 2: (int) 2,\n" +
- "(spew_test.pstringer) (len=1) stringer 3: (int) 3\n" +
- "}\n"
- if spew.UnsafeDisabled {
- expected = "(map[spew_test.pstringer]int) (len=3) {\n" +
- "(spew_test.pstringer) (len=1) \"1\": (int) 1,\n" +
- "(spew_test.pstringer) (len=1) \"2\": (int) 2,\n" +
- "(spew_test.pstringer) (len=1) \"3\": (int) 3\n" +
- "}\n"
- }
- if s != expected {
- t.Errorf("Sorted keys mismatch:\n %v %v", s, expected)
- }
-
- s = cfg.Sdump(map[customError]int{customError(1): 1, customError(3): 3, customError(2): 2})
- expected = "(map[spew_test.customError]int) (len=3) {\n" +
- "(spew_test.customError) error: 1: (int) 1,\n" +
- "(spew_test.customError) error: 2: (int) 2,\n" +
- "(spew_test.customError) error: 3: (int) 3\n" +
- "}\n"
- if s != expected {
- t.Errorf("Sorted keys mismatch:\n %v %v", s, expected)
- }
-
-}
diff --git a/vendor/github.com/davecgh/go-spew/spew/dumpcgo_test.go b/vendor/github.com/davecgh/go-spew/spew/dumpcgo_test.go
deleted file mode 100644
index 108baa55..00000000
--- a/vendor/github.com/davecgh/go-spew/spew/dumpcgo_test.go
+++ /dev/null
@@ -1,101 +0,0 @@
-// Copyright (c) 2013-2016 Dave Collins
-//
-// Permission to use, copy, modify, and distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-// NOTE: Due to the following build constraints, this file will only be compiled
-// when both cgo is supported and "-tags testcgo" is added to the go test
-// command line. This means the cgo tests are only added (and hence run) when
-// specifially requested. This configuration is used because spew itself
-// does not require cgo to run even though it does handle certain cgo types
-// specially. Rather than forcing all clients to require cgo and an external
-// C compiler just to run the tests, this scheme makes them optional.
-// +build cgo,testcgo
-
-package spew_test
-
-import (
- "fmt"
-
- "github.com/davecgh/go-spew/spew/testdata"
-)
-
-func addCgoDumpTests() {
- // C char pointer.
- v := testdata.GetCgoCharPointer()
- nv := testdata.GetCgoNullCharPointer()
- pv := &v
- vcAddr := fmt.Sprintf("%p", v)
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "*testdata._Ctype_char"
- vs := "116"
- addDumpTest(v, "("+vt+")("+vcAddr+")("+vs+")\n")
- addDumpTest(pv, "(*"+vt+")("+vAddr+"->"+vcAddr+")("+vs+")\n")
- addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+"->"+vcAddr+")("+vs+")\n")
- addDumpTest(nv, "("+vt+")()\n")
-
- // C char array.
- v2, v2l, v2c := testdata.GetCgoCharArray()
- v2Len := fmt.Sprintf("%d", v2l)
- v2Cap := fmt.Sprintf("%d", v2c)
- v2t := "[6]testdata._Ctype_char"
- v2s := "(len=" + v2Len + " cap=" + v2Cap + ") " +
- "{\n 00000000 74 65 73 74 32 00 " +
- " |test2.|\n}"
- addDumpTest(v2, "("+v2t+") "+v2s+"\n")
-
- // C unsigned char array.
- v3, v3l, v3c := testdata.GetCgoUnsignedCharArray()
- v3Len := fmt.Sprintf("%d", v3l)
- v3Cap := fmt.Sprintf("%d", v3c)
- v3t := "[6]testdata._Ctype_unsignedchar"
- v3t2 := "[6]testdata._Ctype_uchar"
- v3s := "(len=" + v3Len + " cap=" + v3Cap + ") " +
- "{\n 00000000 74 65 73 74 33 00 " +
- " |test3.|\n}"
- addDumpTest(v3, "("+v3t+") "+v3s+"\n", "("+v3t2+") "+v3s+"\n")
-
- // C signed char array.
- v4, v4l, v4c := testdata.GetCgoSignedCharArray()
- v4Len := fmt.Sprintf("%d", v4l)
- v4Cap := fmt.Sprintf("%d", v4c)
- v4t := "[6]testdata._Ctype_schar"
- v4t2 := "testdata._Ctype_schar"
- v4s := "(len=" + v4Len + " cap=" + v4Cap + ") " +
- "{\n (" + v4t2 + ") 116,\n (" + v4t2 + ") 101,\n (" + v4t2 +
- ") 115,\n (" + v4t2 + ") 116,\n (" + v4t2 + ") 52,\n (" + v4t2 +
- ") 0\n}"
- addDumpTest(v4, "("+v4t+") "+v4s+"\n")
-
- // C uint8_t array.
- v5, v5l, v5c := testdata.GetCgoUint8tArray()
- v5Len := fmt.Sprintf("%d", v5l)
- v5Cap := fmt.Sprintf("%d", v5c)
- v5t := "[6]testdata._Ctype_uint8_t"
- v5t2 := "[6]testdata._Ctype_uchar"
- v5s := "(len=" + v5Len + " cap=" + v5Cap + ") " +
- "{\n 00000000 74 65 73 74 35 00 " +
- " |test5.|\n}"
- addDumpTest(v5, "("+v5t+") "+v5s+"\n", "("+v5t2+") "+v5s+"\n")
-
- // C typedefed unsigned char array.
- v6, v6l, v6c := testdata.GetCgoTypdefedUnsignedCharArray()
- v6Len := fmt.Sprintf("%d", v6l)
- v6Cap := fmt.Sprintf("%d", v6c)
- v6t := "[6]testdata._Ctype_custom_uchar_t"
- v6t2 := "[6]testdata._Ctype_uchar"
- v6s := "(len=" + v6Len + " cap=" + v6Cap + ") " +
- "{\n 00000000 74 65 73 74 36 00 " +
- " |test6.|\n}"
- addDumpTest(v6, "("+v6t+") "+v6s+"\n", "("+v6t2+") "+v6s+"\n")
-}
diff --git a/vendor/github.com/davecgh/go-spew/spew/dumpnocgo_test.go b/vendor/github.com/davecgh/go-spew/spew/dumpnocgo_test.go
deleted file mode 100644
index 52a0971f..00000000
--- a/vendor/github.com/davecgh/go-spew/spew/dumpnocgo_test.go
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright (c) 2013 Dave Collins
-//
-// Permission to use, copy, modify, and distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-// NOTE: Due to the following build constraints, this file will only be compiled
-// when either cgo is not supported or "-tags testcgo" is not added to the go
-// test command line. This file intentionally does not setup any cgo tests in
-// this scenario.
-// +build !cgo !testcgo
-
-package spew_test
-
-func addCgoDumpTests() {
- // Don't add any tests for cgo since this file is only compiled when
- // there should not be any cgo tests.
-}
diff --git a/vendor/github.com/davecgh/go-spew/spew/example_test.go b/vendor/github.com/davecgh/go-spew/spew/example_test.go
deleted file mode 100644
index c6ec8c6d..00000000
--- a/vendor/github.com/davecgh/go-spew/spew/example_test.go
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * Copyright (c) 2013-2016 Dave Collins
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-package spew_test
-
-import (
- "fmt"
-
- "github.com/davecgh/go-spew/spew"
-)
-
-type Flag int
-
-const (
- flagOne Flag = iota
- flagTwo
-)
-
-var flagStrings = map[Flag]string{
- flagOne: "flagOne",
- flagTwo: "flagTwo",
-}
-
-func (f Flag) String() string {
- if s, ok := flagStrings[f]; ok {
- return s
- }
- return fmt.Sprintf("Unknown flag (%d)", int(f))
-}
-
-type Bar struct {
- data uintptr
-}
-
-type Foo struct {
- unexportedField Bar
- ExportedField map[interface{}]interface{}
-}
-
-// This example demonstrates how to use Dump to dump variables to stdout.
-func ExampleDump() {
- // The following package level declarations are assumed for this example:
- /*
- type Flag int
-
- const (
- flagOne Flag = iota
- flagTwo
- )
-
- var flagStrings = map[Flag]string{
- flagOne: "flagOne",
- flagTwo: "flagTwo",
- }
-
- func (f Flag) String() string {
- if s, ok := flagStrings[f]; ok {
- return s
- }
- return fmt.Sprintf("Unknown flag (%d)", int(f))
- }
-
- type Bar struct {
- data uintptr
- }
-
- type Foo struct {
- unexportedField Bar
- ExportedField map[interface{}]interface{}
- }
- */
-
- // Setup some sample data structures for the example.
- bar := Bar{uintptr(0)}
- s1 := Foo{bar, map[interface{}]interface{}{"one": true}}
- f := Flag(5)
- b := []byte{
- 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
- 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
- 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
- 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
- 0x31, 0x32,
- }
-
- // Dump!
- spew.Dump(s1, f, b)
-
- // Output:
- // (spew_test.Foo) {
- // unexportedField: (spew_test.Bar) {
- // data: (uintptr)
- // },
- // ExportedField: (map[interface {}]interface {}) (len=1) {
- // (string) (len=3) "one": (bool) true
- // }
- // }
- // (spew_test.Flag) Unknown flag (5)
- // ([]uint8) (len=34 cap=34) {
- // 00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 |............... |
- // 00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 |!"#$%&'()*+,-./0|
- // 00000020 31 32 |12|
- // }
- //
-}
-
-// This example demonstrates how to use Printf to display a variable with a
-// format string and inline formatting.
-func ExamplePrintf() {
- // Create a double pointer to a uint 8.
- ui8 := uint8(5)
- pui8 := &ui8
- ppui8 := &pui8
-
- // Create a circular data type.
- type circular struct {
- ui8 uint8
- c *circular
- }
- c := circular{ui8: 1}
- c.c = &c
-
- // Print!
- spew.Printf("ppui8: %v\n", ppui8)
- spew.Printf("circular: %v\n", c)
-
- // Output:
- // ppui8: <**>5
- // circular: {1 <*>{1 <*>}}
-}
-
-// This example demonstrates how to use a ConfigState.
-func ExampleConfigState() {
- // Modify the indent level of the ConfigState only. The global
- // configuration is not modified.
- scs := spew.ConfigState{Indent: "\t"}
-
- // Output using the ConfigState instance.
- v := map[string]int{"one": 1}
- scs.Printf("v: %v\n", v)
- scs.Dump(v)
-
- // Output:
- // v: map[one:1]
- // (map[string]int) (len=1) {
- // (string) (len=3) "one": (int) 1
- // }
-}
-
-// This example demonstrates how to use ConfigState.Dump to dump variables to
-// stdout
-func ExampleConfigState_Dump() {
- // See the top-level Dump example for details on the types used in this
- // example.
-
- // Create two ConfigState instances with different indentation.
- scs := spew.ConfigState{Indent: "\t"}
- scs2 := spew.ConfigState{Indent: " "}
-
- // Setup some sample data structures for the example.
- bar := Bar{uintptr(0)}
- s1 := Foo{bar, map[interface{}]interface{}{"one": true}}
-
- // Dump using the ConfigState instances.
- scs.Dump(s1)
- scs2.Dump(s1)
-
- // Output:
- // (spew_test.Foo) {
- // unexportedField: (spew_test.Bar) {
- // data: (uintptr)
- // },
- // ExportedField: (map[interface {}]interface {}) (len=1) {
- // (string) (len=3) "one": (bool) true
- // }
- // }
- // (spew_test.Foo) {
- // unexportedField: (spew_test.Bar) {
- // data: (uintptr)
- // },
- // ExportedField: (map[interface {}]interface {}) (len=1) {
- // (string) (len=3) "one": (bool) true
- // }
- // }
- //
-}
-
-// This example demonstrates how to use ConfigState.Printf to display a variable
-// with a format string and inline formatting.
-func ExampleConfigState_Printf() {
- // See the top-level Dump example for details on the types used in this
- // example.
-
- // Create two ConfigState instances and modify the method handling of the
- // first ConfigState only.
- scs := spew.NewDefaultConfig()
- scs2 := spew.NewDefaultConfig()
- scs.DisableMethods = true
-
- // Alternatively
- // scs := spew.ConfigState{Indent: " ", DisableMethods: true}
- // scs2 := spew.ConfigState{Indent: " "}
-
- // This is of type Flag which implements a Stringer and has raw value 1.
- f := flagTwo
-
- // Dump using the ConfigState instances.
- scs.Printf("f: %v\n", f)
- scs2.Printf("f: %v\n", f)
-
- // Output:
- // f: 1
- // f: flagTwo
-}
diff --git a/vendor/github.com/davecgh/go-spew/spew/format_test.go b/vendor/github.com/davecgh/go-spew/spew/format_test.go
deleted file mode 100644
index 87ee9651..00000000
--- a/vendor/github.com/davecgh/go-spew/spew/format_test.go
+++ /dev/null
@@ -1,1558 +0,0 @@
-/*
- * Copyright (c) 2013-2016 Dave Collins
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-/*
-Test Summary:
-NOTE: For each test, a nil pointer, a single pointer and double pointer to the
-base test element are also tested to ensure proper indirection across all types.
-
-- Max int8, int16, int32, int64, int
-- Max uint8, uint16, uint32, uint64, uint
-- Boolean true and false
-- Standard complex64 and complex128
-- Array containing standard ints
-- Array containing type with custom formatter on pointer receiver only
-- Array containing interfaces
-- Slice containing standard float32 values
-- Slice containing type with custom formatter on pointer receiver only
-- Slice containing interfaces
-- Nil slice
-- Standard string
-- Nil interface
-- Sub-interface
-- Map with string keys and int vals
-- Map with custom formatter type on pointer receiver only keys and vals
-- Map with interface keys and values
-- Map with nil interface value
-- Struct with primitives
-- Struct that contains another struct
-- Struct that contains custom type with Stringer pointer interface via both
- exported and unexported fields
-- Struct that contains embedded struct and field to same struct
-- Uintptr to 0 (null pointer)
-- Uintptr address of real variable
-- Unsafe.Pointer to 0 (null pointer)
-- Unsafe.Pointer to address of real variable
-- Nil channel
-- Standard int channel
-- Function with no params and no returns
-- Function with param and no returns
-- Function with multiple params and multiple returns
-- Struct that is circular through self referencing
-- Structs that are circular through cross referencing
-- Structs that are indirectly circular
-- Type that panics in its Stringer interface
-- Type that has a custom Error interface
-- %x passthrough with uint
-- %#x passthrough with uint
-- %f passthrough with precision
-- %f passthrough with width and precision
-- %d passthrough with width
-- %q passthrough with string
-*/
-
-package spew_test
-
-import (
- "bytes"
- "fmt"
- "testing"
- "unsafe"
-
- "github.com/davecgh/go-spew/spew"
-)
-
-// formatterTest is used to describe a test to be performed against NewFormatter.
-type formatterTest struct {
- format string
- in interface{}
- wants []string
-}
-
-// formatterTests houses all of the tests to be performed against NewFormatter.
-var formatterTests = make([]formatterTest, 0)
-
-// addFormatterTest is a helper method to append the passed input and desired
-// result to formatterTests.
-func addFormatterTest(format string, in interface{}, wants ...string) {
- test := formatterTest{format, in, wants}
- formatterTests = append(formatterTests, test)
-}
-
-func addIntFormatterTests() {
- // Max int8.
- v := int8(127)
- nv := (*int8)(nil)
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "int8"
- vs := "127"
- addFormatterTest("%v", v, vs)
- addFormatterTest("%v", pv, "<*>"+vs)
- addFormatterTest("%v", &pv, "<**>"+vs)
- addFormatterTest("%v", nv, "")
- addFormatterTest("%+v", v, vs)
- addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
- addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
- addFormatterTest("%+v", nv, "")
- addFormatterTest("%#v", v, "("+vt+")"+vs)
- addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
- addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
- addFormatterTest("%#v", nv, "(*"+vt+")"+"")
- addFormatterTest("%#+v", v, "("+vt+")"+vs)
- addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
- addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
- addFormatterTest("%#+v", nv, "(*"+vt+")"+"")
-
- // Max int16.
- v2 := int16(32767)
- nv2 := (*int16)(nil)
- pv2 := &v2
- v2Addr := fmt.Sprintf("%p", pv2)
- pv2Addr := fmt.Sprintf("%p", &pv2)
- v2t := "int16"
- v2s := "32767"
- addFormatterTest("%v", v2, v2s)
- addFormatterTest("%v", pv2, "<*>"+v2s)
- addFormatterTest("%v", &pv2, "<**>"+v2s)
- addFormatterTest("%v", nv2, "")
- addFormatterTest("%+v", v2, v2s)
- addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
- addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
- addFormatterTest("%+v", nv2, "")
- addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
- addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
- addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
- addFormatterTest("%#v", nv2, "(*"+v2t+")"+"")
- addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
- addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
- addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
- addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"")
-
- // Max int32.
- v3 := int32(2147483647)
- nv3 := (*int32)(nil)
- pv3 := &v3
- v3Addr := fmt.Sprintf("%p", pv3)
- pv3Addr := fmt.Sprintf("%p", &pv3)
- v3t := "int32"
- v3s := "2147483647"
- addFormatterTest("%v", v3, v3s)
- addFormatterTest("%v", pv3, "<*>"+v3s)
- addFormatterTest("%v", &pv3, "<**>"+v3s)
- addFormatterTest("%v", nv3, "")
- addFormatterTest("%+v", v3, v3s)
- addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s)
- addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s)
- addFormatterTest("%+v", nv3, "")
- addFormatterTest("%#v", v3, "("+v3t+")"+v3s)
- addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s)
- addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s)
- addFormatterTest("%#v", nv3, "(*"+v3t+")"+"")
- addFormatterTest("%#+v", v3, "("+v3t+")"+v3s)
- addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s)
- addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s)
- addFormatterTest("%#v", nv3, "(*"+v3t+")"+"")
-
- // Max int64.
- v4 := int64(9223372036854775807)
- nv4 := (*int64)(nil)
- pv4 := &v4
- v4Addr := fmt.Sprintf("%p", pv4)
- pv4Addr := fmt.Sprintf("%p", &pv4)
- v4t := "int64"
- v4s := "9223372036854775807"
- addFormatterTest("%v", v4, v4s)
- addFormatterTest("%v", pv4, "<*>"+v4s)
- addFormatterTest("%v", &pv4, "<**>"+v4s)
- addFormatterTest("%v", nv4, "")
- addFormatterTest("%+v", v4, v4s)
- addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s)
- addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s)
- addFormatterTest("%+v", nv4, "")
- addFormatterTest("%#v", v4, "("+v4t+")"+v4s)
- addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s)
- addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s)
- addFormatterTest("%#v", nv4, "(*"+v4t+")"+"")
- addFormatterTest("%#+v", v4, "("+v4t+")"+v4s)
- addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s)
- addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s)
- addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"")
-
- // Max int.
- v5 := int(2147483647)
- nv5 := (*int)(nil)
- pv5 := &v5
- v5Addr := fmt.Sprintf("%p", pv5)
- pv5Addr := fmt.Sprintf("%p", &pv5)
- v5t := "int"
- v5s := "2147483647"
- addFormatterTest("%v", v5, v5s)
- addFormatterTest("%v", pv5, "<*>"+v5s)
- addFormatterTest("%v", &pv5, "<**>"+v5s)
- addFormatterTest("%v", nv5, "")
- addFormatterTest("%+v", v5, v5s)
- addFormatterTest("%+v", pv5, "<*>("+v5Addr+")"+v5s)
- addFormatterTest("%+v", &pv5, "<**>("+pv5Addr+"->"+v5Addr+")"+v5s)
- addFormatterTest("%+v", nv5, "")
- addFormatterTest("%#v", v5, "("+v5t+")"+v5s)
- addFormatterTest("%#v", pv5, "(*"+v5t+")"+v5s)
- addFormatterTest("%#v", &pv5, "(**"+v5t+")"+v5s)
- addFormatterTest("%#v", nv5, "(*"+v5t+")"+"")
- addFormatterTest("%#+v", v5, "("+v5t+")"+v5s)
- addFormatterTest("%#+v", pv5, "(*"+v5t+")("+v5Addr+")"+v5s)
- addFormatterTest("%#+v", &pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")"+v5s)
- addFormatterTest("%#+v", nv5, "(*"+v5t+")"+"")
-}
-
-func addUintFormatterTests() {
- // Max uint8.
- v := uint8(255)
- nv := (*uint8)(nil)
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "uint8"
- vs := "255"
- addFormatterTest("%v", v, vs)
- addFormatterTest("%v", pv, "<*>"+vs)
- addFormatterTest("%v", &pv, "<**>"+vs)
- addFormatterTest("%v", nv, "")
- addFormatterTest("%+v", v, vs)
- addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
- addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
- addFormatterTest("%+v", nv, "")
- addFormatterTest("%#v", v, "("+vt+")"+vs)
- addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
- addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
- addFormatterTest("%#v", nv, "(*"+vt+")"+"")
- addFormatterTest("%#+v", v, "("+vt+")"+vs)
- addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
- addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
- addFormatterTest("%#+v", nv, "(*"+vt+")"+"")
-
- // Max uint16.
- v2 := uint16(65535)
- nv2 := (*uint16)(nil)
- pv2 := &v2
- v2Addr := fmt.Sprintf("%p", pv2)
- pv2Addr := fmt.Sprintf("%p", &pv2)
- v2t := "uint16"
- v2s := "65535"
- addFormatterTest("%v", v2, v2s)
- addFormatterTest("%v", pv2, "<*>"+v2s)
- addFormatterTest("%v", &pv2, "<**>"+v2s)
- addFormatterTest("%v", nv2, "")
- addFormatterTest("%+v", v2, v2s)
- addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
- addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
- addFormatterTest("%+v", nv2, "")
- addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
- addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
- addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
- addFormatterTest("%#v", nv2, "(*"+v2t+")"+"")
- addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
- addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
- addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
- addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"")
-
- // Max uint32.
- v3 := uint32(4294967295)
- nv3 := (*uint32)(nil)
- pv3 := &v3
- v3Addr := fmt.Sprintf("%p", pv3)
- pv3Addr := fmt.Sprintf("%p", &pv3)
- v3t := "uint32"
- v3s := "4294967295"
- addFormatterTest("%v", v3, v3s)
- addFormatterTest("%v", pv3, "<*>"+v3s)
- addFormatterTest("%v", &pv3, "<**>"+v3s)
- addFormatterTest("%v", nv3, "")
- addFormatterTest("%+v", v3, v3s)
- addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s)
- addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s)
- addFormatterTest("%+v", nv3, "")
- addFormatterTest("%#v", v3, "("+v3t+")"+v3s)
- addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s)
- addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s)
- addFormatterTest("%#v", nv3, "(*"+v3t+")"+"")
- addFormatterTest("%#+v", v3, "("+v3t+")"+v3s)
- addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s)
- addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s)
- addFormatterTest("%#v", nv3, "(*"+v3t+")"+"")
-
- // Max uint64.
- v4 := uint64(18446744073709551615)
- nv4 := (*uint64)(nil)
- pv4 := &v4
- v4Addr := fmt.Sprintf("%p", pv4)
- pv4Addr := fmt.Sprintf("%p", &pv4)
- v4t := "uint64"
- v4s := "18446744073709551615"
- addFormatterTest("%v", v4, v4s)
- addFormatterTest("%v", pv4, "<*>"+v4s)
- addFormatterTest("%v", &pv4, "<**>"+v4s)
- addFormatterTest("%v", nv4, "")
- addFormatterTest("%+v", v4, v4s)
- addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s)
- addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s)
- addFormatterTest("%+v", nv4, "")
- addFormatterTest("%#v", v4, "("+v4t+")"+v4s)
- addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s)
- addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s)
- addFormatterTest("%#v", nv4, "(*"+v4t+")"+"")
- addFormatterTest("%#+v", v4, "("+v4t+")"+v4s)
- addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s)
- addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s)
- addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"")
-
- // Max uint.
- v5 := uint(4294967295)
- nv5 := (*uint)(nil)
- pv5 := &v5
- v5Addr := fmt.Sprintf("%p", pv5)
- pv5Addr := fmt.Sprintf("%p", &pv5)
- v5t := "uint"
- v5s := "4294967295"
- addFormatterTest("%v", v5, v5s)
- addFormatterTest("%v", pv5, "<*>"+v5s)
- addFormatterTest("%v", &pv5, "<**>"+v5s)
- addFormatterTest("%v", nv5, "")
- addFormatterTest("%+v", v5, v5s)
- addFormatterTest("%+v", pv5, "<*>("+v5Addr+")"+v5s)
- addFormatterTest("%+v", &pv5, "<**>("+pv5Addr+"->"+v5Addr+")"+v5s)
- addFormatterTest("%+v", nv5, "")
- addFormatterTest("%#v", v5, "("+v5t+")"+v5s)
- addFormatterTest("%#v", pv5, "(*"+v5t+")"+v5s)
- addFormatterTest("%#v", &pv5, "(**"+v5t+")"+v5s)
- addFormatterTest("%#v", nv5, "(*"+v5t+")"+"")
- addFormatterTest("%#+v", v5, "("+v5t+")"+v5s)
- addFormatterTest("%#+v", pv5, "(*"+v5t+")("+v5Addr+")"+v5s)
- addFormatterTest("%#+v", &pv5, "(**"+v5t+")("+pv5Addr+"->"+v5Addr+")"+v5s)
- addFormatterTest("%#v", nv5, "(*"+v5t+")"+"")
-}
-
-func addBoolFormatterTests() {
- // Boolean true.
- v := bool(true)
- nv := (*bool)(nil)
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "bool"
- vs := "true"
- addFormatterTest("%v", v, vs)
- addFormatterTest("%v", pv, "<*>"+vs)
- addFormatterTest("%v", &pv, "<**>"+vs)
- addFormatterTest("%v", nv, "")
- addFormatterTest("%+v", v, vs)
- addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
- addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
- addFormatterTest("%+v", nv, "")
- addFormatterTest("%#v", v, "("+vt+")"+vs)
- addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
- addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
- addFormatterTest("%#v", nv, "(*"+vt+")"+"")
- addFormatterTest("%#+v", v, "("+vt+")"+vs)
- addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
- addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
- addFormatterTest("%#+v", nv, "(*"+vt+")"+"")
-
- // Boolean false.
- v2 := bool(false)
- pv2 := &v2
- v2Addr := fmt.Sprintf("%p", pv2)
- pv2Addr := fmt.Sprintf("%p", &pv2)
- v2t := "bool"
- v2s := "false"
- addFormatterTest("%v", v2, v2s)
- addFormatterTest("%v", pv2, "<*>"+v2s)
- addFormatterTest("%v", &pv2, "<**>"+v2s)
- addFormatterTest("%+v", v2, v2s)
- addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
- addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
- addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
- addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
- addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
- addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
- addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
- addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
-}
-
-func addFloatFormatterTests() {
- // Standard float32.
- v := float32(3.1415)
- nv := (*float32)(nil)
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "float32"
- vs := "3.1415"
- addFormatterTest("%v", v, vs)
- addFormatterTest("%v", pv, "<*>"+vs)
- addFormatterTest("%v", &pv, "<**>"+vs)
- addFormatterTest("%v", nv, "")
- addFormatterTest("%+v", v, vs)
- addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
- addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
- addFormatterTest("%+v", nv, "")
- addFormatterTest("%#v", v, "("+vt+")"+vs)
- addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
- addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
- addFormatterTest("%#v", nv, "(*"+vt+")"+"")
- addFormatterTest("%#+v", v, "("+vt+")"+vs)
- addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
- addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
- addFormatterTest("%#+v", nv, "(*"+vt+")"+"")
-
- // Standard float64.
- v2 := float64(3.1415926)
- nv2 := (*float64)(nil)
- pv2 := &v2
- v2Addr := fmt.Sprintf("%p", pv2)
- pv2Addr := fmt.Sprintf("%p", &pv2)
- v2t := "float64"
- v2s := "3.1415926"
- addFormatterTest("%v", v2, v2s)
- addFormatterTest("%v", pv2, "<*>"+v2s)
- addFormatterTest("%v", &pv2, "<**>"+v2s)
- addFormatterTest("%+v", nv2, "")
- addFormatterTest("%+v", v2, v2s)
- addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
- addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
- addFormatterTest("%+v", nv2, "")
- addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
- addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
- addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
- addFormatterTest("%#v", nv2, "(*"+v2t+")"+"")
- addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
- addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
- addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
- addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"")
-}
-
-func addComplexFormatterTests() {
- // Standard complex64.
- v := complex(float32(6), -2)
- nv := (*complex64)(nil)
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "complex64"
- vs := "(6-2i)"
- addFormatterTest("%v", v, vs)
- addFormatterTest("%v", pv, "<*>"+vs)
- addFormatterTest("%v", &pv, "<**>"+vs)
- addFormatterTest("%+v", nv, "")
- addFormatterTest("%+v", v, vs)
- addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
- addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
- addFormatterTest("%+v", nv, "")
- addFormatterTest("%#v", v, "("+vt+")"+vs)
- addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
- addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
- addFormatterTest("%#v", nv, "(*"+vt+")"+"")
- addFormatterTest("%#+v", v, "("+vt+")"+vs)
- addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
- addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
- addFormatterTest("%#+v", nv, "(*"+vt+")"+"")
-
- // Standard complex128.
- v2 := complex(float64(-6), 2)
- nv2 := (*complex128)(nil)
- pv2 := &v2
- v2Addr := fmt.Sprintf("%p", pv2)
- pv2Addr := fmt.Sprintf("%p", &pv2)
- v2t := "complex128"
- v2s := "(-6+2i)"
- addFormatterTest("%v", v2, v2s)
- addFormatterTest("%v", pv2, "<*>"+v2s)
- addFormatterTest("%v", &pv2, "<**>"+v2s)
- addFormatterTest("%+v", nv2, "")
- addFormatterTest("%+v", v2, v2s)
- addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
- addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
- addFormatterTest("%+v", nv2, "")
- addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
- addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
- addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
- addFormatterTest("%#v", nv2, "(*"+v2t+")"+"")
- addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
- addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
- addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
- addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"")
-}
-
-func addArrayFormatterTests() {
- // Array containing standard ints.
- v := [3]int{1, 2, 3}
- nv := (*[3]int)(nil)
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "[3]int"
- vs := "[1 2 3]"
- addFormatterTest("%v", v, vs)
- addFormatterTest("%v", pv, "<*>"+vs)
- addFormatterTest("%v", &pv, "<**>"+vs)
- addFormatterTest("%+v", nv, "")
- addFormatterTest("%+v", v, vs)
- addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
- addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
- addFormatterTest("%+v", nv, "")
- addFormatterTest("%#v", v, "("+vt+")"+vs)
- addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
- addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
- addFormatterTest("%#v", nv, "(*"+vt+")"+"")
- addFormatterTest("%#+v", v, "("+vt+")"+vs)
- addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
- addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
- addFormatterTest("%#+v", nv, "(*"+vt+")"+"")
-
- // Array containing type with custom formatter on pointer receiver only.
- v2 := [3]pstringer{"1", "2", "3"}
- nv2 := (*[3]pstringer)(nil)
- pv2 := &v2
- v2Addr := fmt.Sprintf("%p", pv2)
- pv2Addr := fmt.Sprintf("%p", &pv2)
- v2t := "[3]spew_test.pstringer"
- v2sp := "[stringer 1 stringer 2 stringer 3]"
- v2s := v2sp
- if spew.UnsafeDisabled {
- v2s = "[1 2 3]"
- }
- addFormatterTest("%v", v2, v2s)
- addFormatterTest("%v", pv2, "<*>"+v2sp)
- addFormatterTest("%v", &pv2, "<**>"+v2sp)
- addFormatterTest("%+v", nv2, "")
- addFormatterTest("%+v", v2, v2s)
- addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2sp)
- addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2sp)
- addFormatterTest("%+v", nv2, "")
- addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
- addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2sp)
- addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2sp)
- addFormatterTest("%#v", nv2, "(*"+v2t+")"+"")
- addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
- addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2sp)
- addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2sp)
- addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"")
-
- // Array containing interfaces.
- v3 := [3]interface{}{"one", int(2), uint(3)}
- nv3 := (*[3]interface{})(nil)
- pv3 := &v3
- v3Addr := fmt.Sprintf("%p", pv3)
- pv3Addr := fmt.Sprintf("%p", &pv3)
- v3t := "[3]interface {}"
- v3t2 := "string"
- v3t3 := "int"
- v3t4 := "uint"
- v3s := "[one 2 3]"
- v3s2 := "[(" + v3t2 + ")one (" + v3t3 + ")2 (" + v3t4 + ")3]"
- addFormatterTest("%v", v3, v3s)
- addFormatterTest("%v", pv3, "<*>"+v3s)
- addFormatterTest("%v", &pv3, "<**>"+v3s)
- addFormatterTest("%+v", nv3, "")
- addFormatterTest("%+v", v3, v3s)
- addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s)
- addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s)
- addFormatterTest("%+v", nv3, "")
- addFormatterTest("%#v", v3, "("+v3t+")"+v3s2)
- addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s2)
- addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s2)
- addFormatterTest("%#v", nv3, "(*"+v3t+")"+"")
- addFormatterTest("%#+v", v3, "("+v3t+")"+v3s2)
- addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s2)
- addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s2)
- addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"")
-}
-
-func addSliceFormatterTests() {
- // Slice containing standard float32 values.
- v := []float32{3.14, 6.28, 12.56}
- nv := (*[]float32)(nil)
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "[]float32"
- vs := "[3.14 6.28 12.56]"
- addFormatterTest("%v", v, vs)
- addFormatterTest("%v", pv, "<*>"+vs)
- addFormatterTest("%v", &pv, "<**>"+vs)
- addFormatterTest("%+v", nv, "")
- addFormatterTest("%+v", v, vs)
- addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
- addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
- addFormatterTest("%+v", nv, "")
- addFormatterTest("%#v", v, "("+vt+")"+vs)
- addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
- addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
- addFormatterTest("%#v", nv, "(*"+vt+")"+"")
- addFormatterTest("%#+v", v, "("+vt+")"+vs)
- addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
- addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
- addFormatterTest("%#+v", nv, "(*"+vt+")"+"")
-
- // Slice containing type with custom formatter on pointer receiver only.
- v2 := []pstringer{"1", "2", "3"}
- nv2 := (*[]pstringer)(nil)
- pv2 := &v2
- v2Addr := fmt.Sprintf("%p", pv2)
- pv2Addr := fmt.Sprintf("%p", &pv2)
- v2t := "[]spew_test.pstringer"
- v2s := "[stringer 1 stringer 2 stringer 3]"
- addFormatterTest("%v", v2, v2s)
- addFormatterTest("%v", pv2, "<*>"+v2s)
- addFormatterTest("%v", &pv2, "<**>"+v2s)
- addFormatterTest("%+v", nv2, "")
- addFormatterTest("%+v", v2, v2s)
- addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
- addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
- addFormatterTest("%+v", nv2, "")
- addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
- addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
- addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
- addFormatterTest("%#v", nv2, "(*"+v2t+")"+"")
- addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
- addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
- addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
- addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"")
-
- // Slice containing interfaces.
- v3 := []interface{}{"one", int(2), uint(3), nil}
- nv3 := (*[]interface{})(nil)
- pv3 := &v3
- v3Addr := fmt.Sprintf("%p", pv3)
- pv3Addr := fmt.Sprintf("%p", &pv3)
- v3t := "[]interface {}"
- v3t2 := "string"
- v3t3 := "int"
- v3t4 := "uint"
- v3t5 := "interface {}"
- v3s := "[one 2 3 ]"
- v3s2 := "[(" + v3t2 + ")one (" + v3t3 + ")2 (" + v3t4 + ")3 (" + v3t5 +
- ")]"
- addFormatterTest("%v", v3, v3s)
- addFormatterTest("%v", pv3, "<*>"+v3s)
- addFormatterTest("%v", &pv3, "<**>"+v3s)
- addFormatterTest("%+v", nv3, "")
- addFormatterTest("%+v", v3, v3s)
- addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s)
- addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s)
- addFormatterTest("%+v", nv3, "")
- addFormatterTest("%#v", v3, "("+v3t+")"+v3s2)
- addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s2)
- addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s2)
- addFormatterTest("%#v", nv3, "(*"+v3t+")"+"")
- addFormatterTest("%#+v", v3, "("+v3t+")"+v3s2)
- addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s2)
- addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s2)
- addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"")
-
- // Nil slice.
- var v4 []int
- nv4 := (*[]int)(nil)
- pv4 := &v4
- v4Addr := fmt.Sprintf("%p", pv4)
- pv4Addr := fmt.Sprintf("%p", &pv4)
- v4t := "[]int"
- v4s := ""
- addFormatterTest("%v", v4, v4s)
- addFormatterTest("%v", pv4, "<*>"+v4s)
- addFormatterTest("%v", &pv4, "<**>"+v4s)
- addFormatterTest("%+v", nv4, "")
- addFormatterTest("%+v", v4, v4s)
- addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s)
- addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s)
- addFormatterTest("%+v", nv4, "")
- addFormatterTest("%#v", v4, "("+v4t+")"+v4s)
- addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s)
- addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s)
- addFormatterTest("%#v", nv4, "(*"+v4t+")"+"")
- addFormatterTest("%#+v", v4, "("+v4t+")"+v4s)
- addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s)
- addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s)
- addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"")
-}
-
-func addStringFormatterTests() {
- // Standard string.
- v := "test"
- nv := (*string)(nil)
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "string"
- vs := "test"
- addFormatterTest("%v", v, vs)
- addFormatterTest("%v", pv, "<*>"+vs)
- addFormatterTest("%v", &pv, "<**>"+vs)
- addFormatterTest("%+v", nv, "")
- addFormatterTest("%+v", v, vs)
- addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
- addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
- addFormatterTest("%+v", nv, "")
- addFormatterTest("%#v", v, "("+vt+")"+vs)
- addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
- addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
- addFormatterTest("%#v", nv, "(*"+vt+")"+"")
- addFormatterTest("%#+v", v, "("+vt+")"+vs)
- addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
- addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
- addFormatterTest("%#+v", nv, "(*"+vt+")"+"")
-}
-
-func addInterfaceFormatterTests() {
- // Nil interface.
- var v interface{}
- nv := (*interface{})(nil)
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "interface {}"
- vs := ""
- addFormatterTest("%v", v, vs)
- addFormatterTest("%v", pv, "<*>"+vs)
- addFormatterTest("%v", &pv, "<**>"+vs)
- addFormatterTest("%+v", nv, "")
- addFormatterTest("%+v", v, vs)
- addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
- addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
- addFormatterTest("%+v", nv, "")
- addFormatterTest("%#v", v, "("+vt+")"+vs)
- addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
- addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
- addFormatterTest("%#v", nv, "(*"+vt+")"+"")
- addFormatterTest("%#+v", v, "("+vt+")"+vs)
- addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
- addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
- addFormatterTest("%#+v", nv, "(*"+vt+")"+"")
-
- // Sub-interface.
- v2 := interface{}(uint16(65535))
- pv2 := &v2
- v2Addr := fmt.Sprintf("%p", pv2)
- pv2Addr := fmt.Sprintf("%p", &pv2)
- v2t := "uint16"
- v2s := "65535"
- addFormatterTest("%v", v2, v2s)
- addFormatterTest("%v", pv2, "<*>"+v2s)
- addFormatterTest("%v", &pv2, "<**>"+v2s)
- addFormatterTest("%+v", v2, v2s)
- addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
- addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
- addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
- addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
- addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
- addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
- addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
- addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
-}
-
-func addMapFormatterTests() {
- // Map with string keys and int vals.
- v := map[string]int{"one": 1, "two": 2}
- nilMap := map[string]int(nil)
- nv := (*map[string]int)(nil)
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "map[string]int"
- vs := "map[one:1 two:2]"
- vs2 := "map[two:2 one:1]"
- addFormatterTest("%v", v, vs, vs2)
- addFormatterTest("%v", pv, "<*>"+vs, "<*>"+vs2)
- addFormatterTest("%v", &pv, "<**>"+vs, "<**>"+vs2)
- addFormatterTest("%+v", nilMap, "")
- addFormatterTest("%+v", nv, "")
- addFormatterTest("%+v", v, vs, vs2)
- addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs, "<*>("+vAddr+")"+vs2)
- addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs,
- "<**>("+pvAddr+"->"+vAddr+")"+vs2)
- addFormatterTest("%+v", nilMap, "")
- addFormatterTest("%+v", nv, "")
- addFormatterTest("%#v", v, "("+vt+")"+vs, "("+vt+")"+vs2)
- addFormatterTest("%#v", pv, "(*"+vt+")"+vs, "(*"+vt+")"+vs2)
- addFormatterTest("%#v", &pv, "(**"+vt+")"+vs, "(**"+vt+")"+vs2)
- addFormatterTest("%#v", nilMap, "("+vt+")"+"")
- addFormatterTest("%#v", nv, "(*"+vt+")"+"")
- addFormatterTest("%#+v", v, "("+vt+")"+vs, "("+vt+")"+vs2)
- addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs,
- "(*"+vt+")("+vAddr+")"+vs2)
- addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs,
- "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs2)
- addFormatterTest("%#+v", nilMap, "("+vt+")"+"")
- addFormatterTest("%#+v", nv, "(*"+vt+")"+"")
-
- // Map with custom formatter type on pointer receiver only keys and vals.
- v2 := map[pstringer]pstringer{"one": "1"}
- nv2 := (*map[pstringer]pstringer)(nil)
- pv2 := &v2
- v2Addr := fmt.Sprintf("%p", pv2)
- pv2Addr := fmt.Sprintf("%p", &pv2)
- v2t := "map[spew_test.pstringer]spew_test.pstringer"
- v2s := "map[stringer one:stringer 1]"
- if spew.UnsafeDisabled {
- v2s = "map[one:1]"
- }
- addFormatterTest("%v", v2, v2s)
- addFormatterTest("%v", pv2, "<*>"+v2s)
- addFormatterTest("%v", &pv2, "<**>"+v2s)
- addFormatterTest("%+v", nv2, "")
- addFormatterTest("%+v", v2, v2s)
- addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
- addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
- addFormatterTest("%+v", nv2, "")
- addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
- addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
- addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
- addFormatterTest("%#v", nv2, "(*"+v2t+")"+"")
- addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
- addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
- addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
- addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"")
-
- // Map with interface keys and values.
- v3 := map[interface{}]interface{}{"one": 1}
- nv3 := (*map[interface{}]interface{})(nil)
- pv3 := &v3
- v3Addr := fmt.Sprintf("%p", pv3)
- pv3Addr := fmt.Sprintf("%p", &pv3)
- v3t := "map[interface {}]interface {}"
- v3t1 := "string"
- v3t2 := "int"
- v3s := "map[one:1]"
- v3s2 := "map[(" + v3t1 + ")one:(" + v3t2 + ")1]"
- addFormatterTest("%v", v3, v3s)
- addFormatterTest("%v", pv3, "<*>"+v3s)
- addFormatterTest("%v", &pv3, "<**>"+v3s)
- addFormatterTest("%+v", nv3, "")
- addFormatterTest("%+v", v3, v3s)
- addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s)
- addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s)
- addFormatterTest("%+v", nv3, "")
- addFormatterTest("%#v", v3, "("+v3t+")"+v3s2)
- addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s2)
- addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s2)
- addFormatterTest("%#v", nv3, "(*"+v3t+")"+"")
- addFormatterTest("%#+v", v3, "("+v3t+")"+v3s2)
- addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s2)
- addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s2)
- addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"")
-
- // Map with nil interface value
- v4 := map[string]interface{}{"nil": nil}
- nv4 := (*map[string]interface{})(nil)
- pv4 := &v4
- v4Addr := fmt.Sprintf("%p", pv4)
- pv4Addr := fmt.Sprintf("%p", &pv4)
- v4t := "map[string]interface {}"
- v4t1 := "interface {}"
- v4s := "map[nil:]"
- v4s2 := "map[nil:(" + v4t1 + ")]"
- addFormatterTest("%v", v4, v4s)
- addFormatterTest("%v", pv4, "<*>"+v4s)
- addFormatterTest("%v", &pv4, "<**>"+v4s)
- addFormatterTest("%+v", nv4, "")
- addFormatterTest("%+v", v4, v4s)
- addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s)
- addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s)
- addFormatterTest("%+v", nv4, "")
- addFormatterTest("%#v", v4, "("+v4t+")"+v4s2)
- addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s2)
- addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s2)
- addFormatterTest("%#v", nv4, "(*"+v4t+")"+"")
- addFormatterTest("%#+v", v4, "("+v4t+")"+v4s2)
- addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s2)
- addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s2)
- addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"")
-}
-
-func addStructFormatterTests() {
- // Struct with primitives.
- type s1 struct {
- a int8
- b uint8
- }
- v := s1{127, 255}
- nv := (*s1)(nil)
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "spew_test.s1"
- vt2 := "int8"
- vt3 := "uint8"
- vs := "{127 255}"
- vs2 := "{a:127 b:255}"
- vs3 := "{a:(" + vt2 + ")127 b:(" + vt3 + ")255}"
- addFormatterTest("%v", v, vs)
- addFormatterTest("%v", pv, "<*>"+vs)
- addFormatterTest("%v", &pv, "<**>"+vs)
- addFormatterTest("%+v", nv, "")
- addFormatterTest("%+v", v, vs2)
- addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs2)
- addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs2)
- addFormatterTest("%+v", nv, "")
- addFormatterTest("%#v", v, "("+vt+")"+vs3)
- addFormatterTest("%#v", pv, "(*"+vt+")"+vs3)
- addFormatterTest("%#v", &pv, "(**"+vt+")"+vs3)
- addFormatterTest("%#v", nv, "(*"+vt+")"+"")
- addFormatterTest("%#+v", v, "("+vt+")"+vs3)
- addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs3)
- addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs3)
- addFormatterTest("%#+v", nv, "(*"+vt+")"+"")
-
- // Struct that contains another struct.
- type s2 struct {
- s1 s1
- b bool
- }
- v2 := s2{s1{127, 255}, true}
- nv2 := (*s2)(nil)
- pv2 := &v2
- v2Addr := fmt.Sprintf("%p", pv2)
- pv2Addr := fmt.Sprintf("%p", &pv2)
- v2t := "spew_test.s2"
- v2t2 := "spew_test.s1"
- v2t3 := "int8"
- v2t4 := "uint8"
- v2t5 := "bool"
- v2s := "{{127 255} true}"
- v2s2 := "{s1:{a:127 b:255} b:true}"
- v2s3 := "{s1:(" + v2t2 + "){a:(" + v2t3 + ")127 b:(" + v2t4 + ")255} b:(" +
- v2t5 + ")true}"
- addFormatterTest("%v", v2, v2s)
- addFormatterTest("%v", pv2, "<*>"+v2s)
- addFormatterTest("%v", &pv2, "<**>"+v2s)
- addFormatterTest("%+v", nv2, "")
- addFormatterTest("%+v", v2, v2s2)
- addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s2)
- addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s2)
- addFormatterTest("%+v", nv2, "")
- addFormatterTest("%#v", v2, "("+v2t+")"+v2s3)
- addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s3)
- addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s3)
- addFormatterTest("%#v", nv2, "(*"+v2t+")"+"")
- addFormatterTest("%#+v", v2, "("+v2t+")"+v2s3)
- addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s3)
- addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s3)
- addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"")
-
- // Struct that contains custom type with Stringer pointer interface via both
- // exported and unexported fields.
- type s3 struct {
- s pstringer
- S pstringer
- }
- v3 := s3{"test", "test2"}
- nv3 := (*s3)(nil)
- pv3 := &v3
- v3Addr := fmt.Sprintf("%p", pv3)
- pv3Addr := fmt.Sprintf("%p", &pv3)
- v3t := "spew_test.s3"
- v3t2 := "spew_test.pstringer"
- v3s := "{stringer test stringer test2}"
- v3sp := v3s
- v3s2 := "{s:stringer test S:stringer test2}"
- v3s2p := v3s2
- v3s3 := "{s:(" + v3t2 + ")stringer test S:(" + v3t2 + ")stringer test2}"
- v3s3p := v3s3
- if spew.UnsafeDisabled {
- v3s = "{test test2}"
- v3sp = "{test stringer test2}"
- v3s2 = "{s:test S:test2}"
- v3s2p = "{s:test S:stringer test2}"
- v3s3 = "{s:(" + v3t2 + ")test S:(" + v3t2 + ")test2}"
- v3s3p = "{s:(" + v3t2 + ")test S:(" + v3t2 + ")stringer test2}"
- }
- addFormatterTest("%v", v3, v3s)
- addFormatterTest("%v", pv3, "<*>"+v3sp)
- addFormatterTest("%v", &pv3, "<**>"+v3sp)
- addFormatterTest("%+v", nv3, "")
- addFormatterTest("%+v", v3, v3s2)
- addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s2p)
- addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s2p)
- addFormatterTest("%+v", nv3, "")
- addFormatterTest("%#v", v3, "("+v3t+")"+v3s3)
- addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s3p)
- addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s3p)
- addFormatterTest("%#v", nv3, "(*"+v3t+")"+"")
- addFormatterTest("%#+v", v3, "("+v3t+")"+v3s3)
- addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s3p)
- addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s3p)
- addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"")
-
- // Struct that contains embedded struct and field to same struct.
- e := embed{"embedstr"}
- v4 := embedwrap{embed: &e, e: &e}
- nv4 := (*embedwrap)(nil)
- pv4 := &v4
- eAddr := fmt.Sprintf("%p", &e)
- v4Addr := fmt.Sprintf("%p", pv4)
- pv4Addr := fmt.Sprintf("%p", &pv4)
- v4t := "spew_test.embedwrap"
- v4t2 := "spew_test.embed"
- v4t3 := "string"
- v4s := "{<*>{embedstr} <*>{embedstr}}"
- v4s2 := "{embed:<*>(" + eAddr + "){a:embedstr} e:<*>(" + eAddr +
- "){a:embedstr}}"
- v4s3 := "{embed:(*" + v4t2 + "){a:(" + v4t3 + ")embedstr} e:(*" + v4t2 +
- "){a:(" + v4t3 + ")embedstr}}"
- v4s4 := "{embed:(*" + v4t2 + ")(" + eAddr + "){a:(" + v4t3 +
- ")embedstr} e:(*" + v4t2 + ")(" + eAddr + "){a:(" + v4t3 + ")embedstr}}"
- addFormatterTest("%v", v4, v4s)
- addFormatterTest("%v", pv4, "<*>"+v4s)
- addFormatterTest("%v", &pv4, "<**>"+v4s)
- addFormatterTest("%+v", nv4, "")
- addFormatterTest("%+v", v4, v4s2)
- addFormatterTest("%+v", pv4, "<*>("+v4Addr+")"+v4s2)
- addFormatterTest("%+v", &pv4, "<**>("+pv4Addr+"->"+v4Addr+")"+v4s2)
- addFormatterTest("%+v", nv4, "")
- addFormatterTest("%#v", v4, "("+v4t+")"+v4s3)
- addFormatterTest("%#v", pv4, "(*"+v4t+")"+v4s3)
- addFormatterTest("%#v", &pv4, "(**"+v4t+")"+v4s3)
- addFormatterTest("%#v", nv4, "(*"+v4t+")"+"")
- addFormatterTest("%#+v", v4, "("+v4t+")"+v4s4)
- addFormatterTest("%#+v", pv4, "(*"+v4t+")("+v4Addr+")"+v4s4)
- addFormatterTest("%#+v", &pv4, "(**"+v4t+")("+pv4Addr+"->"+v4Addr+")"+v4s4)
- addFormatterTest("%#+v", nv4, "(*"+v4t+")"+"")
-}
-
-func addUintptrFormatterTests() {
- // Null pointer.
- v := uintptr(0)
- nv := (*uintptr)(nil)
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "uintptr"
- vs := ""
- addFormatterTest("%v", v, vs)
- addFormatterTest("%v", pv, "<*>"+vs)
- addFormatterTest("%v", &pv, "<**>"+vs)
- addFormatterTest("%+v", nv, "")
- addFormatterTest("%+v", v, vs)
- addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
- addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
- addFormatterTest("%+v", nv, "")
- addFormatterTest("%#v", v, "("+vt+")"+vs)
- addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
- addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
- addFormatterTest("%#v", nv, "(*"+vt+")"+"")
- addFormatterTest("%#+v", v, "("+vt+")"+vs)
- addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
- addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
- addFormatterTest("%#+v", nv, "(*"+vt+")"+"")
-
- // Address of real variable.
- i := 1
- v2 := uintptr(unsafe.Pointer(&i))
- pv2 := &v2
- v2Addr := fmt.Sprintf("%p", pv2)
- pv2Addr := fmt.Sprintf("%p", &pv2)
- v2t := "uintptr"
- v2s := fmt.Sprintf("%p", &i)
- addFormatterTest("%v", v2, v2s)
- addFormatterTest("%v", pv2, "<*>"+v2s)
- addFormatterTest("%v", &pv2, "<**>"+v2s)
- addFormatterTest("%+v", v2, v2s)
- addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
- addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
- addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
- addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
- addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
- addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
- addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
- addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
-}
-
-func addUnsafePointerFormatterTests() {
- // Null pointer.
- v := unsafe.Pointer(nil)
- nv := (*unsafe.Pointer)(nil)
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "unsafe.Pointer"
- vs := ""
- addFormatterTest("%v", v, vs)
- addFormatterTest("%v", pv, "<*>"+vs)
- addFormatterTest("%v", &pv, "<**>"+vs)
- addFormatterTest("%+v", nv, "")
- addFormatterTest("%+v", v, vs)
- addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
- addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
- addFormatterTest("%+v", nv, "")
- addFormatterTest("%#v", v, "("+vt+")"+vs)
- addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
- addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
- addFormatterTest("%#v", nv, "(*"+vt+")"+"")
- addFormatterTest("%#+v", v, "("+vt+")"+vs)
- addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
- addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
- addFormatterTest("%#+v", nv, "(*"+vt+")"+"")
-
- // Address of real variable.
- i := 1
- v2 := unsafe.Pointer(&i)
- pv2 := &v2
- v2Addr := fmt.Sprintf("%p", pv2)
- pv2Addr := fmt.Sprintf("%p", &pv2)
- v2t := "unsafe.Pointer"
- v2s := fmt.Sprintf("%p", &i)
- addFormatterTest("%v", v2, v2s)
- addFormatterTest("%v", pv2, "<*>"+v2s)
- addFormatterTest("%v", &pv2, "<**>"+v2s)
- addFormatterTest("%+v", v2, v2s)
- addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
- addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
- addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
- addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
- addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
- addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
- addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
- addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
-}
-
-func addChanFormatterTests() {
- // Nil channel.
- var v chan int
- pv := &v
- nv := (*chan int)(nil)
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "chan int"
- vs := ""
- addFormatterTest("%v", v, vs)
- addFormatterTest("%v", pv, "<*>"+vs)
- addFormatterTest("%v", &pv, "<**>"+vs)
- addFormatterTest("%+v", nv, "")
- addFormatterTest("%+v", v, vs)
- addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
- addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
- addFormatterTest("%+v", nv, "")
- addFormatterTest("%#v", v, "("+vt+")"+vs)
- addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
- addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
- addFormatterTest("%#v", nv, "(*"+vt+")"+"")
- addFormatterTest("%#+v", v, "("+vt+")"+vs)
- addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
- addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
- addFormatterTest("%#+v", nv, "(*"+vt+")"+"")
-
- // Real channel.
- v2 := make(chan int)
- pv2 := &v2
- v2Addr := fmt.Sprintf("%p", pv2)
- pv2Addr := fmt.Sprintf("%p", &pv2)
- v2t := "chan int"
- v2s := fmt.Sprintf("%p", v2)
- addFormatterTest("%v", v2, v2s)
- addFormatterTest("%v", pv2, "<*>"+v2s)
- addFormatterTest("%v", &pv2, "<**>"+v2s)
- addFormatterTest("%+v", v2, v2s)
- addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
- addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
- addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
- addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
- addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
- addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
- addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
- addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
-}
-
-func addFuncFormatterTests() {
- // Function with no params and no returns.
- v := addIntFormatterTests
- nv := (*func())(nil)
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "func()"
- vs := fmt.Sprintf("%p", v)
- addFormatterTest("%v", v, vs)
- addFormatterTest("%v", pv, "<*>"+vs)
- addFormatterTest("%v", &pv, "<**>"+vs)
- addFormatterTest("%+v", nv, "")
- addFormatterTest("%+v", v, vs)
- addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs)
- addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs)
- addFormatterTest("%+v", nv, "")
- addFormatterTest("%#v", v, "("+vt+")"+vs)
- addFormatterTest("%#v", pv, "(*"+vt+")"+vs)
- addFormatterTest("%#v", &pv, "(**"+vt+")"+vs)
- addFormatterTest("%#v", nv, "(*"+vt+")"+"")
- addFormatterTest("%#+v", v, "("+vt+")"+vs)
- addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs)
- addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs)
- addFormatterTest("%#+v", nv, "(*"+vt+")"+"")
-
- // Function with param and no returns.
- v2 := TestFormatter
- nv2 := (*func(*testing.T))(nil)
- pv2 := &v2
- v2Addr := fmt.Sprintf("%p", pv2)
- pv2Addr := fmt.Sprintf("%p", &pv2)
- v2t := "func(*testing.T)"
- v2s := fmt.Sprintf("%p", v2)
- addFormatterTest("%v", v2, v2s)
- addFormatterTest("%v", pv2, "<*>"+v2s)
- addFormatterTest("%v", &pv2, "<**>"+v2s)
- addFormatterTest("%+v", nv2, "")
- addFormatterTest("%+v", v2, v2s)
- addFormatterTest("%+v", pv2, "<*>("+v2Addr+")"+v2s)
- addFormatterTest("%+v", &pv2, "<**>("+pv2Addr+"->"+v2Addr+")"+v2s)
- addFormatterTest("%+v", nv2, "")
- addFormatterTest("%#v", v2, "("+v2t+")"+v2s)
- addFormatterTest("%#v", pv2, "(*"+v2t+")"+v2s)
- addFormatterTest("%#v", &pv2, "(**"+v2t+")"+v2s)
- addFormatterTest("%#v", nv2, "(*"+v2t+")"+"")
- addFormatterTest("%#+v", v2, "("+v2t+")"+v2s)
- addFormatterTest("%#+v", pv2, "(*"+v2t+")("+v2Addr+")"+v2s)
- addFormatterTest("%#+v", &pv2, "(**"+v2t+")("+pv2Addr+"->"+v2Addr+")"+v2s)
- addFormatterTest("%#+v", nv2, "(*"+v2t+")"+"")
-
- // Function with multiple params and multiple returns.
- var v3 = func(i int, s string) (b bool, err error) {
- return true, nil
- }
- nv3 := (*func(int, string) (bool, error))(nil)
- pv3 := &v3
- v3Addr := fmt.Sprintf("%p", pv3)
- pv3Addr := fmt.Sprintf("%p", &pv3)
- v3t := "func(int, string) (bool, error)"
- v3s := fmt.Sprintf("%p", v3)
- addFormatterTest("%v", v3, v3s)
- addFormatterTest("%v", pv3, "<*>"+v3s)
- addFormatterTest("%v", &pv3, "<**>"+v3s)
- addFormatterTest("%+v", nv3, "")
- addFormatterTest("%+v", v3, v3s)
- addFormatterTest("%+v", pv3, "<*>("+v3Addr+")"+v3s)
- addFormatterTest("%+v", &pv3, "<**>("+pv3Addr+"->"+v3Addr+")"+v3s)
- addFormatterTest("%+v", nv3, "")
- addFormatterTest("%#v", v3, "("+v3t+")"+v3s)
- addFormatterTest("%#v", pv3, "(*"+v3t+")"+v3s)
- addFormatterTest("%#v", &pv3, "(**"+v3t+")"+v3s)
- addFormatterTest("%#v", nv3, "(*"+v3t+")"+"")
- addFormatterTest("%#+v", v3, "("+v3t+")"+v3s)
- addFormatterTest("%#+v", pv3, "(*"+v3t+")("+v3Addr+")"+v3s)
- addFormatterTest("%#+v", &pv3, "(**"+v3t+")("+pv3Addr+"->"+v3Addr+")"+v3s)
- addFormatterTest("%#+v", nv3, "(*"+v3t+")"+"")
-}
-
-func addCircularFormatterTests() {
- // Struct that is circular through self referencing.
- type circular struct {
- c *circular
- }
- v := circular{nil}
- v.c = &v
- pv := &v
- vAddr := fmt.Sprintf("%p", pv)
- pvAddr := fmt.Sprintf("%p", &pv)
- vt := "spew_test.circular"
- vs := "{<*>{<*>}}"
- vs2 := "{<*>}"
- vs3 := "{c:<*>(" + vAddr + "){c:<*>(" + vAddr + ")}}"
- vs4 := "{c:<*>(" + vAddr + ")}"
- vs5 := "{c:(*" + vt + "){c:(*" + vt + ")}}"
- vs6 := "{c:(*" + vt + ")}"
- vs7 := "{c:(*" + vt + ")(" + vAddr + "){c:(*" + vt + ")(" + vAddr +
- ")}}"
- vs8 := "{c:(*" + vt + ")(" + vAddr + ")}"
- addFormatterTest("%v", v, vs)
- addFormatterTest("%v", pv, "<*>"+vs2)
- addFormatterTest("%v", &pv, "<**>"+vs2)
- addFormatterTest("%+v", v, vs3)
- addFormatterTest("%+v", pv, "<*>("+vAddr+")"+vs4)
- addFormatterTest("%+v", &pv, "<**>("+pvAddr+"->"+vAddr+")"+vs4)
- addFormatterTest("%#v", v, "("+vt+")"+vs5)
- addFormatterTest("%#v", pv, "(*"+vt+")"+vs6)
- addFormatterTest("%#v", &pv, "(**"+vt+")"+vs6)
- addFormatterTest("%#+v", v, "("+vt+")"+vs7)
- addFormatterTest("%#+v", pv, "(*"+vt+")("+vAddr+")"+vs8)
- addFormatterTest("%#+v", &pv, "(**"+vt+")("+pvAddr+"->"+vAddr+")"+vs8)
-
- // Structs that are circular through cross referencing.
- v2 := xref1{nil}
- ts2 := xref2{&v2}
- v2.ps2 = &ts2
- pv2 := &v2
- ts2Addr := fmt.Sprintf("%p", &ts2)
- v2Addr := fmt.Sprintf("%p", pv2)
- pv2Addr := fmt.Sprintf("%p", &pv2)
- v2t := "spew_test.xref1"
- v2t2 := "spew_test.xref2"
- v2s := "{<*>{<*>{<*>}}}"
- v2s2 := "{<*>{<*>}}"
- v2s3 := "{ps2:<*>(" + ts2Addr + "){ps1:<*>(" + v2Addr + "){ps2:<*>(" +
- ts2Addr + ")}}}"
- v2s4 := "{ps2:<*>(" + ts2Addr + "){ps1:<*>(" + v2Addr + ")