Update vendor dir

This commit is contained in:
Elizabeth Engelman 2019-07-23 12:05:30 -05:00
parent 7cd66b8775
commit e637024cce
508 changed files with 97139 additions and 23000 deletions

230
Gopkg.lock generated
View File

@ -2,37 +2,29 @@
[[projects]] [[projects]]
digest = "1:48a213e9dc4880bbbd6999309a476fa4d3cc67560aa7127154cf8ea95bd464c2"
name = "github.com/allegro/bigcache" name = "github.com/allegro/bigcache"
packages = [ packages = [
".", ".",
"queue", "queue"
] ]
pruneopts = "" revision = "69ea0af04088faa57adb9ac683934277141e92a5"
revision = "f31987a23e44c5121ef8c8b2f2ea2e8ffa37b068" version = "v2.0.0"
version = "v1.1.0"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:a313376bcbcce8ae8bddb8089a7293e0473a0f8e9e3710d6244e09e81875ccf0"
name = "github.com/aristanetworks/goarista" name = "github.com/aristanetworks/goarista"
packages = ["monotime"] packages = ["monotime"]
pruneopts = "" revision = "ed1100a1c0154be237da0078e86b19c523c8c661"
revision = "ff33da284e760fcdb03c33d37a719e5ed30ba844"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:c6bf1ac7bbc0fe51637bf54d5a88ff79b171b3b42dbc665dec98303c862d8662"
name = "github.com/btcsuite/btcd" name = "github.com/btcsuite/btcd"
packages = ["btcec"] packages = ["btcec"]
pruneopts = "" revision = "c26ffa870fd817666a857af1bf6498fabba1ffe3"
revision = "cff30e1d23fc9e800b2b5b4b41ef1817dda07e9f"
[[projects]] [[projects]]
digest = "1:5d47691333460db6ac83ced03c79b4bdb9aff3e322be24affb7855bed8affc6c"
name = "github.com/dave/jennifer" name = "github.com/dave/jennifer"
packages = ["jen"] packages = ["jen"]
pruneopts = ""
revision = "14e399b6b5e8456c66c45c955fc27b568bacb5c9" revision = "14e399b6b5e8456c66c45c955fc27b568bacb5c9"
version = "v1.3.0" version = "v1.3.0"
@ -45,7 +37,6 @@
[[projects]] [[projects]]
name = "github.com/deckarep/golang-set" name = "github.com/deckarep/golang-set"
packages = ["."] packages = ["."]
pruneopts = ""
revision = "cbaa98ba5575e67703b32b4b19f73c91f3c4159e" revision = "cbaa98ba5575e67703b32b4b19f73c91f3c4159e"
version = "v1.7.1" version = "v1.7.1"
@ -140,10 +131,8 @@
revision = "bcb5799ab5e5bd6a0fbd8ba513f95a50d9eac048" revision = "bcb5799ab5e5bd6a0fbd8ba513f95a50d9eac048"
[[projects]] [[projects]]
digest = "1:eb53021a8aa3f599d29c7102e65026242bdedce998a54837dc67f14b6a97c5fd"
name = "github.com/fsnotify/fsnotify" name = "github.com/fsnotify/fsnotify"
packages = ["."] packages = ["."]
pruneopts = ""
revision = "c2828203cd70a50dcccfb2761f8b1f8ceef9a8e9" revision = "c2828203cd70a50dcccfb2761f8b1f8ceef9a8e9"
version = "v1.4.7" version = "v1.4.7"
@ -156,12 +145,10 @@
[[projects]] [[projects]]
name = "github.com/go-stack/stack" name = "github.com/go-stack/stack"
packages = ["."] packages = ["."]
pruneopts = ""
revision = "2fee6af1a9795aafbe0253a0cfbdf668e1fb8a9a" revision = "2fee6af1a9795aafbe0253a0cfbdf668e1fb8a9a"
version = "v1.8.0" version = "v1.8.0"
[[projects]] [[projects]]
digest = "1:3dd078fda7500c341bc26cfbc6c6a34614f295a2457149fc1045cab767cbcf18"
name = "github.com/golang/protobuf" name = "github.com/golang/protobuf"
packages = [ packages = [
"proto", "proto",
@ -170,34 +157,27 @@
revision = "6c65a5562fc06764971b7c5d05c76c75e84bdbf7" revision = "6c65a5562fc06764971b7c5d05c76c75e84bdbf7"
[[projects]] [[projects]]
branch = "master"
digest = "1:2a5888946cdbc8aa360fd43301f9fc7869d663f60d5eedae7d4e6e5e4f06f2bf"
name = "github.com/golang/snappy" name = "github.com/golang/snappy"
packages = ["."] packages = ["."]
pruneopts = "" revision = "2a8bb927dd31d8daada140a5d09578521ce5c36a"
revision = "2e65f85255dbc3072edf28d6b5b8efc472979f5a" version = "v0.0.1"
[[projects]] [[projects]]
digest = "1:5247b135b5492aa232a731acdcb52b08f32b874cb398f21ab460396eadbe866b"
name = "github.com/google/uuid" name = "github.com/google/uuid"
packages = ["."] packages = ["."]
pruneopts = "" revision = "0cd6bf5da1e1c83f8b45653022c74f71af0538a4"
revision = "d460ce9f8df2e77fb1ba55ca87fafed96c607494" version = "v1.1.1"
version = "v1.0.0"
[[projects]] [[projects]]
branch = "master"
digest = "1:9c776d7d9c54b7ed89f119e449983c3f24c0023e75001d6092442412ebca6b94"
name = "github.com/hashicorp/golang-lru" name = "github.com/hashicorp/golang-lru"
packages = [ packages = [
".", ".",
"simplelru", "simplelru"
] ]
pruneopts = "" revision = "7087cb70de9f7a8bc0a10c375cb0d2280a8edf9c"
revision = "0fb14efe8c47ae851c0034ed7a448854d3d34cf3" version = "v0.5.1"
[[projects]] [[projects]]
digest = "1:d14365c51dd1d34d5c79833ec91413bfbb166be978724f15701e17080dc06dec"
name = "github.com/hashicorp/hcl" name = "github.com/hashicorp/hcl"
packages = [ packages = [
".", ".",
@ -209,29 +189,24 @@
"hcl/token", "hcl/token",
"json/parser", "json/parser",
"json/scanner", "json/scanner",
"json/token", "json/token"
] ]
pruneopts = ""
revision = "8cb6e5b959231cc1119e43259c4a608f9c51a241" revision = "8cb6e5b959231cc1119e43259c4a608f9c51a241"
version = "v1.0.0" version = "v1.0.0"
[[projects]] [[projects]]
digest = "1:b3c5b95e56c06f5aa72cb2500e6ee5f44fcd122872d4fec2023a488e561218bc"
name = "github.com/hpcloud/tail" name = "github.com/hpcloud/tail"
packages = [ packages = [
".", ".",
"ratelimiter", "ratelimiter",
"util", "util",
"watch", "watch",
"winfile", "winfile"
] ]
pruneopts = ""
revision = "a30252cb686a21eb2d0b98132633053ec2f7f1e5" revision = "a30252cb686a21eb2d0b98132633053ec2f7f1e5"
version = "v1.0.0" version = "v1.0.0"
[[projects]] [[projects]]
branch = "master"
digest = "1:b6e4cc26365c004808649862e22069de09594a9222143399a7a04904e9f7018c"
name = "github.com/huin/goupnp" name = "github.com/huin/goupnp"
packages = [ packages = [
".", ".",
@ -240,37 +215,31 @@
"httpu", "httpu",
"scpd", "scpd",
"soap", "soap",
"ssdp", "ssdp"
] ]
pruneopts = "" revision = "656e61dfadd241c7cbdd22a023fa81ecb6860ea8"
revision = "1395d1447324cbea88d249fbfcfd70ea878fdfca" version = "v1.0.0"
[[projects]] [[projects]]
digest = "1:870d441fe217b8e689d7949fef6e43efbc787e50f200cb1e70dbca9204a1d6be"
name = "github.com/inconshreveable/mousetrap" name = "github.com/inconshreveable/mousetrap"
packages = ["."] packages = ["."]
pruneopts = ""
revision = "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75" revision = "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75"
version = "v1.0" version = "v1.0"
[[projects]] [[projects]]
digest = "1:76f836364ae83ed811c415aa92e1209ce49de9f62aad85b85fca749a8b96a110"
name = "github.com/jackpal/go-nat-pmp" name = "github.com/jackpal/go-nat-pmp"
packages = ["."] packages = ["."]
pruneopts = ""
revision = "c9cfead9f2a36ddf3daa40ba269aa7f4bbba6b62" revision = "c9cfead9f2a36ddf3daa40ba269aa7f4bbba6b62"
version = "v1.0.1" version = "v1.0.1"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:617ee2434b77e911fa26b678730be9a617f75243b194eadc8201c8ac860844aa"
name = "github.com/jmoiron/sqlx" name = "github.com/jmoiron/sqlx"
packages = [ packages = [
".", ".",
"reflectx", "reflectx"
] ]
pruneopts = "" revision = "38398a30ed8516ffda617a04c822de09df8a3ec5"
revision = "0dae4fefe7c0e190f7b5a78dac28a1c82cc8d849"
[[projects]] [[projects]]
branch = "master" branch = "master"
@ -281,28 +250,24 @@
[[projects]] [[projects]]
name = "github.com/konsorten/go-windows-terminal-sequences" name = "github.com/konsorten/go-windows-terminal-sequences"
packages = ["."] packages = ["."]
pruneopts = "" revision = "f55edac94c9bbba5d6182a4be46d86a2c9b5b50e"
revision = "5c8c8bd35d3832f5d134ae1e1e375b69a4d25242" version = "v1.0.2"
version = "v1.0.1"
[[projects]] [[projects]]
branch = "master"
digest = "1:29145d7af4adafd72a79df5e41456ac9e232d5a28c1cd4dacf3ff008a217fc10"
name = "github.com/lib/pq" name = "github.com/lib/pq"
packages = [ packages = [
".", ".",
"oid", "oid",
"scram"
] ]
pruneopts = "" revision = "3427c32cb71afc948325f299f040e53c1dd78979"
revision = "4ded0e9383f75c197b3a2aaa6d590ac52df6fd79" version = "v1.2.0"
[[projects]] [[projects]]
digest = "1:961dc3b1d11f969370533390fdf203813162980c858e1dabe827b60940c909a5"
name = "github.com/magiconair/properties" name = "github.com/magiconair/properties"
packages = ["."] packages = ["."]
pruneopts = "" revision = "de8848e004dd33dc07a2947b3d76f618a7fc7ef1"
revision = "c2353362d570a7bfa228149c62842019201cfb71" version = "v1.8.1"
version = "v1.8.0"
[[projects]] [[projects]]
name = "github.com/mattn/go-colorable" name = "github.com/mattn/go-colorable"
@ -325,17 +290,14 @@
[[projects]] [[projects]]
name = "github.com/mitchellh/go-homedir" name = "github.com/mitchellh/go-homedir"
packages = ["."] packages = ["."]
pruneopts = "" revision = "af06845cf3004701891bf4fdb884bfe4920b3727"
revision = "ae18d6b8b3205b561c79e8e5f69bff09736185f4" version = "v1.1.0"
version = "v1.0.0"
[[projects]] [[projects]]
digest = "1:5219b4506253ccc598f9340677162a42d6a78f340a4cc6df2d62db4d0593c4e9"
name = "github.com/mitchellh/mapstructure" name = "github.com/mitchellh/mapstructure"
packages = ["."] packages = ["."]
pruneopts = "" revision = "3536a929edddb9a5b34bd6861dc4a9647cb459fe"
revision = "fa473d140ef3c6adf42d6b391fe76707f1f243c8" version = "v1.1.2"
version = "v1.0.0"
[[projects]] [[projects]]
name = "github.com/olekukonko/tablewriter" name = "github.com/olekukonko/tablewriter"
@ -363,14 +325,12 @@
"reporters/stenographer", "reporters/stenographer",
"reporters/stenographer/support/go-colorable", "reporters/stenographer/support/go-colorable",
"reporters/stenographer/support/go-isatty", "reporters/stenographer/support/go-isatty",
"types", "types"
] ]
pruneopts = "" revision = "eea6ad008b96acdaa524f5b409513bf062b500ad"
revision = "3774a09d95489ccaa16032e0770d08ea77ba6184" version = "v1.8.0"
version = "v1.6.0"
[[projects]] [[projects]]
digest = "1:3ecd0a37c4a90c12a97e31c398cdbc173824351aa891898ee178120bfe71c478"
name = "github.com/onsi/gomega" name = "github.com/onsi/gomega"
packages = [ packages = [
".", ".",
@ -385,41 +345,32 @@
"matchers/support/goraph/edge", "matchers/support/goraph/edge",
"matchers/support/goraph/node", "matchers/support/goraph/node",
"matchers/support/goraph/util", "matchers/support/goraph/util",
"types", "types"
] ]
pruneopts = "" revision = "90e289841c1ed79b7a598a7cd9959750cb5e89e2"
revision = "7615b9433f86a8bdf29709bf288bc4fd0636a369" version = "v1.5.0"
version = "v1.4.2"
[[projects]] [[projects]]
digest = "1:a5484d4fa43127138ae6e7b2299a6a52ae006c7f803d98d717f60abf3e97192e"
name = "github.com/pborman/uuid" name = "github.com/pborman/uuid"
packages = ["."] packages = ["."]
pruneopts = ""
revision = "adf5a7427709b9deb95d29d3fa8a2bf9cfd388f1" revision = "adf5a7427709b9deb95d29d3fa8a2bf9cfd388f1"
version = "v1.2" version = "v1.2"
[[projects]] [[projects]]
digest = "1:894aef961c056b6d85d12bac890bf60c44e99b46292888bfa66caf529f804457"
name = "github.com/pelletier/go-toml" name = "github.com/pelletier/go-toml"
packages = ["."] packages = ["."]
pruneopts = "" revision = "728039f679cbcd4f6a54e080d2219a4c4928c546"
revision = "c01d1270ff3e442a8a57cddc1c92dc1138598194" version = "v1.4.0"
version = "v1.2.0"
[[projects]] [[projects]]
digest = "1:1d7e1867c49a6dd9856598ef7c3123604ea3daabf5b83f303ff457bcbc410b1d"
name = "github.com/pkg/errors" name = "github.com/pkg/errors"
packages = ["."] packages = ["."]
pruneopts = ""
revision = "ba968bfe8b2f7e042a574c888954fccecfa385b4" revision = "ba968bfe8b2f7e042a574c888954fccecfa385b4"
version = "v0.8.1" version = "v0.8.1"
[[projects]] [[projects]]
digest = "1:fdbe7e05d74cc4d175cc4515a7807a5bb8b66ebe130da382b99713c9038648ae"
name = "github.com/pressly/goose" name = "github.com/pressly/goose"
packages = ["."] packages = ["."]
pruneopts = ""
revision = "e4b98955473e91a12fc7d8816c28d06376d1d92c" revision = "e4b98955473e91a12fc7d8816c28d06376d1d92c"
version = "v2.6.0" version = "v2.6.0"
@ -432,76 +383,59 @@
[[projects]] [[projects]]
name = "github.com/rjeczalik/notify" name = "github.com/rjeczalik/notify"
packages = ["."] packages = ["."]
pruneopts = "" revision = "69d839f37b13a8cb7a78366f7633a4071cb43be7"
revision = "0f065fa99b48b842c3fd3e2c8b194c6f2b69f6b8" version = "v0.9.2"
version = "v0.9.1"
[[projects]] [[projects]]
digest = "1:78c9cf43ddeacd0e472f412082227a0fac2ae107ee60e9112156f9371f9912cf"
name = "github.com/rs/cors" name = "github.com/rs/cors"
packages = ["."] packages = ["."]
pruneopts = "" revision = "9a47f48565a795472d43519dd49aac781f3034fb"
revision = "3fb1b69b103a84de38a19c3c6ec073dd6caa4d3f" version = "v1.6.0"
version = "v1.5.0"
[[projects]] [[projects]]
digest = "1:9d57e200ef5ccc4217fe0a34287308bac652435e7c6513f6263e0493d2245c56"
name = "github.com/sirupsen/logrus" name = "github.com/sirupsen/logrus"
packages = ["."] packages = ["."]
pruneopts = "" revision = "839c75faf7f98a33d445d181f3018b5c3409a45e"
revision = "bcd833dfe83d3cebad139e4a29ed79cb2318bf95" version = "v1.4.2"
version = "v1.2.0"
[[projects]] [[projects]]
digest = "1:d0431c2fd72e39ee43ea7742322abbc200c3e704c9102c5c3c2e2e667095b0ca"
name = "github.com/spf13/afero" name = "github.com/spf13/afero"
packages = [ packages = [
".", ".",
"mem", "mem"
] ]
pruneopts = "" revision = "588a75ec4f32903aa5e39a2619ba6a4631e28424"
revision = "d40851caa0d747393da1ffb28f7f9d8b4eeffebd" version = "v1.2.2"
version = "v1.1.2"
[[projects]] [[projects]]
digest = "1:d0b38ba6da419a6d4380700218eeec8623841d44a856bb57369c172fbf692ab4"
name = "github.com/spf13/cast" name = "github.com/spf13/cast"
packages = ["."] packages = ["."]
pruneopts = "" revision = "8c9545af88b134710ab1cd196795e7f2388358d7"
revision = "8965335b8c7107321228e3e3702cab9832751bac" version = "v1.3.0"
version = "v1.2.0"
[[projects]] [[projects]]
digest = "1:a1403cc8a94b8d7956ee5e9694badef0e7b051af289caad1cf668331e3ffa4f6"
name = "github.com/spf13/cobra" name = "github.com/spf13/cobra"
packages = ["."] packages = ["."]
pruneopts = "" revision = "f2b07da1e2c38d5f12845a4f607e2e1018cbb1f5"
revision = "ef82de70bb3f60c65fb8eebacbb2d122ef517385" version = "v0.0.5"
version = "v0.0.3"
[[projects]] [[projects]]
digest = "1:9ceffa4ab5f7195ecf18b3a7fff90c837a9ed5e22e66d18069e4bccfe1f52aa0"
name = "github.com/spf13/jwalterweatherman" name = "github.com/spf13/jwalterweatherman"
packages = ["."] packages = ["."]
pruneopts = "" revision = "94f6ae3ed3bceceafa716478c5fbf8d29ca601a1"
revision = "4a4406e478ca629068e7768fc33f3f044173c0a6" version = "v1.1.0"
version = "v1.0.0"
[[projects]] [[projects]]
digest = "1:0a52bcb568386d98f4894575d53ce3e456f56471de6897bb8b9de13c33d9340e"
name = "github.com/spf13/pflag" name = "github.com/spf13/pflag"
packages = ["."] packages = ["."]
pruneopts = "" revision = "298182f68c66c05229eb03ac171abe6e309ee79a"
revision = "9a97c102cda95a86cec2345a6f09f55a939babf5" version = "v1.0.3"
version = "v1.0.2"
[[projects]] [[projects]]
digest = "1:ac25ea6cc1156aca9611411274b4a0bdd83a623845df6985aab508253955cc66"
name = "github.com/spf13/viper" name = "github.com/spf13/viper"
packages = ["."] packages = ["."]
pruneopts = "" revision = "b5bf975e5823809fb22c7644d008757f78a4259e"
revision = "8fb642006536c8d3760c99d4fa2389f5e2205631" version = "v1.4.0"
version = "v1.2.0"
[[projects]] [[projects]]
branch = "develop" branch = "develop"
@ -522,8 +456,6 @@
version = "0.2.5" version = "0.2.5"
[[projects]] [[projects]]
branch = "master"
digest = "1:ce5194e5afac308cc34e500cab45b4ce88a0742d689e3cf7e37b607ad76bed2f"
name = "github.com/syndtr/goleveldb" name = "github.com/syndtr/goleveldb"
packages = [ packages = [
"leveldb", "leveldb",
@ -537,10 +469,10 @@
"leveldb/opt", "leveldb/opt",
"leveldb/storage", "leveldb/storage",
"leveldb/table", "leveldb/table",
"leveldb/util", "leveldb/util"
] ]
pruneopts = "" revision = "9d007e481048296f09f59bd19bb7ae584563cd95"
revision = "ae2bd5eed72d46b28834ec3f60db3a3ebedd8dbd" version = "v1.0.0"
[[projects]] [[projects]]
name = "github.com/tyler-smith/go-bip39" name = "github.com/tyler-smith/go-bip39"
@ -559,7 +491,6 @@
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:59b49c47c11a48f1054529207f65907c014ecf5f9a7c0d9c0f1616dec7b062ed"
name = "golang.org/x/crypto" name = "golang.org/x/crypto"
packages = [ packages = [
"curve25519", "curve25519",
@ -567,46 +498,39 @@
"ripemd160", "ripemd160",
"scrypt", "scrypt",
"sha3", "sha3",
"ssh/terminal", "ssh/terminal"
] ]
pruneopts = "" revision = "4def268fd1a49955bfb3dda92fe3db4f924f2285"
revision = "ff983b9c42bc9fbf91556e191cc8efb585c16908"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:fbdbb6cf8db3278412c9425ad78b26bb8eb788181f26a3ffb3e4f216b314f86a"
name = "golang.org/x/net" name = "golang.org/x/net"
packages = [ packages = [
"context", "context",
"html", "html",
"html/atom", "html/atom",
"html/charset", "html/charset",
"websocket"
] ]
pruneopts = "" revision = "da137c7871d730100384dbcf36e6f8fa493aef5b"
revision = "26e67e76b6c3f6ce91f7c52def5af501b4e0f3a2"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:b2ea75de0ccb2db2ac79356407f8a4cd8f798fe15d41b381c00abf3ae8e55ed1"
name = "golang.org/x/sync" name = "golang.org/x/sync"
packages = ["errgroup"] packages = ["errgroup"]
pruneopts = "" revision = "112230192c580c3556b8cee6403af37a4fc5f28c"
revision = "1d60e4601c6fd243af51cc01ddf169918a5407ca"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:70d519d5cddeb60ceda2db88c24c340b1b2d7efb25ab54bacb38f57ea1998df7"
name = "golang.org/x/sys" name = "golang.org/x/sys"
packages = [ packages = [
"cpu", "cpu",
"unix", "unix",
"windows", "windows"
] ]
pruneopts = "" revision = "fae7ac547cb717d141c433a2a173315e216b64c4"
revision = "d641721ec2dead6fe5ca284096fe4b1fcd49e427"
[[projects]] [[projects]]
digest = "1:5acd3512b047305d49e8763eef7ba423901e85d5dd2fd1e71778a0ea8de10bd4"
name = "golang.org/x/text" name = "golang.org/x/text"
packages = [ packages = [
"encoding", "encoding",
@ -620,6 +544,8 @@
"encoding/traditionalchinese", "encoding/traditionalchinese",
"encoding/unicode", "encoding/unicode",
"internal/gen", "internal/gen",
"internal/language",
"internal/language/compact",
"internal/tag", "internal/tag",
"internal/triegen", "internal/triegen",
"internal/ucd", "internal/ucd",
@ -628,35 +554,28 @@
"runes", "runes",
"transform", "transform",
"unicode/cldr", "unicode/cldr",
"unicode/norm", "unicode/norm"
] ]
pruneopts = "" revision = "342b2e1fbaa52c93f31447ad2c6abc048c63e475"
revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0" version = "v0.3.2"
version = "v0.3.0"
[[projects]] [[projects]]
digest = "1:eb53021a8aa3f599d29c7102e65026242bdedce998a54837dc67f14b6a97c5fd"
name = "gopkg.in/fsnotify.v1" name = "gopkg.in/fsnotify.v1"
packages = ["."] packages = ["."]
pruneopts = ""
revision = "c2828203cd70a50dcccfb2761f8b1f8ceef9a8e9" revision = "c2828203cd70a50dcccfb2761f8b1f8ceef9a8e9"
source = "gopkg.in/fsnotify/fsnotify.v1" source = "gopkg.in/fsnotify/fsnotify.v1"
version = "v1.4.7" version = "v1.4.7"
[[projects]] [[projects]]
branch = "v2" branch = "v2"
digest = "1:4f830ee018eb8c56d0def653ad7c9a1d2a053f0cef2ac6b2200f73b98fa6a681"
name = "gopkg.in/natefinch/npipe.v2" name = "gopkg.in/natefinch/npipe.v2"
packages = ["."] packages = ["."]
pruneopts = ""
revision = "c1b8fa8bdccecb0b8db834ee0b92fdbcfa606dd6" revision = "c1b8fa8bdccecb0b8db834ee0b92fdbcfa606dd6"
[[projects]] [[projects]]
branch = "v1" branch = "v1"
digest = "1:a96d16bd088460f2e0685d46c39bcf1208ba46e0a977be2df49864ec7da447dd"
name = "gopkg.in/tomb.v1" name = "gopkg.in/tomb.v1"
packages = ["."] packages = ["."]
pruneopts = ""
revision = "dd632973f1e7218eb1089048e0798ec9ae7dceb8" revision = "dd632973f1e7218eb1089048e0798ec9ae7dceb8"
[[projects]] [[projects]]
@ -668,9 +587,8 @@
[[projects]] [[projects]]
name = "gopkg.in/yaml.v2" name = "gopkg.in/yaml.v2"
packages = ["."] packages = ["."]
pruneopts = "" revision = "51d6538a90f86fe93ac480b35f37b2be17fef232"
revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183" version = "v2.2.2"
version = "v2.2.1"
[solve-meta] [solve-meta]
analyzer-name = "dep" analyzer-name = "dep"

View File

@ -2,4 +2,9 @@
.DS_Store .DS_Store
/server/server.exe /server/server.exe
/server/server /server/server
/server/server_dar*
/server/server_fre*
/server/server_win*
/server/server_net*
/server/server_ope*
CHANGELOG.md CHANGELOG.md

View File

@ -14,7 +14,7 @@ before_install:
- go get github.com/mattn/goveralls - go get github.com/mattn/goveralls
- go get golang.org/x/tools/cmd/cover - go get golang.org/x/tools/cmd/cover
- go get golang.org/x/tools/cmd/goimports - go get golang.org/x/tools/cmd/goimports
- go get github.com/golang/lint/golint - go get golang.org/x/lint/golint
- go get github.com/stretchr/testify/assert - go get github.com/stretchr/testify/assert
- go get github.com/gordonklaus/ineffassign - go get github.com/gordonklaus/ineffassign

View File

@ -46,10 +46,15 @@ config := bigcache.Config {
// if value is reached then the oldest entries can be overridden for the new ones // if value is reached then the oldest entries can be overridden for the new ones
// 0 value means no size limit // 0 value means no size limit
HardMaxCacheSize: 8192, HardMaxCacheSize: 8192,
// callback fired when the oldest entry is removed because of its // callback fired when the oldest entry is removed because of its expiration time or no space left
// expiration time or no space left for the new entry. Default value is nil which // for the new entry, or because delete was called. A bitmask representing the reason will be returned.
// means no callback and it prevents from unwrapping the oldest entry. // Default value is nil which means no callback and it prevents from unwrapping the oldest entry.
OnRemove: nil, OnRemove: nil,
// OnRemoveWithReason is a callback fired when the oldest entry is removed because of its expiration time or no space left
// for the new entry, or because delete was called. A constant representing the reason will be passed through.
// Default value is nil which means no callback and it prevents from unwrapping the oldest entry.
// Ignored if OnRemove is specified.
OnRemoveWithReason: nil,
} }
cache, initErr := bigcache.NewBigCache(config) cache, initErr := bigcache.NewBigCache(config)
@ -74,20 +79,20 @@ Benchmark tests were made using an i7-6700K with 32GB of RAM on Windows 10.
```bash ```bash
cd caches_bench; go test -bench=. -benchtime=10s ./... -timeout 30m cd caches_bench; go test -bench=. -benchtime=10s ./... -timeout 30m
BenchmarkMapSet-8 2000000 716 ns/op 336 B/op 3 allocs/op BenchmarkMapSet-8 3000000 569 ns/op 202 B/op 3 allocs/op
BenchmarkConcurrentMapSet-8 1000000 1292 ns/op 347 B/op 8 allocs/op BenchmarkConcurrentMapSet-8 1000000 1592 ns/op 347 B/op 8 allocs/op
BenchmarkFreeCacheSet-8 3000000 501 ns/op 371 B/op 3 allocs/op BenchmarkFreeCacheSet-8 3000000 775 ns/op 355 B/op 2 allocs/op
BenchmarkBigCacheSet-8 3000000 482 ns/op 303 B/op 2 allocs/op BenchmarkBigCacheSet-8 3000000 640 ns/op 303 B/op 2 allocs/op
BenchmarkMapGet-8 5000000 309 ns/op 24 B/op 1 allocs/op BenchmarkMapGet-8 5000000 407 ns/op 24 B/op 1 allocs/op
BenchmarkConcurrentMapGet-8 2000000 659 ns/op 24 B/op 2 allocs/op BenchmarkConcurrentMapGet-8 3000000 558 ns/op 24 B/op 2 allocs/op
BenchmarkFreeCacheGet-8 3000000 541 ns/op 152 B/op 3 allocs/op BenchmarkFreeCacheGet-8 2000000 682 ns/op 136 B/op 2 allocs/op
BenchmarkBigCacheGet-8 3000000 420 ns/op 152 B/op 3 allocs/op BenchmarkBigCacheGet-8 3000000 512 ns/op 152 B/op 4 allocs/op
BenchmarkBigCacheSetParallel-8 10000000 184 ns/op 313 B/op 3 allocs/op BenchmarkBigCacheSetParallel-8 10000000 225 ns/op 313 B/op 3 allocs/op
BenchmarkFreeCacheSetParallel-8 10000000 195 ns/op 357 B/op 4 allocs/op BenchmarkFreeCacheSetParallel-8 10000000 218 ns/op 341 B/op 3 allocs/op
BenchmarkConcurrentMapSetParallel-8 5000000 242 ns/op 200 B/op 6 allocs/op BenchmarkConcurrentMapSetParallel-8 5000000 318 ns/op 200 B/op 6 allocs/op
BenchmarkBigCacheGetParallel-8 20000000 100 ns/op 152 B/op 4 allocs/op BenchmarkBigCacheGetParallel-8 20000000 178 ns/op 152 B/op 4 allocs/op
BenchmarkFreeCacheGetParallel-8 10000000 133 ns/op 152 B/op 4 allocs/op BenchmarkFreeCacheGetParallel-8 20000000 295 ns/op 136 B/op 3 allocs/op
BenchmarkConcurrentMapGetParallel-8 10000000 202 ns/op 24 B/op 2 allocs/op BenchmarkConcurrentMapGetParallel-8 10000000 237 ns/op 24 B/op 2 allocs/op
``` ```
Writes and reads in bigcache are faster than in freecache. Writes and reads in bigcache are faster than in freecache.

View File

@ -10,7 +10,7 @@ const (
) )
// BigCache is fast, concurrent, evicting cache created to keep big number of entries without impact on performance. // BigCache is fast, concurrent, evicting cache created to keep big number of entries without impact on performance.
// It keeps entries on heap but omits GC for them. To achieve that operations on bytes arrays take place, // It keeps entries on heap but omits GC for them. To achieve that, operations take place on byte arrays,
// therefore entries (de)serialization in front of the cache will be needed in most use cases. // therefore entries (de)serialization in front of the cache will be needed in most use cases.
type BigCache struct { type BigCache struct {
shards []*cacheShard shards []*cacheShard
@ -20,8 +20,22 @@ type BigCache struct {
config Config config Config
shardMask uint64 shardMask uint64
maxShardSize uint32 maxShardSize uint32
close chan struct{}
} }
// RemoveReason is a value used to signal to the user why a particular key was removed in the OnRemove callback.
type RemoveReason uint32
const (
// Expired means the key is past its LifeWindow.
Expired RemoveReason = iota
// NoSpace means the key is the oldest and the cache size was at its maximum when Set was called, or the
// entry exceeded the maximum shard size.
NoSpace
// Deleted means Delete was called and this key was removed as a result.
Deleted
)
// NewBigCache initialize new instance of BigCache // NewBigCache initialize new instance of BigCache
func NewBigCache(config Config) (*BigCache, error) { func NewBigCache(config Config) (*BigCache, error) {
return newBigCache(config, &systemClock{}) return newBigCache(config, &systemClock{})
@ -45,13 +59,16 @@ func newBigCache(config Config, clock clock) (*BigCache, error) {
config: config, config: config,
shardMask: uint64(config.Shards - 1), shardMask: uint64(config.Shards - 1),
maxShardSize: uint32(config.maximumShardSize()), maxShardSize: uint32(config.maximumShardSize()),
close: make(chan struct{}),
} }
var onRemove func(wrappedEntry []byte) var onRemove func(wrappedEntry []byte, reason RemoveReason)
if config.OnRemove == nil { if config.OnRemove != nil {
onRemove = cache.notProvidedOnRemove
} else {
onRemove = cache.providedOnRemove onRemove = cache.providedOnRemove
} else if config.OnRemoveWithReason != nil {
onRemove = cache.providedOnRemoveWithReason
} else {
onRemove = cache.notProvidedOnRemove
} }
for i := 0; i < config.Shards; i++ { for i := 0; i < config.Shards; i++ {
@ -60,8 +77,15 @@ func newBigCache(config Config, clock clock) (*BigCache, error) {
if config.CleanWindow > 0 { if config.CleanWindow > 0 {
go func() { go func() {
for t := range time.Tick(config.CleanWindow) { ticker := time.NewTicker(config.CleanWindow)
cache.cleanUp(uint64(t.Unix())) defer ticker.Stop()
for {
select {
case t := <-ticker.C:
cache.cleanUp(uint64(t.Unix()))
case <-cache.close:
return
}
} }
}() }()
} }
@ -69,8 +93,16 @@ func newBigCache(config Config, clock clock) (*BigCache, error) {
return cache, nil return cache, nil
} }
// Close is used to signal a shutdown of the cache when you are done with it.
// This allows the cleaning goroutines to exit and ensures references are not
// kept to the cache preventing GC of the entire cache.
func (c *BigCache) Close() error {
close(c.close)
return nil
}
// Get reads entry for the key. // Get reads entry for the key.
// It returns an EntryNotFoundError when // It returns an ErrEntryNotFound when
// no entry exists for the given key. // no entry exists for the given key.
func (c *BigCache) Get(key string) ([]byte, error) { func (c *BigCache) Get(key string) ([]byte, error) {
hashedKey := c.hash.Sum64(key) hashedKey := c.hash.Sum64(key)
@ -109,6 +141,15 @@ func (c *BigCache) Len() int {
return len return len
} }
// Capacity returns amount of bytes store in the cache.
func (c *BigCache) Capacity() int {
var len int
for _, shard := range c.shards {
len += shard.capacity()
}
return len
}
// Stats returns cache's statistics // Stats returns cache's statistics
func (c *BigCache) Stats() Stats { func (c *BigCache) Stats() Stats {
var s Stats var s Stats
@ -128,10 +169,10 @@ func (c *BigCache) Iterator() *EntryInfoIterator {
return newIterator(c) return newIterator(c)
} }
func (c *BigCache) onEvict(oldestEntry []byte, currentTimestamp uint64, evict func() error) bool { func (c *BigCache) onEvict(oldestEntry []byte, currentTimestamp uint64, evict func(reason RemoveReason) error) bool {
oldestTimestamp := readTimestampFromEntry(oldestEntry) oldestTimestamp := readTimestampFromEntry(oldestEntry)
if currentTimestamp-oldestTimestamp > c.lifeWindow { if currentTimestamp-oldestTimestamp > c.lifeWindow {
evict() evict(Expired)
return true return true
} }
return false return false
@ -147,9 +188,15 @@ func (c *BigCache) getShard(hashedKey uint64) (shard *cacheShard) {
return c.shards[hashedKey&c.shardMask] return c.shards[hashedKey&c.shardMask]
} }
func (c *BigCache) providedOnRemove(wrappedEntry []byte) { func (c *BigCache) providedOnRemove(wrappedEntry []byte, reason RemoveReason) {
c.config.OnRemove(readKeyFromEntry(wrappedEntry), readEntry(wrappedEntry)) c.config.OnRemove(readKeyFromEntry(wrappedEntry), readEntry(wrappedEntry))
} }
func (c *BigCache) notProvidedOnRemove(wrappedEntry []byte) { func (c *BigCache) providedOnRemoveWithReason(wrappedEntry []byte, reason RemoveReason) {
if c.config.onRemoveFilter == 0 || (1<<uint(reason))&c.config.onRemoveFilter > 0 {
c.config.OnRemoveWithReason(readKeyFromEntry(wrappedEntry), readEntry(wrappedEntry), reason)
}
}
func (c *BigCache) notProvidedOnRemove(wrappedEntry []byte, reason RemoveReason) {
} }

14
vendor/github.com/allegro/bigcache/bytes.go generated vendored Normal file
View File

@ -0,0 +1,14 @@
// +build !appengine
package bigcache
import (
"reflect"
"unsafe"
)
func bytesToString(b []byte) string {
bytesHeader := (*reflect.SliceHeader)(unsafe.Pointer(&b))
strHeader := reflect.StringHeader{Data: bytesHeader.Data, Len: bytesHeader.Len}
return *(*string)(unsafe.Pointer(&strHeader))
}

View File

@ -0,0 +1,7 @@
// +build appengine
package bigcache
func bytesToString(b []byte) string {
return string(b)
}

View File

@ -26,8 +26,16 @@ type Config struct {
// the oldest entries are overridden for the new ones. // the oldest entries are overridden for the new ones.
HardMaxCacheSize int HardMaxCacheSize int
// OnRemove is a callback fired when the oldest entry is removed because of its expiration time or no space left // OnRemove is a callback fired when the oldest entry is removed because of its expiration time or no space left
// for the new entry. Default value is nil which means no callback and it prevents from unwrapping the oldest entry. // for the new entry, or because delete was called.
// Default value is nil which means no callback and it prevents from unwrapping the oldest entry.
OnRemove func(key string, entry []byte) OnRemove func(key string, entry []byte)
// OnRemoveWithReason is a callback fired when the oldest entry is removed because of its expiration time or no space left
// for the new entry, or because delete was called. A constant representing the reason will be passed through.
// Default value is nil which means no callback and it prevents from unwrapping the oldest entry.
// Ignored if OnRemove is specified.
OnRemoveWithReason func(key string, entry []byte, reason RemoveReason)
onRemoveFilter int
// Logger is a logging interface and used in combination with `Verbose` // Logger is a logging interface and used in combination with `Verbose`
// Defaults to `DefaultLogger()` // Defaults to `DefaultLogger()`
@ -65,3 +73,14 @@ func (c Config) maximumShardSize() int {
return maxShardSize return maxShardSize
} }
// OnRemoveFilterSet sets which remove reasons will trigger a call to OnRemoveWithReason.
// Filtering out reasons prevents bigcache from unwrapping them, which saves cpu.
func (c Config) OnRemoveFilterSet(reasons ...RemoveReason) Config {
c.onRemoveFilter = 0
for i := range reasons {
c.onRemoveFilter |= 1 << uint(reasons[i])
}
return c
}

View File

@ -2,8 +2,6 @@ package bigcache
import ( import (
"encoding/binary" "encoding/binary"
"reflect"
"unsafe"
) )
const ( const (
@ -55,12 +53,6 @@ func readKeyFromEntry(data []byte) string {
return bytesToString(dst) return bytesToString(dst)
} }
func bytesToString(b []byte) string {
bytesHeader := (*reflect.SliceHeader)(unsafe.Pointer(&b))
strHeader := reflect.StringHeader{Data: bytesHeader.Data, Len: bytesHeader.Len}
return *(*string)(unsafe.Pointer(&strHeader))
}
func readHashFromEntry(data []byte) uint64 { func readHashFromEntry(data []byte) uint64 {
return binary.LittleEndian.Uint64(data[timestampSizeInBytes:]) return binary.LittleEndian.Uint64(data[timestampSizeInBytes:])
} }

View File

@ -1,17 +1,6 @@
package bigcache package bigcache
import "fmt" import "errors"
// EntryNotFoundError is an error type struct which is returned when entry was not found for provided key // ErrEntryNotFound is an error type struct which is returned when entry was not found for provided key
type EntryNotFoundError struct { var ErrEntryNotFound = errors.New("Entry not found")
message string
}
func notFound(key string) error {
return &EntryNotFoundError{fmt.Sprintf("Entry %q not found", key)}
}
// Error returned when entry does not exist.
func (e EntryNotFoundError) Error() string {
return e.message
}

9
vendor/github.com/allegro/bigcache/go.mod generated vendored Normal file
View File

@ -0,0 +1,9 @@
module github.com/allegro/bigcache
go 1.12
require (
github.com/cespare/xxhash v1.1.0 // indirect
github.com/coocood/freecache v1.1.0
github.com/stretchr/testify v1.3.0
)

13
vendor/github.com/allegro/bigcache/go.sum generated vendored Normal file
View File

@ -0,0 +1,13 @@
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/coocood/freecache v1.1.0 h1:ENiHOsWdj1BrrlPwblhbn4GdAsMymK3pZORJ+bJGAjA=
github.com/coocood/freecache v1.1.0/go.mod h1:ePwxCDzOYvARfHdr1pByNct1at3CoKnsipOHwKlNbzI=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=

238
vendor/github.com/allegro/bigcache/queue/bytes_queue.go generated vendored Normal file
View File

@ -0,0 +1,238 @@
package queue
import (
"encoding/binary"
"log"
"time"
)
const (
// Number of bytes used to keep information about entry size
headerEntrySize = 4
// Bytes before left margin are not used. Zero index means element does not exist in queue, useful while reading slice from index
leftMarginIndex = 1
// Minimum empty blob size in bytes. Empty blob fills space between tail and head in additional memory allocation.
// It keeps entries indexes unchanged
minimumEmptyBlobSize = 32 + headerEntrySize
)
var (
errEmptyQueue = &queueError{"Empty queue"}
errInvalidIndex = &queueError{"Index must be greater than zero. Invalid index."}
errIndexOutOfBounds = &queueError{"Index out of range"}
)
// BytesQueue is a non-thread safe queue type of fifo based on bytes array.
// For every push operation index of entry is returned. It can be used to read the entry later
type BytesQueue struct {
array []byte
capacity int
maxCapacity int
head int
tail int
count int
rightMargin int
headerBuffer []byte
verbose bool
initialCapacity int
}
type queueError struct {
message string
}
// NewBytesQueue initialize new bytes queue.
// Initial capacity is used in bytes array allocation
// When verbose flag is set then information about memory allocation are printed
func NewBytesQueue(initialCapacity int, maxCapacity int, verbose bool) *BytesQueue {
return &BytesQueue{
array: make([]byte, initialCapacity),
capacity: initialCapacity,
maxCapacity: maxCapacity,
headerBuffer: make([]byte, headerEntrySize),
tail: leftMarginIndex,
head: leftMarginIndex,
rightMargin: leftMarginIndex,
verbose: verbose,
initialCapacity: initialCapacity,
}
}
// Reset removes all entries from queue
func (q *BytesQueue) Reset() {
// Just reset indexes
q.tail = leftMarginIndex
q.head = leftMarginIndex
q.rightMargin = leftMarginIndex
q.count = 0
}
// Push copies entry at the end of queue and moves tail pointer. Allocates more space if needed.
// Returns index for pushed data or error if maximum size queue limit is reached.
func (q *BytesQueue) Push(data []byte) (int, error) {
dataLen := len(data)
if q.availableSpaceAfterTail() < dataLen+headerEntrySize {
if q.availableSpaceBeforeHead() >= dataLen+headerEntrySize {
q.tail = leftMarginIndex
} else if q.capacity+headerEntrySize+dataLen >= q.maxCapacity && q.maxCapacity > 0 {
return -1, &queueError{"Full queue. Maximum size limit reached."}
} else {
q.allocateAdditionalMemory(dataLen + headerEntrySize)
}
}
index := q.tail
q.push(data, dataLen)
return index, nil
}
func (q *BytesQueue) allocateAdditionalMemory(minimum int) {
start := time.Now()
if q.capacity < minimum {
q.capacity += minimum
}
q.capacity = q.capacity * 2
if q.capacity > q.maxCapacity && q.maxCapacity > 0 {
q.capacity = q.maxCapacity
}
oldArray := q.array
q.array = make([]byte, q.capacity)
if leftMarginIndex != q.rightMargin {
copy(q.array, oldArray[:q.rightMargin])
if q.tail < q.head {
emptyBlobLen := q.head - q.tail - headerEntrySize
q.push(make([]byte, emptyBlobLen), emptyBlobLen)
q.head = leftMarginIndex
q.tail = q.rightMargin
}
}
if q.verbose {
log.Printf("Allocated new queue in %s; Capacity: %d \n", time.Since(start), q.capacity)
}
}
func (q *BytesQueue) push(data []byte, len int) {
binary.LittleEndian.PutUint32(q.headerBuffer, uint32(len))
q.copy(q.headerBuffer, headerEntrySize)
q.copy(data, len)
if q.tail > q.head {
q.rightMargin = q.tail
}
q.count++
}
func (q *BytesQueue) copy(data []byte, len int) {
q.tail += copy(q.array[q.tail:], data[:len])
}
// Pop reads the oldest entry from queue and moves head pointer to the next one
func (q *BytesQueue) Pop() ([]byte, error) {
data, size, err := q.peek(q.head)
if err != nil {
return nil, err
}
q.head += headerEntrySize + size
q.count--
if q.head == q.rightMargin {
q.head = leftMarginIndex
if q.tail == q.rightMargin {
q.tail = leftMarginIndex
}
q.rightMargin = q.tail
}
return data, nil
}
// Peek reads the oldest entry from list without moving head pointer
func (q *BytesQueue) Peek() ([]byte, error) {
data, _, err := q.peek(q.head)
return data, err
}
// Get reads entry from index
func (q *BytesQueue) Get(index int) ([]byte, error) {
data, _, err := q.peek(index)
return data, err
}
// CheckGet checks if an entry can be read from index
func (q *BytesQueue) CheckGet(index int) error {
return q.peekCheckErr(index)
}
// Capacity returns number of allocated bytes for queue
func (q *BytesQueue) Capacity() int {
return q.capacity
}
// Len returns number of entries kept in queue
func (q *BytesQueue) Len() int {
return q.count
}
// Error returns error message
func (e *queueError) Error() string {
return e.message
}
// peekCheckErr is identical to peek, but does not actually return any data
func (q *BytesQueue) peekCheckErr(index int) error {
if q.count == 0 {
return errEmptyQueue
}
if index <= 0 {
return errInvalidIndex
}
if index+headerEntrySize >= len(q.array) {
return errIndexOutOfBounds
}
return nil
}
func (q *BytesQueue) peek(index int) ([]byte, int, error) {
if q.count == 0 {
return nil, 0, errEmptyQueue
}
if index <= 0 {
return nil, 0, errInvalidIndex
}
if index+headerEntrySize >= len(q.array) {
return nil, 0, errIndexOutOfBounds
}
blockSize := int(binary.LittleEndian.Uint32(q.array[index : index+headerEntrySize]))
return q.array[index+headerEntrySize : index+headerEntrySize+blockSize], blockSize, nil
}
func (q *BytesQueue) availableSpaceAfterTail() int {
if q.tail >= q.head {
return q.capacity - q.tail
}
return q.head - q.tail - minimumEmptyBlobSize
}
func (q *BytesQueue) availableSpaceBeforeHead() int {
if q.tail >= q.head {
return q.head - leftMarginIndex - minimumEmptyBlobSize
}
return q.head - q.tail - minimumEmptyBlobSize
}

View File

@ -8,12 +8,14 @@ import (
"github.com/allegro/bigcache/queue" "github.com/allegro/bigcache/queue"
) )
type onRemoveCallback func(wrappedEntry []byte, reason RemoveReason)
type cacheShard struct { type cacheShard struct {
hashmap map[uint64]uint32 hashmap map[uint64]uint32
entries queue.BytesQueue entries queue.BytesQueue
lock sync.RWMutex lock sync.RWMutex
entryBuffer []byte entryBuffer []byte
onRemove func(wrappedEntry []byte) onRemove onRemoveCallback
isVerbose bool isVerbose bool
logger Logger logger Logger
@ -23,8 +25,6 @@ type cacheShard struct {
stats Stats stats Stats
} }
type onRemoveCallback func(wrappedEntry []byte)
func (s *cacheShard) get(key string, hashedKey uint64) ([]byte, error) { func (s *cacheShard) get(key string, hashedKey uint64) ([]byte, error) {
s.lock.RLock() s.lock.RLock()
itemIndex := s.hashmap[hashedKey] itemIndex := s.hashmap[hashedKey]
@ -32,7 +32,7 @@ func (s *cacheShard) get(key string, hashedKey uint64) ([]byte, error) {
if itemIndex == 0 { if itemIndex == 0 {
s.lock.RUnlock() s.lock.RUnlock()
s.miss() s.miss()
return nil, notFound(key) return nil, ErrEntryNotFound
} }
wrappedEntry, err := s.entries.Get(int(itemIndex)) wrappedEntry, err := s.entries.Get(int(itemIndex))
@ -47,11 +47,12 @@ func (s *cacheShard) get(key string, hashedKey uint64) ([]byte, error) {
} }
s.lock.RUnlock() s.lock.RUnlock()
s.collision() s.collision()
return nil, notFound(key) return nil, ErrEntryNotFound
} }
entry := readEntry(wrappedEntry)
s.lock.RUnlock() s.lock.RUnlock()
s.hit() s.hit()
return readEntry(wrappedEntry), nil return entry, nil
} }
func (s *cacheShard) set(key string, hashedKey uint64, entry []byte) error { func (s *cacheShard) set(key string, hashedKey uint64, entry []byte) error {
@ -77,7 +78,7 @@ func (s *cacheShard) set(key string, hashedKey uint64, entry []byte) error {
s.lock.Unlock() s.lock.Unlock()
return nil return nil
} }
if s.removeOldestEntry() != nil { if s.removeOldestEntry(NoSpace) != nil {
s.lock.Unlock() s.lock.Unlock()
return fmt.Errorf("entry is bigger than max shard size") return fmt.Errorf("entry is bigger than max shard size")
} }
@ -85,17 +86,17 @@ func (s *cacheShard) set(key string, hashedKey uint64, entry []byte) error {
} }
func (s *cacheShard) del(key string, hashedKey uint64) error { func (s *cacheShard) del(key string, hashedKey uint64) error {
// Optimistic pre-check using only readlock
s.lock.RLock() s.lock.RLock()
itemIndex := s.hashmap[hashedKey] itemIndex := s.hashmap[hashedKey]
if itemIndex == 0 { if itemIndex == 0 {
s.lock.RUnlock() s.lock.RUnlock()
s.delmiss() s.delmiss()
return notFound(key) return ErrEntryNotFound
} }
wrappedEntry, err := s.entries.Get(int(itemIndex)) if err := s.entries.CheckGet(int(itemIndex)); err != nil {
if err != nil {
s.lock.RUnlock() s.lock.RUnlock()
s.delmiss() s.delmiss()
return err return err
@ -104,8 +105,25 @@ func (s *cacheShard) del(key string, hashedKey uint64) error {
s.lock.Lock() s.lock.Lock()
{ {
// After obtaining the writelock, we need to read the same again,
// since the data delivered earlier may be stale now
itemIndex = s.hashmap[hashedKey]
if itemIndex == 0 {
s.lock.Unlock()
s.delmiss()
return ErrEntryNotFound
}
wrappedEntry, err := s.entries.Get(int(itemIndex))
if err != nil {
s.lock.Unlock()
s.delmiss()
return err
}
delete(s.hashmap, hashedKey) delete(s.hashmap, hashedKey)
s.onRemove(wrappedEntry) s.onRemove(wrappedEntry, Deleted)
resetKeyFromEntry(wrappedEntry) resetKeyFromEntry(wrappedEntry)
} }
s.lock.Unlock() s.lock.Unlock()
@ -114,10 +132,10 @@ func (s *cacheShard) del(key string, hashedKey uint64) error {
return nil return nil
} }
func (s *cacheShard) onEvict(oldestEntry []byte, currentTimestamp uint64, evict func() error) bool { func (s *cacheShard) onEvict(oldestEntry []byte, currentTimestamp uint64, evict func(reason RemoveReason) error) bool {
oldestTimestamp := readTimestampFromEntry(oldestEntry) oldestTimestamp := readTimestampFromEntry(oldestEntry)
if currentTimestamp-oldestTimestamp > s.lifeWindow { if currentTimestamp-oldestTimestamp > s.lifeWindow {
evict() evict(Expired)
return true return true
} }
return false return false
@ -136,17 +154,22 @@ func (s *cacheShard) cleanUp(currentTimestamp uint64) {
} }
func (s *cacheShard) getOldestEntry() ([]byte, error) { func (s *cacheShard) getOldestEntry() ([]byte, error) {
s.lock.RLock()
defer s.lock.RUnlock()
return s.entries.Peek() return s.entries.Peek()
} }
func (s *cacheShard) getEntry(index int) ([]byte, error) { func (s *cacheShard) getEntry(index int) ([]byte, error) {
return s.entries.Get(index) s.lock.RLock()
entry, err := s.entries.Get(index)
s.lock.RUnlock()
return entry, err
} }
func (s *cacheShard) copyKeys() (keys []uint32, next int) { func (s *cacheShard) copyKeys() (keys []uint32, next int) {
keys = make([]uint32, len(s.hashmap))
s.lock.RLock() s.lock.RLock()
keys = make([]uint32, len(s.hashmap))
for _, index := range s.hashmap { for _, index := range s.hashmap {
keys[next] = index keys[next] = index
@ -157,12 +180,12 @@ func (s *cacheShard) copyKeys() (keys []uint32, next int) {
return keys, next return keys, next
} }
func (s *cacheShard) removeOldestEntry() error { func (s *cacheShard) removeOldestEntry(reason RemoveReason) error {
oldest, err := s.entries.Pop() oldest, err := s.entries.Pop()
if err == nil { if err == nil {
hash := readHashFromEntry(oldest) hash := readHashFromEntry(oldest)
delete(s.hashmap, hash) delete(s.hashmap, hash)
s.onRemove(oldest) s.onRemove(oldest, reason)
return nil return nil
} }
return err return err
@ -183,6 +206,13 @@ func (s *cacheShard) len() int {
return res return res
} }
func (s *cacheShard) capacity() int {
s.lock.RLock()
res := s.entries.Capacity()
s.lock.RUnlock()
return res
}
func (s *cacheShard) getStats() Stats { func (s *cacheShard) getStats() Stats {
var stats = Stats{ var stats = Stats{
Hits: atomic.LoadInt64(&s.stats.Hits), Hits: atomic.LoadInt64(&s.stats.Hits),

View File

@ -85,6 +85,11 @@ func (sig *Signature) IsEqual(otherSig *Signature) bool {
sig.S.Cmp(otherSig.S) == 0 sig.S.Cmp(otherSig.S) == 0
} }
// MinSigLen is the minimum length of a DER encoded signature and is when both R
// and S are 1 byte each.
// 0x30 + <1-byte> + 0x02 + 0x01 + <byte> + 0x2 + 0x01 + <byte>
const MinSigLen = 8
func parseSig(sigStr []byte, curve elliptic.Curve, der bool) (*Signature, error) { func parseSig(sigStr []byte, curve elliptic.Curve, der bool) (*Signature, error) {
// Originally this code used encoding/asn1 in order to parse the // Originally this code used encoding/asn1 in order to parse the
// signature, but a number of problems were found with this approach. // signature, but a number of problems were found with this approach.
@ -98,9 +103,7 @@ func parseSig(sigStr []byte, curve elliptic.Curve, der bool) (*Signature, error)
signature := &Signature{} signature := &Signature{}
// minimal message is when both numbers are 1 bytes. adding up to: if len(sigStr) < MinSigLen {
// 0x30 + len + 0x02 + 0x01 + <byte> + 0x2 + 0x01 + <byte>
if len(sigStr) < 8 {
return nil, errors.New("malformed signature: too short") return nil, errors.New("malformed signature: too short")
} }
// 0x30 // 0x30
@ -112,7 +115,10 @@ func parseSig(sigStr []byte, curve elliptic.Curve, der bool) (*Signature, error)
// length of remaining message // length of remaining message
siglen := sigStr[index] siglen := sigStr[index]
index++ index++
if int(siglen+2) > len(sigStr) {
// siglen should be less than the entire message and greater than
// the minimal message size.
if int(siglen+2) > len(sigStr) || int(siglen+2) < MinSigLen {
return nil, errors.New("malformed signature: bad length") return nil, errors.New("malformed signature: bad length")
} }
// trim the slice we're working on so we only look at what matters. // trim the slice we're working on so we only look at what matters.
@ -421,9 +427,7 @@ func signRFC6979(privateKey *PrivateKey, hash []byte) (*Signature, error) {
k := nonceRFC6979(privkey.D, hash) k := nonceRFC6979(privkey.D, hash)
inv := new(big.Int).ModInverse(k, N) inv := new(big.Int).ModInverse(k, N)
r, _ := privkey.Curve.ScalarBaseMult(k.Bytes()) r, _ := privkey.Curve.ScalarBaseMult(k.Bytes())
if r.Cmp(N) == 1 { r.Mod(r, N)
r.Sub(r, N)
}
if r.Sign() == 0 { if r.Sign() == 0 {
return nil, errors.New("calculated R is zero") return nil, errors.New("calculated R is zero")

1
vendor/github.com/golang/snappy/go.mod generated vendored Normal file
View File

@ -0,0 +1 @@
module github.com/golang/snappy

1
vendor/github.com/google/uuid/go.mod generated vendored Normal file
View File

@ -0,0 +1 @@
module github.com/google/uuid

View File

@ -48,6 +48,7 @@ func setNodeInterface(name string) bool {
// does not specify a specific interface generate a random Node ID // does not specify a specific interface generate a random Node ID
// (section 4.1.6) // (section 4.1.6)
if name == "" { if name == "" {
ifname = "random"
randomBits(nodeID[:]) randomBits(nodeID[:])
return true return true
} }

View File

@ -1,4 +1,4 @@
// Copyright 2016 Google Inc. All rights reserved. // Copyright 2018 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
@ -35,20 +35,43 @@ const (
var rander = rand.Reader // random function var rander = rand.Reader // random function
// Parse decodes s into a UUID or returns an error. Both the UUID form of // Parse decodes s into a UUID or returns an error. Both the standard UUID
// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and // forms of xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx are decoded. // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx are decoded as well as the
// Microsoft encoding {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} and the raw hex
// encoding: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.
func Parse(s string) (UUID, error) { func Parse(s string) (UUID, error) {
var uuid UUID var uuid UUID
if len(s) != 36 { switch len(s) {
if len(s) != 36+9 { // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
return uuid, fmt.Errorf("invalid UUID length: %d", len(s)) case 36:
}
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
case 36 + 9:
if strings.ToLower(s[:9]) != "urn:uuid:" { if strings.ToLower(s[:9]) != "urn:uuid:" {
return uuid, fmt.Errorf("invalid urn prefix: %q", s[:9]) return uuid, fmt.Errorf("invalid urn prefix: %q", s[:9])
} }
s = s[9:] s = s[9:]
// {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
case 36 + 2:
s = s[1:]
// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
case 32:
var ok bool
for i := range uuid {
uuid[i], ok = xtob(s[i*2], s[i*2+1])
if !ok {
return uuid, errors.New("invalid UUID format")
}
}
return uuid, nil
default:
return uuid, fmt.Errorf("invalid UUID length: %d", len(s))
} }
// s is now at least 36 bytes long
// it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' { if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' {
return uuid, errors.New("invalid UUID format") return uuid, errors.New("invalid UUID format")
} }
@ -70,15 +93,29 @@ func Parse(s string) (UUID, error) {
// ParseBytes is like Parse, except it parses a byte slice instead of a string. // ParseBytes is like Parse, except it parses a byte slice instead of a string.
func ParseBytes(b []byte) (UUID, error) { func ParseBytes(b []byte) (UUID, error) {
var uuid UUID var uuid UUID
if len(b) != 36 { switch len(b) {
if len(b) != 36+9 { case 36: // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
return uuid, fmt.Errorf("invalid UUID length: %d", len(b)) case 36 + 9: // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
}
if !bytes.Equal(bytes.ToLower(b[:9]), []byte("urn:uuid:")) { if !bytes.Equal(bytes.ToLower(b[:9]), []byte("urn:uuid:")) {
return uuid, fmt.Errorf("invalid urn prefix: %q", b[:9]) return uuid, fmt.Errorf("invalid urn prefix: %q", b[:9])
} }
b = b[9:] b = b[9:]
case 36 + 2: // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
b = b[1:]
case 32: // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
var ok bool
for i := 0; i < 32; i += 2 {
uuid[i/2], ok = xtob(b[i], b[i+1])
if !ok {
return uuid, errors.New("invalid UUID format")
}
}
return uuid, nil
default:
return uuid, fmt.Errorf("invalid UUID length: %d", len(b))
} }
// s is now at least 36 bytes long
// it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
if b[8] != '-' || b[13] != '-' || b[18] != '-' || b[23] != '-' { if b[8] != '-' || b[13] != '-' || b[18] != '-' || b[23] != '-' {
return uuid, errors.New("invalid UUID format") return uuid, errors.New("invalid UUID format")
} }
@ -97,6 +134,16 @@ func ParseBytes(b []byte) (UUID, error) {
return uuid, nil return uuid, nil
} }
// MustParse is like Parse but panics if the string cannot be parsed.
// It simplifies safe initialization of global variables holding compiled UUIDs.
func MustParse(s string) UUID {
uuid, err := Parse(s)
if err != nil {
panic(`uuid: Parse(` + s + `): ` + err.Error())
}
return uuid
}
// FromBytes creates a new UUID from a byte slice. Returns an error if the slice // FromBytes creates a new UUID from a byte slice. Returns an error if the slice
// does not have a length of 16. The bytes are copied from the slice. // does not have a length of 16. The bytes are copied from the slice.
func FromBytes(b []byte) (uuid UUID, err error) { func FromBytes(b []byte) (uuid UUID, err error) {
@ -130,7 +177,7 @@ func (uuid UUID) URN() string {
} }
func encodeHex(dst []byte, uuid UUID) { func encodeHex(dst []byte, uuid UUID) {
hex.Encode(dst[:], uuid[:4]) hex.Encode(dst, uuid[:4])
dst[8] = '-' dst[8] = '-'
hex.Encode(dst[9:13], uuid[4:6]) hex.Encode(dst[9:13], uuid[4:6])
dst[13] = '-' dst[13] = '-'

1
vendor/github.com/hashicorp/golang-lru/go.mod generated vendored Normal file
View File

@ -0,0 +1 @@
module github.com/hashicorp/golang-lru

View File

@ -40,31 +40,35 @@ func (c *Cache) Purge() {
// Add adds a value to the cache. Returns true if an eviction occurred. // Add adds a value to the cache. Returns true if an eviction occurred.
func (c *Cache) Add(key, value interface{}) (evicted bool) { func (c *Cache) Add(key, value interface{}) (evicted bool) {
c.lock.Lock() c.lock.Lock()
defer c.lock.Unlock() evicted = c.lru.Add(key, value)
return c.lru.Add(key, value) c.lock.Unlock()
return evicted
} }
// Get looks up a key's value from the cache. // Get looks up a key's value from the cache.
func (c *Cache) Get(key interface{}) (value interface{}, ok bool) { func (c *Cache) Get(key interface{}) (value interface{}, ok bool) {
c.lock.Lock() c.lock.Lock()
defer c.lock.Unlock() value, ok = c.lru.Get(key)
return c.lru.Get(key) c.lock.Unlock()
return value, ok
} }
// Contains checks if a key is in the cache, without updating the // Contains checks if a key is in the cache, without updating the
// recent-ness or deleting it for being stale. // recent-ness or deleting it for being stale.
func (c *Cache) Contains(key interface{}) bool { func (c *Cache) Contains(key interface{}) bool {
c.lock.RLock() c.lock.RLock()
defer c.lock.RUnlock() containKey := c.lru.Contains(key)
return c.lru.Contains(key) c.lock.RUnlock()
return containKey
} }
// Peek returns the key value (or undefined if not found) without updating // Peek returns the key value (or undefined if not found) without updating
// the "recently used"-ness of the key. // the "recently used"-ness of the key.
func (c *Cache) Peek(key interface{}) (value interface{}, ok bool) { func (c *Cache) Peek(key interface{}) (value interface{}, ok bool) {
c.lock.RLock() c.lock.RLock()
defer c.lock.RUnlock() value, ok = c.lru.Peek(key)
return c.lru.Peek(key) c.lock.RUnlock()
return value, ok
} }
// ContainsOrAdd checks if a key is in the cache without updating the // ContainsOrAdd checks if a key is in the cache without updating the
@ -98,13 +102,15 @@ func (c *Cache) RemoveOldest() {
// Keys returns a slice of the keys in the cache, from oldest to newest. // Keys returns a slice of the keys in the cache, from oldest to newest.
func (c *Cache) Keys() []interface{} { func (c *Cache) Keys() []interface{} {
c.lock.RLock() c.lock.RLock()
defer c.lock.RUnlock() keys := c.lru.Keys()
return c.lru.Keys() c.lock.RUnlock()
return keys
} }
// Len returns the number of items in the cache. // Len returns the number of items in the cache.
func (c *Cache) Len() int { func (c *Cache) Len() int {
c.lock.RLock() c.lock.RLock()
defer c.lock.RUnlock() length := c.lru.Len()
return c.lru.Len() c.lock.RUnlock()
return length
} }

View File

@ -1,37 +1,36 @@
package simplelru package simplelru
// LRUCache is the interface for simple LRU cache. // LRUCache is the interface for simple LRU cache.
type LRUCache interface { type LRUCache interface {
// Adds a value to the cache, returns true if an eviction occurred and // Adds a value to the cache, returns true if an eviction occurred and
// updates the "recently used"-ness of the key. // updates the "recently used"-ness of the key.
Add(key, value interface{}) bool Add(key, value interface{}) bool
// Returns key's value from the cache and // Returns key's value from the cache and
// updates the "recently used"-ness of the key. #value, isFound // updates the "recently used"-ness of the key. #value, isFound
Get(key interface{}) (value interface{}, ok bool) Get(key interface{}) (value interface{}, ok bool)
// Check if a key exsists in cache without updating the recent-ness. // Check if a key exsists in cache without updating the recent-ness.
Contains(key interface{}) (ok bool) Contains(key interface{}) (ok bool)
// Returns key's value without updating the "recently used"-ness of the key. // Returns key's value without updating the "recently used"-ness of the key.
Peek(key interface{}) (value interface{}, ok bool) Peek(key interface{}) (value interface{}, ok bool)
// Removes a key from the cache. // Removes a key from the cache.
Remove(key interface{}) bool Remove(key interface{}) bool
// Removes the oldest entry from cache. // Removes the oldest entry from cache.
RemoveOldest() (interface{}, interface{}, bool) RemoveOldest() (interface{}, interface{}, bool)
// Returns the oldest entry from the cache. #key, value, isFound // Returns the oldest entry from the cache. #key, value, isFound
GetOldest() (interface{}, interface{}, bool) GetOldest() (interface{}, interface{}, bool)
// Returns a slice of the keys in the cache, from oldest to newest. // Returns a slice of the keys in the cache, from oldest to newest.
Keys() []interface{} Keys() []interface{}
// Returns the number of items in the cache. // Returns the number of items in the cache.
Len() int Len() int
// Clear all cache entries // Clear all cache entries
Purge() Purge()
} }

View File

@ -1 +1,2 @@
/gotasks/specs *.zip
*.sublime-workspace

View File

@ -25,15 +25,19 @@ Core components:
Regenerating dcps generated source code: Regenerating dcps generated source code:
---------------------------------------- ----------------------------------------
1. Install gotasks: `go get -u github.com/jingweno/gotask` 1. Build code generator:
2. Change to the gotasks directory: `cd gotasks`
3. Run specgen task: `gotask specgen` `go get -u github.com/huin/goupnp/cmd/goupnpdcpgen`
2. Regenerate the code:
`go generate ./...`
Supporting additional UPnP devices and services: Supporting additional UPnP devices and services:
------------------------------------------------ ------------------------------------------------
Supporting additional services is, in the trivial case, simply a matter of Supporting additional services is, in the trivial case, simply a matter of
adding the service to the `dcpMetadata` whitelist in `gotasks/specgen_task.go`, adding the service to the `dcpMetadata` whitelist in `cmd/goupnpdcpgen/metadata.go`,
regenerating the source code (see above), and committing that source code. regenerating the source code (see above), and committing that source code.
However, it would be helpful if anyone needing such a service could test the However, it would be helpful if anyone needing such a service could test the

View File

@ -0,0 +1,2 @@
//go:generate goupnpdcpgen -dcp_name internetgateway1
package internetgateway1

View File

@ -0,0 +1,2 @@
//go:generate goupnpdcpgen -dcp_name internetgateway2
package internetgateway2

7
vendor/github.com/huin/goupnp/go.mod generated vendored Normal file
View File

@ -0,0 +1,7 @@
module github.com/huin/goupnp
require (
github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150
golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1
golang.org/x/text v0.3.0 // indirect
)

6
vendor/github.com/huin/goupnp/go.sum generated vendored Normal file
View File

@ -0,0 +1,6 @@
github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150 h1:vlNjIqmUZ9CMAWsbURYl3a6wZbw7q5RHVvlXTNS/Bs8=
github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o=
golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1 h1:Y/KGZSOdz/2r0WJ9Mkmz6NJBusp0kiNx1Cn82lzJQ6w=
golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=

8
vendor/github.com/huin/goupnp/goupnp.sublime-project generated vendored Normal file
View File

@ -0,0 +1,8 @@
{
"folders":
[
{
"path": "."
}
]
}

View File

@ -18,9 +18,9 @@ before_install:
# go versions to test # go versions to test
go: go:
- "1.8"
- "1.9"
- "1.10.x" - "1.10.x"
- "1.11.x"
- "1.12.x"
# run tests w/ coverage # run tests w/ coverage
script: script:

View File

@ -15,11 +15,13 @@ Major additional concepts are:
* `Get` and `Select` to go quickly from query to struct/slice * `Get` and `Select` to go quickly from query to struct/slice
In addition to the [godoc API documentation](http://godoc.org/github.com/jmoiron/sqlx), In addition to the [godoc API documentation](http://godoc.org/github.com/jmoiron/sqlx),
there is also some [standard documentation](http://jmoiron.github.io/sqlx/) that there is also some [user documentation](http://jmoiron.github.io/sqlx/) that
explains how to use `database/sql` along with sqlx. explains how to use `database/sql` along with sqlx.
## Recent Changes ## Recent Changes
* The [introduction](https://github.com/jmoiron/sqlx/pull/387) of `sql.ColumnType` sets the required minimum Go version to 1.8.
* sqlx/types.JsonText has been renamed to JSONText to follow Go naming conventions. * sqlx/types.JsonText has been renamed to JSONText to follow Go naming conventions.
This breaks backwards compatibility, but it's in a way that is trivially fixable This breaks backwards compatibility, but it's in a way that is trivially fixable

View File

@ -2,6 +2,7 @@ package sqlx
import ( import (
"bytes" "bytes"
"database/sql/driver"
"errors" "errors"
"reflect" "reflect"
"strconv" "strconv"
@ -16,12 +17,13 @@ const (
QUESTION QUESTION
DOLLAR DOLLAR
NAMED NAMED
AT
) )
// BindType returns the bindtype for a given database given a drivername. // BindType returns the bindtype for a given database given a drivername.
func BindType(driverName string) int { func BindType(driverName string) int {
switch driverName { switch driverName {
case "postgres", "pgx", "pq-timeouts", "cloudsqlpostgres": case "postgres", "pgx", "pq-timeouts", "cloudsqlpostgres", "ql":
return DOLLAR return DOLLAR
case "mysql": case "mysql":
return QUESTION return QUESTION
@ -29,6 +31,8 @@ func BindType(driverName string) int {
return QUESTION return QUESTION
case "oci8", "ora", "goracle": case "oci8", "ora", "goracle":
return NAMED return NAMED
case "sqlserver":
return AT
} }
return UNKNOWN return UNKNOWN
} }
@ -56,6 +60,8 @@ func Rebind(bindType int, query string) string {
rqb = append(rqb, '$') rqb = append(rqb, '$')
case NAMED: case NAMED:
rqb = append(rqb, ':', 'a', 'r', 'g') rqb = append(rqb, ':', 'a', 'r', 'g')
case AT:
rqb = append(rqb, '@', 'p')
} }
j++ j++
@ -110,6 +116,9 @@ func In(query string, args ...interface{}) (string, []interface{}, error) {
meta := make([]argMeta, len(args)) meta := make([]argMeta, len(args))
for i, arg := range args { for i, arg := range args {
if a, ok := arg.(driver.Valuer); ok {
arg, _ = a.Value()
}
v := reflect.ValueOf(arg) v := reflect.ValueOf(arg)
t := reflectx.Deref(v.Type()) t := reflectx.Deref(v.Type())
@ -137,7 +146,7 @@ func In(query string, args ...interface{}) (string, []interface{}, error) {
} }
newArgs := make([]interface{}, 0, flatArgsCount) newArgs := make([]interface{}, 0, flatArgsCount)
buf := bytes.NewBuffer(make([]byte, 0, len(query)+len(", ?")*flatArgsCount)) buf := make([]byte, 0, len(query)+len(", ?")*flatArgsCount)
var arg, offset int var arg, offset int
@ -163,10 +172,10 @@ func In(query string, args ...interface{}) (string, []interface{}, error) {
} }
// write everything up to and including our ? character // write everything up to and including our ? character
buf.WriteString(query[:offset+i+1]) buf = append(buf, query[:offset+i+1]...)
for si := 1; si < argMeta.length; si++ { for si := 1; si < argMeta.length; si++ {
buf.WriteString(", ?") buf = append(buf, ", ?"...)
} }
newArgs = appendReflectSlice(newArgs, argMeta.v, argMeta.length) newArgs = appendReflectSlice(newArgs, argMeta.v, argMeta.length)
@ -177,13 +186,13 @@ func In(query string, args ...interface{}) (string, []interface{}, error) {
offset = 0 offset = 0
} }
buf.WriteString(query) buf = append(buf, query...)
if arg < len(meta) { if arg < len(meta) {
return "", nil, errors.New("number of bindVars less than number arguments") return "", nil, errors.New("number of bindVars less than number arguments")
} }
return buf.String(), newArgs, nil return string(buf), newArgs, nil
} }
func appendReflectSlice(args []interface{}, v reflect.Value, vlen int) []interface{} { func appendReflectSlice(args []interface{}, v reflect.Value, vlen int) []interface{} {

7
vendor/github.com/jmoiron/sqlx/go.mod generated vendored Normal file
View File

@ -0,0 +1,7 @@
module github.com/jmoiron/sqlx
require (
github.com/go-sql-driver/mysql v1.4.0
github.com/lib/pq v1.0.0
github.com/mattn/go-sqlite3 v1.9.0
)

6
vendor/github.com/jmoiron/sqlx/go.sum generated vendored Normal file
View File

@ -0,0 +1,6 @@
github.com/go-sql-driver/mysql v1.4.0 h1:7LxgVwFb2hIQtMm87NdgAVfXjnt4OePseqT1tKx+opk=
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/mattn/go-sqlite3 v1.9.0 h1:pDRiWfl+++eC2FEFRy6jXmQlvp4Yh3z1MJKg4UeYM/4=
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=

View File

@ -12,10 +12,12 @@ package sqlx
// * bindArgs, bindMapArgs, bindAnyArgs - given a list of names, return an arglist // * bindArgs, bindMapArgs, bindAnyArgs - given a list of names, return an arglist
// //
import ( import (
"bytes"
"database/sql" "database/sql"
"errors" "errors"
"fmt" "fmt"
"reflect" "reflect"
"regexp"
"strconv" "strconv"
"unicode" "unicode"
@ -208,6 +210,56 @@ func bindStruct(bindType int, query string, arg interface{}, m *reflectx.Mapper)
return bound, arglist, nil return bound, arglist, nil
} }
var valueBracketReg = regexp.MustCompile(`\([^(]*\?+[^)]*\)`)
func fixBound(bound string, loop int) string {
loc := valueBracketReg.FindStringIndex(bound)
if len(loc) != 2 {
return bound
}
var buffer bytes.Buffer
buffer.WriteString(bound[0:loc[1]])
for i := 0; i < loop-1; i++ {
buffer.WriteString(",")
buffer.WriteString(bound[loc[0]:loc[1]])
}
buffer.WriteString(bound[loc[1]:])
return buffer.String()
}
// bindArray binds a named parameter query with fields from an array or slice of
// structs argument.
func bindArray(bindType int, query string, arg interface{}, m *reflectx.Mapper) (string, []interface{}, error) {
// do the initial binding with QUESTION; if bindType is not question,
// we can rebind it at the end.
bound, names, err := compileNamedQuery([]byte(query), QUESTION)
if err != nil {
return "", []interface{}{}, err
}
arrayValue := reflect.ValueOf(arg)
arrayLen := arrayValue.Len()
if arrayLen == 0 {
return "", []interface{}{}, fmt.Errorf("length of array is 0: %#v", arg)
}
var arglist []interface{}
for i := 0; i < arrayLen; i++ {
elemArglist, err := bindArgs(names, arrayValue.Index(i).Interface(), m)
if err != nil {
return "", []interface{}{}, err
}
arglist = append(arglist, elemArglist...)
}
if arrayLen > 1 {
bound = fixBound(bound, arrayLen)
}
// adjust binding type if we weren't on question
if bindType != QUESTION {
bound = Rebind(bindType, bound)
}
return bound, arglist, nil
}
// bindMap binds a named parameter query with a map of arguments. // bindMap binds a named parameter query with a map of arguments.
func bindMap(bindType int, query string, args map[string]interface{}) (string, []interface{}, error) { func bindMap(bindType int, query string, args map[string]interface{}) (string, []interface{}, error) {
bound, names, err := compileNamedQuery([]byte(query), bindType) bound, names, err := compileNamedQuery([]byte(query), bindType)
@ -259,6 +311,10 @@ func compileNamedQuery(qs []byte, bindType int) (query string, names []string, e
} }
inName = true inName = true
name = []byte{} name = []byte{}
} else if inName && i > 0 && b == '=' && len(name) == 0 {
rebound = append(rebound, ':', '=')
inName = false
continue
// if we're in a name, and this is an allowed character, continue // if we're in a name, and this is an allowed character, continue
} else if inName && (unicode.IsOneOf(allowedBindRunes, rune(b)) || b == '_' || b == '.') && i != last { } else if inName && (unicode.IsOneOf(allowedBindRunes, rune(b)) || b == '_' || b == '.') && i != last {
// append the byte to the name if we are in a name and not on the last byte // append the byte to the name if we are in a name and not on the last byte
@ -287,6 +343,12 @@ func compileNamedQuery(qs []byte, bindType int) (query string, names []string, e
rebound = append(rebound, byte(b)) rebound = append(rebound, byte(b))
} }
currentVar++ currentVar++
case AT:
rebound = append(rebound, '@', 'p')
for _, b := range strconv.Itoa(currentVar) {
rebound = append(rebound, byte(b))
}
currentVar++
} }
// add this byte to string unless it was not part of the name // add this byte to string unless it was not part of the name
if i != last { if i != last {
@ -320,7 +382,12 @@ func bindNamedMapper(bindType int, query string, arg interface{}, m *reflectx.Ma
if maparg, ok := arg.(map[string]interface{}); ok { if maparg, ok := arg.(map[string]interface{}); ok {
return bindMap(bindType, query, maparg) return bindMap(bindType, query, maparg)
} }
return bindStruct(bindType, query, arg, m) switch reflect.TypeOf(arg).Kind() {
case reflect.Array, reflect.Slice:
return bindArray(bindType, query, arg, m)
default:
return bindStruct(bindType, query, arg, m)
}
} }
// NamedQuery binds a named query and then runs Query on the result using the // NamedQuery binds a named query and then runs Query on the result using the
@ -336,7 +403,7 @@ func NamedQuery(e Ext, query string, arg interface{}) (*Rows, error) {
// NamedExec uses BindStruct to get a query executable by the driver and // NamedExec uses BindStruct to get a query executable by the driver and
// then runs Exec on the result. Returns an error from the binding // then runs Exec on the result. Returns an error from the binding
// or the query excution itself. // or the query execution itself.
func NamedExec(e Ext, query string, arg interface{}) (sql.Result, error) { func NamedExec(e Ext, query string, arg interface{}) (sql.Result, error) {
q, args, err := bindNamedMapper(BindType(e.DriverName()), query, arg, mapperFor(e)) q, args, err := bindNamedMapper(BindType(e.DriverName()), query, arg, mapperFor(e))
if err != nil { if err != nil {

View File

@ -122,7 +122,7 @@ func NamedQueryContext(ctx context.Context, e ExtContext, query string, arg inte
// NamedExecContext uses BindStruct to get a query executable by the driver and // NamedExecContext uses BindStruct to get a query executable by the driver and
// then runs Exec on the result. Returns an error from the binding // then runs Exec on the result. Returns an error from the binding
// or the query excution itself. // or the query execution itself.
func NamedExecContext(ctx context.Context, e ExtContext, query string, arg interface{}) (sql.Result, error) { func NamedExecContext(ctx context.Context, e ExtContext, query string, arg interface{}) (sql.Result, error) {
q, args, err := bindNamedMapper(BindType(e.DriverName()), query, arg, mapperFor(e)) q, args, err := bindNamedMapper(BindType(e.DriverName()), query, arg, mapperFor(e))
if err != nil { if err != nil {

View File

@ -269,9 +269,7 @@ type typeQueue struct {
// A copying append that creates a new slice each time. // A copying append that creates a new slice each time.
func apnd(is []int, i int) []int { func apnd(is []int, i int) []int {
x := make([]int, len(is)+1) x := make([]int, len(is)+1)
for p, n := range is { copy(x, is)
x[p] = n
}
x[len(x)-1] = i x[len(x)-1] = i
return x return x
} }

View File

@ -149,15 +149,15 @@ func isUnsafe(i interface{}) bool {
} }
func mapperFor(i interface{}) *reflectx.Mapper { func mapperFor(i interface{}) *reflectx.Mapper {
switch i.(type) { switch i := i.(type) {
case DB: case DB:
return i.(DB).Mapper return i.Mapper
case *DB: case *DB:
return i.(*DB).Mapper return i.Mapper
case Tx: case Tx:
return i.(Tx).Mapper return i.Mapper
case *Tx: case *Tx:
return i.(*Tx).Mapper return i.Mapper
default: default:
return mapper() return mapper()
} }
@ -471,8 +471,6 @@ func (tx *Tx) Stmtx(stmt interface{}) *Stmt {
s = v.Stmt s = v.Stmt
case *Stmt: case *Stmt:
s = v.Stmt s = v.Stmt
case sql.Stmt:
s = &v
case *sql.Stmt: case *sql.Stmt:
s = v s = v
default: default:

View File

@ -217,8 +217,6 @@ func (tx *Tx) StmtxContext(ctx context.Context, stmt interface{}) *Stmt {
s = v.Stmt s = v.Stmt
case *Stmt: case *Stmt:
s = v.Stmt s = v.Stmt
case sql.Stmt:
s = &v
case *sql.Stmt: case *sql.Stmt:
s = v s = v
default: default:

View File

@ -26,6 +26,7 @@ The tool is sponsored by the [marvin + konsorten GmbH](http://www.konsorten.de).
We thank all the authors who provided code to this library: We thank all the authors who provided code to this library:
* Felix Kollmann * Felix Kollmann
* Nicolas Perraut
## License ## License

View File

@ -0,0 +1,11 @@
// +build linux darwin
package sequences
import (
"fmt"
)
func EnableVirtualTerminalProcessing(stream uintptr, enable bool) error {
return fmt.Errorf("windows only package")
}

13
vendor/github.com/lib/pq/.travis.sh generated vendored
View File

@ -70,17 +70,4 @@ postgresql_uninstall() {
sudo rm -rf /var/lib/postgresql sudo rm -rf /var/lib/postgresql
} }
megacheck_install() {
# Lock megacheck version at $MEGACHECK_VERSION to prevent spontaneous
# new error messages in old code.
go get -d honnef.co/go/tools/...
git -C $GOPATH/src/honnef.co/go/tools/ checkout $MEGACHECK_VERSION
go install honnef.co/go/tools/cmd/megacheck
megacheck --version
}
golint_install() {
go get github.com/golang/lint/golint
}
$1 $1

16
vendor/github.com/lib/pq/.travis.yml generated vendored
View File

@ -1,9 +1,8 @@
language: go language: go
go: go:
- 1.8.x - 1.11.x
- 1.9.x - 1.12.x
- 1.10.x
- master - master
sudo: true sudo: true
@ -14,16 +13,11 @@ env:
- PQGOSSLTESTS=1 - PQGOSSLTESTS=1
- PQSSLCERTTEST_PATH=$PWD/certs - PQSSLCERTTEST_PATH=$PWD/certs
- PGHOST=127.0.0.1 - PGHOST=127.0.0.1
- MEGACHECK_VERSION=2017.2.2
matrix: matrix:
- PGVERSION=10 - PGVERSION=10
- PGVERSION=9.6 - PGVERSION=9.6
- PGVERSION=9.5 - PGVERSION=9.5
- PGVERSION=9.4 - PGVERSION=9.4
- PGVERSION=9.3
- PGVERSION=9.2
- PGVERSION=9.1
- PGVERSION=9.0
before_install: before_install:
- ./.travis.sh postgresql_uninstall - ./.travis.sh postgresql_uninstall
@ -31,9 +25,9 @@ before_install:
- ./.travis.sh postgresql_install - ./.travis.sh postgresql_install
- ./.travis.sh postgresql_configure - ./.travis.sh postgresql_configure
- ./.travis.sh client_configure - ./.travis.sh client_configure
- ./.travis.sh megacheck_install
- ./.travis.sh golint_install
- go get golang.org/x/tools/cmd/goimports - go get golang.org/x/tools/cmd/goimports
- go get golang.org/x/lint/golint
- GO111MODULE=on go get honnef.co/go/tools/cmd/staticcheck@2019.2.1
before_script: before_script:
- createdb pqgotest - createdb pqgotest
@ -44,7 +38,7 @@ script:
- > - >
goimports -d -e $(find -name '*.go') | awk '{ print } END { exit NR == 0 ? 0 : 1 }' goimports -d -e $(find -name '*.go') | awk '{ print } END { exit NR == 0 ? 0 : 1 }'
- go vet ./... - go vet ./...
- megacheck -go 1.8 ./... - staticcheck -go 1.11 ./...
- golint ./... - golint ./...
- PQTEST_BINARY_PARAMETERS=no go test -race -v ./... - PQTEST_BINARY_PARAMETERS=no go test -race -v ./...
- PQTEST_BINARY_PARAMETERS=yes go test -race -v ./... - PQTEST_BINARY_PARAMETERS=yes go test -race -v ./...

2
vendor/github.com/lib/pq/README.md generated vendored
View File

@ -10,7 +10,7 @@
## Docs ## Docs
For detailed documentation and basic usage examples, please see the package For detailed documentation and basic usage examples, please see the package
documentation at <http://godoc.org/github.com/lib/pq>. documentation at <https://godoc.org/github.com/lib/pq>.
## Tests ## Tests

91
vendor/github.com/lib/pq/buf.go generated vendored Normal file
View File

@ -0,0 +1,91 @@
package pq
import (
"bytes"
"encoding/binary"
"github.com/lib/pq/oid"
)
type readBuf []byte
func (b *readBuf) int32() (n int) {
n = int(int32(binary.BigEndian.Uint32(*b)))
*b = (*b)[4:]
return
}
func (b *readBuf) oid() (n oid.Oid) {
n = oid.Oid(binary.BigEndian.Uint32(*b))
*b = (*b)[4:]
return
}
// N.B: this is actually an unsigned 16-bit integer, unlike int32
func (b *readBuf) int16() (n int) {
n = int(binary.BigEndian.Uint16(*b))
*b = (*b)[2:]
return
}
func (b *readBuf) string() string {
i := bytes.IndexByte(*b, 0)
if i < 0 {
errorf("invalid message format; expected string terminator")
}
s := (*b)[:i]
*b = (*b)[i+1:]
return string(s)
}
func (b *readBuf) next(n int) (v []byte) {
v = (*b)[:n]
*b = (*b)[n:]
return
}
func (b *readBuf) byte() byte {
return b.next(1)[0]
}
type writeBuf struct {
buf []byte
pos int
}
func (b *writeBuf) int32(n int) {
x := make([]byte, 4)
binary.BigEndian.PutUint32(x, uint32(n))
b.buf = append(b.buf, x...)
}
func (b *writeBuf) int16(n int) {
x := make([]byte, 2)
binary.BigEndian.PutUint16(x, uint16(n))
b.buf = append(b.buf, x...)
}
func (b *writeBuf) string(s string) {
b.buf = append(append(b.buf, s...), '\000')
}
func (b *writeBuf) byte(c byte) {
b.buf = append(b.buf, c)
}
func (b *writeBuf) bytes(v []byte) {
b.buf = append(b.buf, v...)
}
func (b *writeBuf) wrap() []byte {
p := b.buf[b.pos:]
binary.BigEndian.PutUint32(p, uint32(len(p)))
return b.buf
}
func (b *writeBuf) next(c byte) {
p := b.buf[b.pos:]
binary.BigEndian.PutUint32(p, uint32(len(p)))
b.pos = len(b.buf) + 1
b.buf = append(b.buf, c, 0, 0, 0, 0)
}

301
vendor/github.com/lib/pq/conn.go generated vendored
View File

@ -2,7 +2,9 @@ package pq
import ( import (
"bufio" "bufio"
"context"
"crypto/md5" "crypto/md5"
"crypto/sha256"
"database/sql" "database/sql"
"database/sql/driver" "database/sql/driver"
"encoding/binary" "encoding/binary"
@ -20,6 +22,7 @@ import (
"unicode" "unicode"
"github.com/lib/pq/oid" "github.com/lib/pq/oid"
"github.com/lib/pq/scram"
) )
// Common error types // Common error types
@ -89,13 +92,25 @@ type Dialer interface {
DialTimeout(network, address string, timeout time.Duration) (net.Conn, error) DialTimeout(network, address string, timeout time.Duration) (net.Conn, error)
} }
type defaultDialer struct{} // DialerContext is the context-aware dialer interface.
type DialerContext interface {
func (d defaultDialer) Dial(ntw, addr string) (net.Conn, error) { DialContext(ctx context.Context, network, address string) (net.Conn, error)
return net.Dial(ntw, addr)
} }
func (d defaultDialer) DialTimeout(ntw, addr string, timeout time.Duration) (net.Conn, error) {
return net.DialTimeout(ntw, addr, timeout) type defaultDialer struct {
d net.Dialer
}
func (d defaultDialer) Dial(network, address string) (net.Conn, error) {
return d.d.Dial(network, address)
}
func (d defaultDialer) DialTimeout(network, address string, timeout time.Duration) (net.Conn, error) {
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
return d.DialContext(ctx, network, address)
}
func (d defaultDialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
return d.d.DialContext(ctx, network, address)
} }
type conn struct { type conn struct {
@ -244,90 +259,35 @@ func (cn *conn) writeBuf(b byte) *writeBuf {
} }
} }
// Open opens a new connection to the database. name is a connection string. // Open opens a new connection to the database. dsn is a connection string.
// Most users should only use it through database/sql package from the standard // Most users should only use it through database/sql package from the standard
// library. // library.
func Open(name string) (_ driver.Conn, err error) { func Open(dsn string) (_ driver.Conn, err error) {
return DialOpen(defaultDialer{}, name) return DialOpen(defaultDialer{}, dsn)
} }
// DialOpen opens a new connection to the database using a dialer. // DialOpen opens a new connection to the database using a dialer.
func DialOpen(d Dialer, name string) (_ driver.Conn, err error) { func DialOpen(d Dialer, dsn string) (_ driver.Conn, err error) {
c, err := NewConnector(dsn)
if err != nil {
return nil, err
}
c.dialer = d
return c.open(context.Background())
}
func (c *Connector) open(ctx context.Context) (cn *conn, err error) {
// Handle any panics during connection initialization. Note that we // Handle any panics during connection initialization. Note that we
// specifically do *not* want to use errRecover(), as that would turn any // specifically do *not* want to use errRecover(), as that would turn any
// connection errors into ErrBadConns, hiding the real error message from // connection errors into ErrBadConns, hiding the real error message from
// the user. // the user.
defer errRecoverNoErrBadConn(&err) defer errRecoverNoErrBadConn(&err)
o := make(values) o := c.opts
// A number of defaults are applied here, in this order: cn = &conn{
//
// * Very low precedence defaults applied in every situation
// * Environment variables
// * Explicitly passed connection information
o["host"] = "localhost"
o["port"] = "5432"
// N.B.: Extra float digits should be set to 3, but that breaks
// Postgres 8.4 and older, where the max is 2.
o["extra_float_digits"] = "2"
for k, v := range parseEnviron(os.Environ()) {
o[k] = v
}
if strings.HasPrefix(name, "postgres://") || strings.HasPrefix(name, "postgresql://") {
name, err = ParseURL(name)
if err != nil {
return nil, err
}
}
if err := parseOpts(name, o); err != nil {
return nil, err
}
// Use the "fallback" application name if necessary
if fallback, ok := o["fallback_application_name"]; ok {
if _, ok := o["application_name"]; !ok {
o["application_name"] = fallback
}
}
// We can't work with any client_encoding other than UTF-8 currently.
// However, we have historically allowed the user to set it to UTF-8
// explicitly, and there's no reason to break such programs, so allow that.
// Note that the "options" setting could also set client_encoding, but
// parsing its value is not worth it. Instead, we always explicitly send
// client_encoding as a separate run-time parameter, which should override
// anything set in options.
if enc, ok := o["client_encoding"]; ok && !isUTF8(enc) {
return nil, errors.New("client_encoding must be absent or 'UTF8'")
}
o["client_encoding"] = "UTF8"
// DateStyle needs a similar treatment.
if datestyle, ok := o["datestyle"]; ok {
if datestyle != "ISO, MDY" {
panic(fmt.Sprintf("setting datestyle must be absent or %v; got %v",
"ISO, MDY", datestyle))
}
} else {
o["datestyle"] = "ISO, MDY"
}
// If a user is not provided by any other means, the last
// resort is to use the current operating system provided user
// name.
if _, ok := o["user"]; !ok {
u, err := userCurrent()
if err != nil {
return nil, err
}
o["user"] = u
}
cn := &conn{
opts: o, opts: o,
dialer: d, dialer: c.dialer,
} }
err = cn.handleDriverSettings(o) err = cn.handleDriverSettings(o)
if err != nil { if err != nil {
@ -335,13 +295,16 @@ func DialOpen(d Dialer, name string) (_ driver.Conn, err error) {
} }
cn.handlePgpass(o) cn.handlePgpass(o)
cn.c, err = dial(d, o) cn.c, err = dial(ctx, c.dialer, o)
if err != nil { if err != nil {
return nil, err return nil, err
} }
err = cn.ssl(o) err = cn.ssl(o)
if err != nil { if err != nil {
if cn.c != nil {
cn.c.Close()
}
return nil, err return nil, err
} }
@ -364,10 +327,10 @@ func DialOpen(d Dialer, name string) (_ driver.Conn, err error) {
return cn, err return cn, err
} }
func dial(d Dialer, o values) (net.Conn, error) { func dial(ctx context.Context, d Dialer, o values) (net.Conn, error) {
ntw, addr := network(o) network, address := network(o)
// SSL is not necessary or supported over UNIX domain sockets // SSL is not necessary or supported over UNIX domain sockets
if ntw == "unix" { if network == "unix" {
o["sslmode"] = "disable" o["sslmode"] = "disable"
} }
@ -378,19 +341,30 @@ func dial(d Dialer, o values) (net.Conn, error) {
return nil, fmt.Errorf("invalid value for parameter connect_timeout: %s", err) return nil, fmt.Errorf("invalid value for parameter connect_timeout: %s", err)
} }
duration := time.Duration(seconds) * time.Second duration := time.Duration(seconds) * time.Second
// connect_timeout should apply to the entire connection establishment // connect_timeout should apply to the entire connection establishment
// procedure, so we both use a timeout for the TCP connection // procedure, so we both use a timeout for the TCP connection
// establishment and set a deadline for doing the initial handshake. // establishment and set a deadline for doing the initial handshake.
// The deadline is then reset after startup() is done. // The deadline is then reset after startup() is done.
deadline := time.Now().Add(duration) deadline := time.Now().Add(duration)
conn, err := d.DialTimeout(ntw, addr, duration) var conn net.Conn
if dctx, ok := d.(DialerContext); ok {
ctx, cancel := context.WithTimeout(ctx, duration)
defer cancel()
conn, err = dctx.DialContext(ctx, network, address)
} else {
conn, err = d.DialTimeout(network, address, duration)
}
if err != nil { if err != nil {
return nil, err return nil, err
} }
err = conn.SetDeadline(deadline) err = conn.SetDeadline(deadline)
return conn, err return conn, err
} }
return d.Dial(ntw, addr) if dctx, ok := d.(DialerContext); ok {
return dctx.DialContext(ctx, network, address)
}
return d.Dial(network, address)
} }
func network(o values) (string, string) { func network(o values) (string, string) {
@ -576,7 +550,7 @@ func (cn *conn) Commit() (err error) {
// would get the same behaviour if you issued a COMMIT in a failed // would get the same behaviour if you issued a COMMIT in a failed
// transaction, so it's also the least surprising thing to do here. // transaction, so it's also the least surprising thing to do here.
if cn.txnStatus == txnStatusInFailedTransaction { if cn.txnStatus == txnStatusInFailedTransaction {
if err := cn.Rollback(); err != nil { if err := cn.rollback(); err != nil {
return err return err
} }
return ErrInFailedTransaction return ErrInFailedTransaction
@ -603,7 +577,10 @@ func (cn *conn) Rollback() (err error) {
return driver.ErrBadConn return driver.ErrBadConn
} }
defer cn.errRecover(&err) defer cn.errRecover(&err)
return cn.rollback()
}
func (cn *conn) rollback() (err error) {
cn.checkIsInTransaction(true) cn.checkIsInTransaction(true)
_, commandTag, err := cn.simpleExec("ROLLBACK") _, commandTag, err := cn.simpleExec("ROLLBACK")
if err != nil { if err != nil {
@ -704,7 +681,7 @@ func (cn *conn) simpleQuery(q string) (res *rows, err error) {
// res might be non-nil here if we received a previous // res might be non-nil here if we received a previous
// CommandComplete, but that's fine; just overwrite it // CommandComplete, but that's fine; just overwrite it
res = &rows{cn: cn} res = &rows{cn: cn}
res.colNames, res.colFmts, res.colTyps = parsePortalRowDescribe(r) res.rowsHeader = parsePortalRowDescribe(r)
// To work around a bug in QueryRow in Go 1.2 and earlier, wait // To work around a bug in QueryRow in Go 1.2 and earlier, wait
// until the first DataRow has been received. // until the first DataRow has been received.
@ -861,17 +838,15 @@ func (cn *conn) query(query string, args []driver.Value) (_ *rows, err error) {
cn.readParseResponse() cn.readParseResponse()
cn.readBindResponse() cn.readBindResponse()
rows := &rows{cn: cn} rows := &rows{cn: cn}
rows.colNames, rows.colFmts, rows.colTyps = cn.readPortalDescribeResponse() rows.rowsHeader = cn.readPortalDescribeResponse()
cn.postExecuteWorkaround() cn.postExecuteWorkaround()
return rows, nil return rows, nil
} }
st := cn.prepareTo(query, "") st := cn.prepareTo(query, "")
st.exec(args) st.exec(args)
return &rows{ return &rows{
cn: cn, cn: cn,
colNames: st.colNames, rowsHeader: st.rowsHeader,
colTyps: st.colTyps,
colFmts: st.colFmts,
}, nil }, nil
} }
@ -992,7 +967,6 @@ func (cn *conn) recv() (t byte, r *readBuf) {
if err != nil { if err != nil {
panic(err) panic(err)
} }
switch t { switch t {
case 'E': case 'E':
panic(parseError(r)) panic(parseError(r))
@ -1163,6 +1137,55 @@ func (cn *conn) auth(r *readBuf, o values) {
if r.int32() != 0 { if r.int32() != 0 {
errorf("unexpected authentication response: %q", t) errorf("unexpected authentication response: %q", t)
} }
case 10:
sc := scram.NewClient(sha256.New, o["user"], o["password"])
sc.Step(nil)
if sc.Err() != nil {
errorf("SCRAM-SHA-256 error: %s", sc.Err().Error())
}
scOut := sc.Out()
w := cn.writeBuf('p')
w.string("SCRAM-SHA-256")
w.int32(len(scOut))
w.bytes(scOut)
cn.send(w)
t, r := cn.recv()
if t != 'R' {
errorf("unexpected password response: %q", t)
}
if r.int32() != 11 {
errorf("unexpected authentication response: %q", t)
}
nextStep := r.next(len(*r))
sc.Step(nextStep)
if sc.Err() != nil {
errorf("SCRAM-SHA-256 error: %s", sc.Err().Error())
}
scOut = sc.Out()
w = cn.writeBuf('p')
w.bytes(scOut)
cn.send(w)
t, r = cn.recv()
if t != 'R' {
errorf("unexpected password response: %q", t)
}
if r.int32() != 12 {
errorf("unexpected authentication response: %q", t)
}
nextStep = r.next(len(*r))
sc.Step(nextStep)
if sc.Err() != nil {
errorf("SCRAM-SHA-256 error: %s", sc.Err().Error())
}
default: default:
errorf("unknown authentication response: %d", code) errorf("unknown authentication response: %d", code)
} }
@ -1180,12 +1203,10 @@ var colFmtDataAllBinary = []byte{0, 1, 0, 1}
var colFmtDataAllText = []byte{0, 0} var colFmtDataAllText = []byte{0, 0}
type stmt struct { type stmt struct {
cn *conn cn *conn
name string name string
colNames []string rowsHeader
colFmts []format
colFmtData []byte colFmtData []byte
colTyps []fieldDesc
paramTyps []oid.Oid paramTyps []oid.Oid
closed bool closed bool
} }
@ -1231,10 +1252,8 @@ func (st *stmt) Query(v []driver.Value) (r driver.Rows, err error) {
st.exec(v) st.exec(v)
return &rows{ return &rows{
cn: st.cn, cn: st.cn,
colNames: st.colNames, rowsHeader: st.rowsHeader,
colTyps: st.colTyps,
colFmts: st.colFmts,
}, nil }, nil
} }
@ -1344,16 +1363,22 @@ func (cn *conn) parseComplete(commandTag string) (driver.Result, string) {
return driver.RowsAffected(n), commandTag return driver.RowsAffected(n), commandTag
} }
type rows struct { type rowsHeader struct {
cn *conn
finish func()
colNames []string colNames []string
colTyps []fieldDesc colTyps []fieldDesc
colFmts []format colFmts []format
done bool }
rb readBuf
result driver.Result type rows struct {
tag string cn *conn
finish func()
rowsHeader
done bool
rb readBuf
result driver.Result
tag string
next *rowsHeader
} }
func (rs *rows) Close() error { func (rs *rows) Close() error {
@ -1440,7 +1465,8 @@ func (rs *rows) Next(dest []driver.Value) (err error) {
} }
return return
case 'T': case 'T':
rs.colNames, rs.colFmts, rs.colTyps = parsePortalRowDescribe(&rs.rb) next := parsePortalRowDescribe(&rs.rb)
rs.next = &next
return io.EOF return io.EOF
default: default:
errorf("unexpected message after execute: %q", t) errorf("unexpected message after execute: %q", t)
@ -1449,10 +1475,16 @@ func (rs *rows) Next(dest []driver.Value) (err error) {
} }
func (rs *rows) HasNextResultSet() bool { func (rs *rows) HasNextResultSet() bool {
return !rs.done hasNext := rs.next != nil && !rs.done
return hasNext
} }
func (rs *rows) NextResultSet() error { func (rs *rows) NextResultSet() error {
if rs.next == nil {
return io.EOF
}
rs.rowsHeader = *rs.next
rs.next = nil
return nil return nil
} }
@ -1475,6 +1507,39 @@ func QuoteIdentifier(name string) string {
return `"` + strings.Replace(name, `"`, `""`, -1) + `"` return `"` + strings.Replace(name, `"`, `""`, -1) + `"`
} }
// QuoteLiteral quotes a 'literal' (e.g. a parameter, often used to pass literal
// to DDL and other statements that do not accept parameters) to be used as part
// of an SQL statement. For example:
//
// exp_date := pq.QuoteLiteral("2023-01-05 15:00:00Z")
// err := db.Exec(fmt.Sprintf("CREATE ROLE my_user VALID UNTIL %s", exp_date))
//
// Any single quotes in name will be escaped. Any backslashes (i.e. "\") will be
// replaced by two backslashes (i.e. "\\") and the C-style escape identifier
// that PostgreSQL provides ('E') will be prepended to the string.
func QuoteLiteral(literal string) string {
// This follows the PostgreSQL internal algorithm for handling quoted literals
// from libpq, which can be found in the "PQEscapeStringInternal" function,
// which is found in the libpq/fe-exec.c source file:
// https://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/interfaces/libpq/fe-exec.c
//
// substitute any single-quotes (') with two single-quotes ('')
literal = strings.Replace(literal, `'`, `''`, -1)
// determine if the string has any backslashes (\) in it.
// if it does, replace any backslashes (\) with two backslashes (\\)
// then, we need to wrap the entire string with a PostgreSQL
// C-style escape. Per how "PQEscapeStringInternal" handles this case, we
// also add a space before the "E"
if strings.Contains(literal, `\`) {
literal = strings.Replace(literal, `\`, `\\`, -1)
literal = ` E'` + literal + `'`
} else {
// otherwise, we can just wrap the literal with a pair of single quotes
literal = `'` + literal + `'`
}
return literal
}
func md5s(s string) string { func md5s(s string) string {
h := md5.New() h := md5.New()
h.Write([]byte(s)) h.Write([]byte(s))
@ -1630,13 +1695,13 @@ func (cn *conn) readStatementDescribeResponse() (paramTyps []oid.Oid, colNames [
} }
} }
func (cn *conn) readPortalDescribeResponse() (colNames []string, colFmts []format, colTyps []fieldDesc) { func (cn *conn) readPortalDescribeResponse() rowsHeader {
t, r := cn.recv1() t, r := cn.recv1()
switch t { switch t {
case 'T': case 'T':
return parsePortalRowDescribe(r) return parsePortalRowDescribe(r)
case 'n': case 'n':
return nil, nil, nil return rowsHeader{}
case 'E': case 'E':
err := parseError(r) err := parseError(r)
cn.readReadyForQuery() cn.readReadyForQuery()
@ -1742,11 +1807,11 @@ func parseStatementRowDescribe(r *readBuf) (colNames []string, colTyps []fieldDe
return return
} }
func parsePortalRowDescribe(r *readBuf) (colNames []string, colFmts []format, colTyps []fieldDesc) { func parsePortalRowDescribe(r *readBuf) rowsHeader {
n := r.int16() n := r.int16()
colNames = make([]string, n) colNames := make([]string, n)
colFmts = make([]format, n) colFmts := make([]format, n)
colTyps = make([]fieldDesc, n) colTyps := make([]fieldDesc, n)
for i := range colNames { for i := range colNames {
colNames[i] = r.string() colNames[i] = r.string()
r.next(6) r.next(6)
@ -1755,7 +1820,11 @@ func parsePortalRowDescribe(r *readBuf) (colNames []string, colFmts []format, co
colTyps[i].Mod = r.int32() colTyps[i].Mod = r.int32()
colFmts[i] = format(r.int16()) colFmts[i] = format(r.int16())
} }
return return rowsHeader{
colNames: colNames,
colFmts: colFmts,
colTyps: colTyps,
}
} }
// parseEnviron tries to mimic some of libpq's environment handling // parseEnviron tries to mimic some of libpq's environment handling

View File

@ -1,5 +1,3 @@
// +build go1.8
package pq package pq
import ( import (
@ -9,6 +7,7 @@ import (
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
"time"
) )
// Implement the "QueryerContext" interface // Implement the "QueryerContext" interface
@ -76,13 +75,32 @@ func (cn *conn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx,
return tx, nil return tx, nil
} }
func (cn *conn) Ping(ctx context.Context) error {
if finish := cn.watchCancel(ctx); finish != nil {
defer finish()
}
rows, err := cn.simpleQuery("SELECT 'lib/pq ping test';")
if err != nil {
return driver.ErrBadConn // https://golang.org/pkg/database/sql/driver/#Pinger
}
rows.Close()
return nil
}
func (cn *conn) watchCancel(ctx context.Context) func() { func (cn *conn) watchCancel(ctx context.Context) func() {
if done := ctx.Done(); done != nil { if done := ctx.Done(); done != nil {
finished := make(chan struct{}) finished := make(chan struct{})
go func() { go func() {
select { select {
case <-done: case <-done:
_ = cn.cancel() // At this point the function level context is canceled,
// so it must not be used for the additional network
// request to cancel the query.
// Create a new context to pass into the dial.
ctxCancel, cancel := context.WithTimeout(context.Background(), time.Second*10)
defer cancel()
_ = cn.cancel(ctxCancel)
finished <- struct{}{} finished <- struct{}{}
case <-finished: case <-finished:
} }
@ -97,8 +115,8 @@ func (cn *conn) watchCancel(ctx context.Context) func() {
return nil return nil
} }
func (cn *conn) cancel() error { func (cn *conn) cancel(ctx context.Context) error {
c, err := dial(cn.dialer, cn.opts) c, err := dial(ctx, cn.dialer, cn.opts)
if err != nil { if err != nil {
return err return err
} }

View File

@ -1,10 +1,12 @@
// +build go1.10
package pq package pq
import ( import (
"context" "context"
"database/sql/driver" "database/sql/driver"
"errors"
"fmt"
"os"
"strings"
) )
// Connector represents a fixed configuration for the pq driver with a given // Connector represents a fixed configuration for the pq driver with a given
@ -14,30 +16,95 @@ import (
// //
// See https://golang.org/pkg/database/sql/driver/#Connector. // See https://golang.org/pkg/database/sql/driver/#Connector.
// See https://golang.org/pkg/database/sql/#OpenDB. // See https://golang.org/pkg/database/sql/#OpenDB.
type connector struct { type Connector struct {
name string opts values
dialer Dialer
} }
// Connect returns a connection to the database using the fixed configuration // Connect returns a connection to the database using the fixed configuration
// of this Connector. Context is not used. // of this Connector. Context is not used.
func (c *connector) Connect(_ context.Context) (driver.Conn, error) { func (c *Connector) Connect(ctx context.Context) (driver.Conn, error) {
return (&Driver{}).Open(c.name) return c.open(ctx)
} }
// Driver returnst the underlying driver of this Connector. // Driver returnst the underlying driver of this Connector.
func (c *connector) Driver() driver.Driver { func (c *Connector) Driver() driver.Driver {
return &Driver{} return &Driver{}
} }
var _ driver.Connector = &connector{}
// NewConnector returns a connector for the pq driver in a fixed configuration // NewConnector returns a connector for the pq driver in a fixed configuration
// with the given name. The returned connector can be used to create any number // with the given dsn. The returned connector can be used to create any number
// of equivalent Conn's. The returned connector is intended to be used with // of equivalent Conn's. The returned connector is intended to be used with
// database/sql.OpenDB. // database/sql.OpenDB.
// //
// See https://golang.org/pkg/database/sql/driver/#Connector. // See https://golang.org/pkg/database/sql/driver/#Connector.
// See https://golang.org/pkg/database/sql/#OpenDB. // See https://golang.org/pkg/database/sql/#OpenDB.
func NewConnector(name string) (driver.Connector, error) { func NewConnector(dsn string) (*Connector, error) {
return &connector{name: name}, nil var err error
o := make(values)
// A number of defaults are applied here, in this order:
//
// * Very low precedence defaults applied in every situation
// * Environment variables
// * Explicitly passed connection information
o["host"] = "localhost"
o["port"] = "5432"
// N.B.: Extra float digits should be set to 3, but that breaks
// Postgres 8.4 and older, where the max is 2.
o["extra_float_digits"] = "2"
for k, v := range parseEnviron(os.Environ()) {
o[k] = v
}
if strings.HasPrefix(dsn, "postgres://") || strings.HasPrefix(dsn, "postgresql://") {
dsn, err = ParseURL(dsn)
if err != nil {
return nil, err
}
}
if err := parseOpts(dsn, o); err != nil {
return nil, err
}
// Use the "fallback" application name if necessary
if fallback, ok := o["fallback_application_name"]; ok {
if _, ok := o["application_name"]; !ok {
o["application_name"] = fallback
}
}
// We can't work with any client_encoding other than UTF-8 currently.
// However, we have historically allowed the user to set it to UTF-8
// explicitly, and there's no reason to break such programs, so allow that.
// Note that the "options" setting could also set client_encoding, but
// parsing its value is not worth it. Instead, we always explicitly send
// client_encoding as a separate run-time parameter, which should override
// anything set in options.
if enc, ok := o["client_encoding"]; ok && !isUTF8(enc) {
return nil, errors.New("client_encoding must be absent or 'UTF8'")
}
o["client_encoding"] = "UTF8"
// DateStyle needs a similar treatment.
if datestyle, ok := o["datestyle"]; ok {
if datestyle != "ISO, MDY" {
return nil, fmt.Errorf("setting datestyle must be absent or %v; got %v", "ISO, MDY", datestyle)
}
} else {
o["datestyle"] = "ISO, MDY"
}
// If a user is not provided by any other means, the last
// resort is to use the current operating system provided user
// name.
if _, ok := o["user"]; !ok {
u, err := userCurrent()
if err != nil {
return nil, err
}
o["user"] = u
}
return &Connector{opts: o, dialer: defaultDialer{}}, nil
} }

2
vendor/github.com/lib/pq/doc.go generated vendored
View File

@ -239,7 +239,7 @@ for more information). Note that the channel name will be truncated to 63
bytes by the PostgreSQL server. bytes by the PostgreSQL server.
You can find a complete, working example of Listener usage at You can find a complete, working example of Listener usage at
http://godoc.org/github.com/lib/pq/example/listen. https://godoc.org/github.com/lib/pq/example/listen.
*/ */
package pq package pq

9
vendor/github.com/lib/pq/encode.go generated vendored
View File

@ -117,11 +117,10 @@ func textDecode(parameterStatus *parameterStatus, s []byte, typ oid.Oid) interfa
} }
return i return i
case oid.T_float4, oid.T_float8: case oid.T_float4, oid.T_float8:
bits := 64 // We always use 64 bit parsing, regardless of whether the input text is for
if typ == oid.T_float4 { // a float4 or float8, because clients expect float64s for all float datatypes
bits = 32 // and returning a 32-bit parsed float64 produces lossy results.
} f, err := strconv.ParseFloat(string(s), 64)
f, err := strconv.ParseFloat(string(s), bits)
if err != nil { if err != nil {
errorf("%s", err) errorf("%s", err)
} }

515
vendor/github.com/lib/pq/error.go generated vendored Normal file
View File

@ -0,0 +1,515 @@
package pq
import (
"database/sql/driver"
"fmt"
"io"
"net"
"runtime"
)
// Error severities
const (
Efatal = "FATAL"
Epanic = "PANIC"
Ewarning = "WARNING"
Enotice = "NOTICE"
Edebug = "DEBUG"
Einfo = "INFO"
Elog = "LOG"
)
// Error represents an error communicating with the server.
//
// See http://www.postgresql.org/docs/current/static/protocol-error-fields.html for details of the fields
type Error struct {
Severity string
Code ErrorCode
Message string
Detail string
Hint string
Position string
InternalPosition string
InternalQuery string
Where string
Schema string
Table string
Column string
DataTypeName string
Constraint string
File string
Line string
Routine string
}
// ErrorCode is a five-character error code.
type ErrorCode string
// Name returns a more human friendly rendering of the error code, namely the
// "condition name".
//
// See http://www.postgresql.org/docs/9.3/static/errcodes-appendix.html for
// details.
func (ec ErrorCode) Name() string {
return errorCodeNames[ec]
}
// ErrorClass is only the class part of an error code.
type ErrorClass string
// Name returns the condition name of an error class. It is equivalent to the
// condition name of the "standard" error code (i.e. the one having the last
// three characters "000").
func (ec ErrorClass) Name() string {
return errorCodeNames[ErrorCode(ec+"000")]
}
// Class returns the error class, e.g. "28".
//
// See http://www.postgresql.org/docs/9.3/static/errcodes-appendix.html for
// details.
func (ec ErrorCode) Class() ErrorClass {
return ErrorClass(ec[0:2])
}
// errorCodeNames is a mapping between the five-character error codes and the
// human readable "condition names". It is derived from the list at
// http://www.postgresql.org/docs/9.3/static/errcodes-appendix.html
var errorCodeNames = map[ErrorCode]string{
// Class 00 - Successful Completion
"00000": "successful_completion",
// Class 01 - Warning
"01000": "warning",
"0100C": "dynamic_result_sets_returned",
"01008": "implicit_zero_bit_padding",
"01003": "null_value_eliminated_in_set_function",
"01007": "privilege_not_granted",
"01006": "privilege_not_revoked",
"01004": "string_data_right_truncation",
"01P01": "deprecated_feature",
// Class 02 - No Data (this is also a warning class per the SQL standard)
"02000": "no_data",
"02001": "no_additional_dynamic_result_sets_returned",
// Class 03 - SQL Statement Not Yet Complete
"03000": "sql_statement_not_yet_complete",
// Class 08 - Connection Exception
"08000": "connection_exception",
"08003": "connection_does_not_exist",
"08006": "connection_failure",
"08001": "sqlclient_unable_to_establish_sqlconnection",
"08004": "sqlserver_rejected_establishment_of_sqlconnection",
"08007": "transaction_resolution_unknown",
"08P01": "protocol_violation",
// Class 09 - Triggered Action Exception
"09000": "triggered_action_exception",
// Class 0A - Feature Not Supported
"0A000": "feature_not_supported",
// Class 0B - Invalid Transaction Initiation
"0B000": "invalid_transaction_initiation",
// Class 0F - Locator Exception
"0F000": "locator_exception",
"0F001": "invalid_locator_specification",
// Class 0L - Invalid Grantor
"0L000": "invalid_grantor",
"0LP01": "invalid_grant_operation",
// Class 0P - Invalid Role Specification
"0P000": "invalid_role_specification",
// Class 0Z - Diagnostics Exception
"0Z000": "diagnostics_exception",
"0Z002": "stacked_diagnostics_accessed_without_active_handler",
// Class 20 - Case Not Found
"20000": "case_not_found",
// Class 21 - Cardinality Violation
"21000": "cardinality_violation",
// Class 22 - Data Exception
"22000": "data_exception",
"2202E": "array_subscript_error",
"22021": "character_not_in_repertoire",
"22008": "datetime_field_overflow",
"22012": "division_by_zero",
"22005": "error_in_assignment",
"2200B": "escape_character_conflict",
"22022": "indicator_overflow",
"22015": "interval_field_overflow",
"2201E": "invalid_argument_for_logarithm",
"22014": "invalid_argument_for_ntile_function",
"22016": "invalid_argument_for_nth_value_function",
"2201F": "invalid_argument_for_power_function",
"2201G": "invalid_argument_for_width_bucket_function",
"22018": "invalid_character_value_for_cast",
"22007": "invalid_datetime_format",
"22019": "invalid_escape_character",
"2200D": "invalid_escape_octet",
"22025": "invalid_escape_sequence",
"22P06": "nonstandard_use_of_escape_character",
"22010": "invalid_indicator_parameter_value",
"22023": "invalid_parameter_value",
"2201B": "invalid_regular_expression",
"2201W": "invalid_row_count_in_limit_clause",
"2201X": "invalid_row_count_in_result_offset_clause",
"22009": "invalid_time_zone_displacement_value",
"2200C": "invalid_use_of_escape_character",
"2200G": "most_specific_type_mismatch",
"22004": "null_value_not_allowed",
"22002": "null_value_no_indicator_parameter",
"22003": "numeric_value_out_of_range",
"2200H": "sequence_generator_limit_exceeded",
"22026": "string_data_length_mismatch",
"22001": "string_data_right_truncation",
"22011": "substring_error",
"22027": "trim_error",
"22024": "unterminated_c_string",
"2200F": "zero_length_character_string",
"22P01": "floating_point_exception",
"22P02": "invalid_text_representation",
"22P03": "invalid_binary_representation",
"22P04": "bad_copy_file_format",
"22P05": "untranslatable_character",
"2200L": "not_an_xml_document",
"2200M": "invalid_xml_document",
"2200N": "invalid_xml_content",
"2200S": "invalid_xml_comment",
"2200T": "invalid_xml_processing_instruction",
// Class 23 - Integrity Constraint Violation
"23000": "integrity_constraint_violation",
"23001": "restrict_violation",
"23502": "not_null_violation",
"23503": "foreign_key_violation",
"23505": "unique_violation",
"23514": "check_violation",
"23P01": "exclusion_violation",
// Class 24 - Invalid Cursor State
"24000": "invalid_cursor_state",
// Class 25 - Invalid Transaction State
"25000": "invalid_transaction_state",
"25001": "active_sql_transaction",
"25002": "branch_transaction_already_active",
"25008": "held_cursor_requires_same_isolation_level",
"25003": "inappropriate_access_mode_for_branch_transaction",
"25004": "inappropriate_isolation_level_for_branch_transaction",
"25005": "no_active_sql_transaction_for_branch_transaction",
"25006": "read_only_sql_transaction",
"25007": "schema_and_data_statement_mixing_not_supported",
"25P01": "no_active_sql_transaction",
"25P02": "in_failed_sql_transaction",
// Class 26 - Invalid SQL Statement Name
"26000": "invalid_sql_statement_name",
// Class 27 - Triggered Data Change Violation
"27000": "triggered_data_change_violation",
// Class 28 - Invalid Authorization Specification
"28000": "invalid_authorization_specification",
"28P01": "invalid_password",
// Class 2B - Dependent Privilege Descriptors Still Exist
"2B000": "dependent_privilege_descriptors_still_exist",
"2BP01": "dependent_objects_still_exist",
// Class 2D - Invalid Transaction Termination
"2D000": "invalid_transaction_termination",
// Class 2F - SQL Routine Exception
"2F000": "sql_routine_exception",
"2F005": "function_executed_no_return_statement",
"2F002": "modifying_sql_data_not_permitted",
"2F003": "prohibited_sql_statement_attempted",
"2F004": "reading_sql_data_not_permitted",
// Class 34 - Invalid Cursor Name
"34000": "invalid_cursor_name",
// Class 38 - External Routine Exception
"38000": "external_routine_exception",
"38001": "containing_sql_not_permitted",
"38002": "modifying_sql_data_not_permitted",
"38003": "prohibited_sql_statement_attempted",
"38004": "reading_sql_data_not_permitted",
// Class 39 - External Routine Invocation Exception
"39000": "external_routine_invocation_exception",
"39001": "invalid_sqlstate_returned",
"39004": "null_value_not_allowed",
"39P01": "trigger_protocol_violated",
"39P02": "srf_protocol_violated",
// Class 3B - Savepoint Exception
"3B000": "savepoint_exception",
"3B001": "invalid_savepoint_specification",
// Class 3D - Invalid Catalog Name
"3D000": "invalid_catalog_name",
// Class 3F - Invalid Schema Name
"3F000": "invalid_schema_name",
// Class 40 - Transaction Rollback
"40000": "transaction_rollback",
"40002": "transaction_integrity_constraint_violation",
"40001": "serialization_failure",
"40003": "statement_completion_unknown",
"40P01": "deadlock_detected",
// Class 42 - Syntax Error or Access Rule Violation
"42000": "syntax_error_or_access_rule_violation",
"42601": "syntax_error",
"42501": "insufficient_privilege",
"42846": "cannot_coerce",
"42803": "grouping_error",
"42P20": "windowing_error",
"42P19": "invalid_recursion",
"42830": "invalid_foreign_key",
"42602": "invalid_name",
"42622": "name_too_long",
"42939": "reserved_name",
"42804": "datatype_mismatch",
"42P18": "indeterminate_datatype",
"42P21": "collation_mismatch",
"42P22": "indeterminate_collation",
"42809": "wrong_object_type",
"42703": "undefined_column",
"42883": "undefined_function",
"42P01": "undefined_table",
"42P02": "undefined_parameter",
"42704": "undefined_object",
"42701": "duplicate_column",
"42P03": "duplicate_cursor",
"42P04": "duplicate_database",
"42723": "duplicate_function",
"42P05": "duplicate_prepared_statement",
"42P06": "duplicate_schema",
"42P07": "duplicate_table",
"42712": "duplicate_alias",
"42710": "duplicate_object",
"42702": "ambiguous_column",
"42725": "ambiguous_function",
"42P08": "ambiguous_parameter",
"42P09": "ambiguous_alias",
"42P10": "invalid_column_reference",
"42611": "invalid_column_definition",
"42P11": "invalid_cursor_definition",
"42P12": "invalid_database_definition",
"42P13": "invalid_function_definition",
"42P14": "invalid_prepared_statement_definition",
"42P15": "invalid_schema_definition",
"42P16": "invalid_table_definition",
"42P17": "invalid_object_definition",
// Class 44 - WITH CHECK OPTION Violation
"44000": "with_check_option_violation",
// Class 53 - Insufficient Resources
"53000": "insufficient_resources",
"53100": "disk_full",
"53200": "out_of_memory",
"53300": "too_many_connections",
"53400": "configuration_limit_exceeded",
// Class 54 - Program Limit Exceeded
"54000": "program_limit_exceeded",
"54001": "statement_too_complex",
"54011": "too_many_columns",
"54023": "too_many_arguments",
// Class 55 - Object Not In Prerequisite State
"55000": "object_not_in_prerequisite_state",
"55006": "object_in_use",
"55P02": "cant_change_runtime_param",
"55P03": "lock_not_available",
// Class 57 - Operator Intervention
"57000": "operator_intervention",
"57014": "query_canceled",
"57P01": "admin_shutdown",
"57P02": "crash_shutdown",
"57P03": "cannot_connect_now",
"57P04": "database_dropped",
// Class 58 - System Error (errors external to PostgreSQL itself)
"58000": "system_error",
"58030": "io_error",
"58P01": "undefined_file",
"58P02": "duplicate_file",
// Class F0 - Configuration File Error
"F0000": "config_file_error",
"F0001": "lock_file_exists",
// Class HV - Foreign Data Wrapper Error (SQL/MED)
"HV000": "fdw_error",
"HV005": "fdw_column_name_not_found",
"HV002": "fdw_dynamic_parameter_value_needed",
"HV010": "fdw_function_sequence_error",
"HV021": "fdw_inconsistent_descriptor_information",
"HV024": "fdw_invalid_attribute_value",
"HV007": "fdw_invalid_column_name",
"HV008": "fdw_invalid_column_number",
"HV004": "fdw_invalid_data_type",
"HV006": "fdw_invalid_data_type_descriptors",
"HV091": "fdw_invalid_descriptor_field_identifier",
"HV00B": "fdw_invalid_handle",
"HV00C": "fdw_invalid_option_index",
"HV00D": "fdw_invalid_option_name",
"HV090": "fdw_invalid_string_length_or_buffer_length",
"HV00A": "fdw_invalid_string_format",
"HV009": "fdw_invalid_use_of_null_pointer",
"HV014": "fdw_too_many_handles",
"HV001": "fdw_out_of_memory",
"HV00P": "fdw_no_schemas",
"HV00J": "fdw_option_name_not_found",
"HV00K": "fdw_reply_handle",
"HV00Q": "fdw_schema_not_found",
"HV00R": "fdw_table_not_found",
"HV00L": "fdw_unable_to_create_execution",
"HV00M": "fdw_unable_to_create_reply",
"HV00N": "fdw_unable_to_establish_connection",
// Class P0 - PL/pgSQL Error
"P0000": "plpgsql_error",
"P0001": "raise_exception",
"P0002": "no_data_found",
"P0003": "too_many_rows",
// Class XX - Internal Error
"XX000": "internal_error",
"XX001": "data_corrupted",
"XX002": "index_corrupted",
}
func parseError(r *readBuf) *Error {
err := new(Error)
for t := r.byte(); t != 0; t = r.byte() {
msg := r.string()
switch t {
case 'S':
err.Severity = msg
case 'C':
err.Code = ErrorCode(msg)
case 'M':
err.Message = msg
case 'D':
err.Detail = msg
case 'H':
err.Hint = msg
case 'P':
err.Position = msg
case 'p':
err.InternalPosition = msg
case 'q':
err.InternalQuery = msg
case 'W':
err.Where = msg
case 's':
err.Schema = msg
case 't':
err.Table = msg
case 'c':
err.Column = msg
case 'd':
err.DataTypeName = msg
case 'n':
err.Constraint = msg
case 'F':
err.File = msg
case 'L':
err.Line = msg
case 'R':
err.Routine = msg
}
}
return err
}
// Fatal returns true if the Error Severity is fatal.
func (err *Error) Fatal() bool {
return err.Severity == Efatal
}
// Get implements the legacy PGError interface. New code should use the fields
// of the Error struct directly.
func (err *Error) Get(k byte) (v string) {
switch k {
case 'S':
return err.Severity
case 'C':
return string(err.Code)
case 'M':
return err.Message
case 'D':
return err.Detail
case 'H':
return err.Hint
case 'P':
return err.Position
case 'p':
return err.InternalPosition
case 'q':
return err.InternalQuery
case 'W':
return err.Where
case 's':
return err.Schema
case 't':
return err.Table
case 'c':
return err.Column
case 'd':
return err.DataTypeName
case 'n':
return err.Constraint
case 'F':
return err.File
case 'L':
return err.Line
case 'R':
return err.Routine
}
return ""
}
func (err Error) Error() string {
return "pq: " + err.Message
}
// PGError is an interface used by previous versions of pq. It is provided
// only to support legacy code. New code should use the Error type.
type PGError interface {
Error() string
Fatal() bool
Get(k byte) (v string)
}
func errorf(s string, args ...interface{}) {
panic(fmt.Errorf("pq: %s", fmt.Sprintf(s, args...)))
}
// TODO(ainar-g) Rename to errorf after removing panics.
func fmterrorf(s string, args ...interface{}) error {
return fmt.Errorf("pq: %s", fmt.Sprintf(s, args...))
}
func errRecoverNoErrBadConn(err *error) {
e := recover()
if e == nil {
// Do nothing
return
}
var ok bool
*err, ok = e.(error)
if !ok {
*err = fmt.Errorf("pq: unexpected error: %#v", e)
}
}
func (cn *conn) errRecover(err *error) {
e := recover()
switch v := e.(type) {
case nil:
// Do nothing
case runtime.Error:
cn.bad = true
panic(v)
case *Error:
if v.Fatal() {
*err = driver.ErrBadConn
} else {
*err = v
}
case *net.OpError:
cn.bad = true
*err = v
case error:
if v == io.EOF || v.(error).Error() == "remote error: handshake failure" {
*err = driver.ErrBadConn
} else {
*err = v
}
default:
cn.bad = true
panic(fmt.Sprintf("unknown error: %#v", e))
}
// Any time we return ErrBadConn, we need to remember it since *Tx doesn't
// mark the connection bad in database/sql.
if *err == driver.ErrBadConn {
cn.bad = true
}
}

264
vendor/github.com/lib/pq/scram/scram.go generated vendored Normal file
View File

@ -0,0 +1,264 @@
// Copyright (c) 2014 - Gustavo Niemeyer <gustavo@niemeyer.net>
//
// 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 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.
// Package scram implements a SCRAM-{SHA-1,etc} client per RFC5802.
//
// http://tools.ietf.org/html/rfc5802
//
package scram
import (
"bytes"
"crypto/hmac"
"crypto/rand"
"encoding/base64"
"fmt"
"hash"
"strconv"
"strings"
)
// Client implements a SCRAM-* client (SCRAM-SHA-1, SCRAM-SHA-256, etc).
//
// A Client may be used within a SASL conversation with logic resembling:
//
// var in []byte
// var client = scram.NewClient(sha1.New, user, pass)
// for client.Step(in) {
// out := client.Out()
// // send out to server
// in := serverOut
// }
// if client.Err() != nil {
// // auth failed
// }
//
type Client struct {
newHash func() hash.Hash
user string
pass string
step int
out bytes.Buffer
err error
clientNonce []byte
serverNonce []byte
saltedPass []byte
authMsg bytes.Buffer
}
// NewClient returns a new SCRAM-* client with the provided hash algorithm.
//
// For SCRAM-SHA-256, for example, use:
//
// client := scram.NewClient(sha256.New, user, pass)
//
func NewClient(newHash func() hash.Hash, user, pass string) *Client {
c := &Client{
newHash: newHash,
user: user,
pass: pass,
}
c.out.Grow(256)
c.authMsg.Grow(256)
return c
}
// Out returns the data to be sent to the server in the current step.
func (c *Client) Out() []byte {
if c.out.Len() == 0 {
return nil
}
return c.out.Bytes()
}
// Err returns the error that ocurred, or nil if there were no errors.
func (c *Client) Err() error {
return c.err
}
// SetNonce sets the client nonce to the provided value.
// If not set, the nonce is generated automatically out of crypto/rand on the first step.
func (c *Client) SetNonce(nonce []byte) {
c.clientNonce = nonce
}
var escaper = strings.NewReplacer("=", "=3D", ",", "=2C")
// Step processes the incoming data from the server and makes the
// next round of data for the server available via Client.Out.
// Step returns false if there are no errors and more data is
// still expected.
func (c *Client) Step(in []byte) bool {
c.out.Reset()
if c.step > 2 || c.err != nil {
return false
}
c.step++
switch c.step {
case 1:
c.err = c.step1(in)
case 2:
c.err = c.step2(in)
case 3:
c.err = c.step3(in)
}
return c.step > 2 || c.err != nil
}
func (c *Client) step1(in []byte) error {
if len(c.clientNonce) == 0 {
const nonceLen = 16
buf := make([]byte, nonceLen+b64.EncodedLen(nonceLen))
if _, err := rand.Read(buf[:nonceLen]); err != nil {
return fmt.Errorf("cannot read random SCRAM-SHA-256 nonce from operating system: %v", err)
}
c.clientNonce = buf[nonceLen:]
b64.Encode(c.clientNonce, buf[:nonceLen])
}
c.authMsg.WriteString("n=")
escaper.WriteString(&c.authMsg, c.user)
c.authMsg.WriteString(",r=")
c.authMsg.Write(c.clientNonce)
c.out.WriteString("n,,")
c.out.Write(c.authMsg.Bytes())
return nil
}
var b64 = base64.StdEncoding
func (c *Client) step2(in []byte) error {
c.authMsg.WriteByte(',')
c.authMsg.Write(in)
fields := bytes.Split(in, []byte(","))
if len(fields) != 3 {
return fmt.Errorf("expected 3 fields in first SCRAM-SHA-256 server message, got %d: %q", len(fields), in)
}
if !bytes.HasPrefix(fields[0], []byte("r=")) || len(fields[0]) < 2 {
return fmt.Errorf("server sent an invalid SCRAM-SHA-256 nonce: %q", fields[0])
}
if !bytes.HasPrefix(fields[1], []byte("s=")) || len(fields[1]) < 6 {
return fmt.Errorf("server sent an invalid SCRAM-SHA-256 salt: %q", fields[1])
}
if !bytes.HasPrefix(fields[2], []byte("i=")) || len(fields[2]) < 6 {
return fmt.Errorf("server sent an invalid SCRAM-SHA-256 iteration count: %q", fields[2])
}
c.serverNonce = fields[0][2:]
if !bytes.HasPrefix(c.serverNonce, c.clientNonce) {
return fmt.Errorf("server SCRAM-SHA-256 nonce is not prefixed by client nonce: got %q, want %q+\"...\"", c.serverNonce, c.clientNonce)
}
salt := make([]byte, b64.DecodedLen(len(fields[1][2:])))
n, err := b64.Decode(salt, fields[1][2:])
if err != nil {
return fmt.Errorf("cannot decode SCRAM-SHA-256 salt sent by server: %q", fields[1])
}
salt = salt[:n]
iterCount, err := strconv.Atoi(string(fields[2][2:]))
if err != nil {
return fmt.Errorf("server sent an invalid SCRAM-SHA-256 iteration count: %q", fields[2])
}
c.saltPassword(salt, iterCount)
c.authMsg.WriteString(",c=biws,r=")
c.authMsg.Write(c.serverNonce)
c.out.WriteString("c=biws,r=")
c.out.Write(c.serverNonce)
c.out.WriteString(",p=")
c.out.Write(c.clientProof())
return nil
}
func (c *Client) step3(in []byte) error {
var isv, ise bool
var fields = bytes.Split(in, []byte(","))
if len(fields) == 1 {
isv = bytes.HasPrefix(fields[0], []byte("v="))
ise = bytes.HasPrefix(fields[0], []byte("e="))
}
if ise {
return fmt.Errorf("SCRAM-SHA-256 authentication error: %s", fields[0][2:])
} else if !isv {
return fmt.Errorf("unsupported SCRAM-SHA-256 final message from server: %q", in)
}
if !bytes.Equal(c.serverSignature(), fields[0][2:]) {
return fmt.Errorf("cannot authenticate SCRAM-SHA-256 server signature: %q", fields[0][2:])
}
return nil
}
func (c *Client) saltPassword(salt []byte, iterCount int) {
mac := hmac.New(c.newHash, []byte(c.pass))
mac.Write(salt)
mac.Write([]byte{0, 0, 0, 1})
ui := mac.Sum(nil)
hi := make([]byte, len(ui))
copy(hi, ui)
for i := 1; i < iterCount; i++ {
mac.Reset()
mac.Write(ui)
mac.Sum(ui[:0])
for j, b := range ui {
hi[j] ^= b
}
}
c.saltedPass = hi
}
func (c *Client) clientProof() []byte {
mac := hmac.New(c.newHash, c.saltedPass)
mac.Write([]byte("Client Key"))
clientKey := mac.Sum(nil)
hash := c.newHash()
hash.Write(clientKey)
storedKey := hash.Sum(nil)
mac = hmac.New(c.newHash, storedKey)
mac.Write(c.authMsg.Bytes())
clientProof := mac.Sum(nil)
for i, b := range clientKey {
clientProof[i] ^= b
}
clientProof64 := make([]byte, b64.EncodedLen(len(clientProof)))
b64.Encode(clientProof64, clientProof)
return clientProof64
}
func (c *Client) serverSignature() []byte {
mac := hmac.New(c.newHash, c.saltedPass)
mac.Write([]byte("Server Key"))
serverKey := mac.Sum(nil)
mac = hmac.New(c.newHash, serverKey)
mac.Write(c.authMsg.Bytes())
serverSignature := mac.Sum(nil)
encoded := make([]byte, b64.EncodedLen(len(serverSignature)))
b64.Encode(encoded, serverSignature)
return encoded
}

8
vendor/github.com/lib/pq/ssl.go generated vendored
View File

@ -58,7 +58,13 @@ func ssl(o values) (func(net.Conn) (net.Conn, error), error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
sslRenegotiation(&tlsConf)
// Accept renegotiation requests initiated by the backend.
//
// Renegotiation was deprecated then removed from PostgreSQL 9.5, but
// the default configuration of older versions has it enabled. Redshift
// also initiates renegotiations and cannot be reconfigured.
tlsConf.Renegotiation = tls.RenegotiateFreelyAsClient
return func(conn net.Conn) (net.Conn, error) { return func(conn net.Conn) (net.Conn, error) {
client := tls.Client(conn, &tlsConf) client := tls.Client(conn, &tlsConf)

View File

@ -1,14 +0,0 @@
// +build go1.7
package pq
import "crypto/tls"
// Accept renegotiation requests initiated by the backend.
//
// Renegotiation was deprecated then removed from PostgreSQL 9.5, but
// the default configuration of older versions has it enabled. Redshift
// also initiates renegotiations and cannot be reconfigured.
func sslRenegotiation(conf *tls.Config) {
conf.Renegotiation = tls.RenegotiateFreelyAsClient
}

View File

@ -1,8 +0,0 @@
// +build !go1.7
package pq
import "crypto/tls"
// Renegotiation is not supported by crypto/tls until Go 1.7.
func sslRenegotiation(*tls.Config) {}

View File

@ -7,4 +7,6 @@ go:
- 1.8.x - 1.8.x
- 1.9.x - 1.9.x
- "1.10.x" - "1.10.x"
- "1.11.x"
- "1.12.x"
- tip - tip

View File

@ -1,5 +1,13 @@
## Changelog ## Changelog
### [1.8.1](https://github.com/magiconair/properties/tree/v1.8.1) - 10 May 2019
* [PR #26](https://github.com/magiconair/properties/pull/35): Close body always after request
This patch ensures that in `LoadURL` the response body is always closed.
Thanks to [@liubog2008](https://github.com/liubog2008) for the patch.
### [1.8](https://github.com/magiconair/properties/tree/v1.8) - 15 May 2018 ### [1.8](https://github.com/magiconair/properties/tree/v1.8) - 15 May 2018
* [PR #26](https://github.com/magiconair/properties/pull/26): Disable expansion during loading * [PR #26](https://github.com/magiconair/properties/pull/26): Disable expansion during loading

View File

@ -1,6 +1,6 @@
[![](https://img.shields.io/github/tag/magiconair/properties.svg?style=flat-square&label=release)](https://github.com/magiconair/properties/releases) [![](https://img.shields.io/github/tag/magiconair/properties.svg?style=flat-square&label=release)](https://github.com/magiconair/properties/releases)
[![Travis CI Status](https://img.shields.io/travis/magiconair/properties.svg?branch=master&style=flat-square&label=travis)](https://travis-ci.org/magiconair/properties) [![Travis CI Status](https://img.shields.io/travis/magiconair/properties.svg?branch=master&style=flat-square&label=travis)](https://travis-ci.org/magiconair/properties)
[![Codeship CI Status](https://img.shields.io/codeship/16aaf660-f615-0135-b8f0-7e33b70920c0/master.svg?label=codeship&style=flat-square)](https://app.codeship.com/projects/274177") [![CircleCI Status](https://img.shields.io/circleci/project/github/magiconair/properties.svg?label=circle+ci&style=flat-square)](https://circleci.com/gh/magiconair/properties)
[![License](https://img.shields.io/badge/License-BSD%202--Clause-orange.svg?style=flat-square)](https://raw.githubusercontent.com/magiconair/properties/master/LICENSE) [![License](https://img.shields.io/badge/License-BSD%202--Clause-orange.svg?style=flat-square)](https://raw.githubusercontent.com/magiconair/properties/master/LICENSE)
[![GoDoc](http://img.shields.io/badge/godoc-reference-5272B4.svg?style=flat-square)](http://godoc.org/github.com/magiconair/properties) [![GoDoc](http://img.shields.io/badge/godoc-reference-5272B4.svg?style=flat-square)](http://godoc.org/github.com/magiconair/properties)
@ -30,7 +30,7 @@ changed from `panic` to `log.Fatal` but this is configurable and custom
error handling functions can be provided. See the package documentation for error handling functions can be provided. See the package documentation for
details. details.
Read the full documentation on [GoDoc](https://godoc.org/github.com/magiconair/properties) [![GoDoc](https://godoc.org/github.com/magiconair/properties?status.png)](https://godoc.org/github.com/magiconair/properties) Read the full documentation on [![GoDoc](http://img.shields.io/badge/godoc-reference-5272B4.svg?style=flat-square)](http://godoc.org/github.com/magiconair/properties)
## Getting Started ## Getting Started

1
vendor/github.com/magiconair/properties/go.mod generated vendored Normal file
View File

@ -0,0 +1 @@
module github.com/magiconair/properties

View File

@ -115,6 +115,7 @@ func (l *Loader) LoadURL(url string) (*Properties, error) {
if err != nil { if err != nil {
return nil, fmt.Errorf("properties: error fetching %q. %s", url, err) return nil, fmt.Errorf("properties: error fetching %q. %s", url, err)
} }
defer resp.Body.Close()
if resp.StatusCode == 404 && l.IgnoreMissing { if resp.StatusCode == 404 && l.IgnoreMissing {
LogPrintf("properties: %s returned %d. skipping", url, resp.StatusCode) LogPrintf("properties: %s returned %d. skipping", url, resp.StatusCode)
@ -129,7 +130,6 @@ func (l *Loader) LoadURL(url string) (*Properties, error) {
if err != nil { if err != nil {
return nil, fmt.Errorf("properties: %s error reading response. %s", url, err) return nil, fmt.Errorf("properties: %s error reading response. %s", url, err)
} }
defer resp.Body.Close()
ct := resp.Header.Get("Content-Type") ct := resp.Header.Get("Content-Type")
var enc Encoding var enc Encoding

View File

@ -76,6 +76,16 @@ func Expand(path string) (string, error) {
return filepath.Join(dir, path[1:]), nil return filepath.Join(dir, path[1:]), nil
} }
// Reset clears the cache, forcing the next call to Dir to re-detect
// the home directory. This generally never has to be called, but can be
// useful in tests if you're modifying the home directory via the HOME
// env var or something.
func Reset() {
cacheLock.Lock()
defer cacheLock.Unlock()
homedirCache = ""
}
func dirUnix() (string, error) { func dirUnix() (string, error) {
homeEnv := "HOME" homeEnv := "HOME"
if runtime.GOOS == "plan9" { if runtime.GOOS == "plan9" {

View File

@ -1,7 +1,7 @@
language: go language: go
go: go:
- 1.9.x - "1.11.x"
- tip - tip
script: script:

21
vendor/github.com/mitchellh/mapstructure/CHANGELOG.md generated vendored Normal file
View File

@ -0,0 +1,21 @@
## 1.1.2
* Fix error when decode hook decodes interface implementation into interface
type. [GH-140]
## 1.1.1
* Fix panic that can happen in `decodePtr`
## 1.1.0
* Added `StringToIPHookFunc` to convert `string` to `net.IP` and `net.IPNet` [GH-133]
* Support struct to struct decoding [GH-137]
* If source map value is nil, then destination map value is nil (instead of empty)
* If source slice value is nil, then destination slice value is nil (instead of empty)
* If source pointer is nil, then destination pointer is set to nil (instead of
allocated zero value of type)
## 1.0.0
* Initial tagged stable release.

View File

@ -2,6 +2,8 @@ package mapstructure
import ( import (
"errors" "errors"
"fmt"
"net"
"reflect" "reflect"
"strconv" "strconv"
"strings" "strings"
@ -115,6 +117,50 @@ func StringToTimeDurationHookFunc() DecodeHookFunc {
} }
} }
// StringToIPHookFunc returns a DecodeHookFunc that converts
// strings to net.IP
func StringToIPHookFunc() DecodeHookFunc {
return func(
f reflect.Type,
t reflect.Type,
data interface{}) (interface{}, error) {
if f.Kind() != reflect.String {
return data, nil
}
if t != reflect.TypeOf(net.IP{}) {
return data, nil
}
// Convert it by parsing
ip := net.ParseIP(data.(string))
if ip == nil {
return net.IP{}, fmt.Errorf("failed parsing ip %v", data)
}
return ip, nil
}
}
// StringToIPNetHookFunc returns a DecodeHookFunc that converts
// strings to net.IPNet
func StringToIPNetHookFunc() DecodeHookFunc {
return func(
f reflect.Type,
t reflect.Type,
data interface{}) (interface{}, error) {
if f.Kind() != reflect.String {
return data, nil
}
if t != reflect.TypeOf(net.IPNet{}) {
return data, nil
}
// Convert it by parsing
_, net, err := net.ParseCIDR(data.(string))
return net, err
}
}
// StringToTimeHookFunc returns a DecodeHookFunc that converts // StringToTimeHookFunc returns a DecodeHookFunc that converts
// strings to time.Time. // strings to time.Time.
func StringToTimeHookFunc(layout string) DecodeHookFunc { func StringToTimeHookFunc(layout string) DecodeHookFunc {

View File

@ -224,6 +224,17 @@ func (d *Decoder) Decode(input interface{}) error {
// Decodes an unknown data type into a specific reflection value. // Decodes an unknown data type into a specific reflection value.
func (d *Decoder) decode(name string, input interface{}, outVal reflect.Value) error { func (d *Decoder) decode(name string, input interface{}, outVal reflect.Value) error {
var inputVal reflect.Value
if input != nil {
inputVal = reflect.ValueOf(input)
// We need to check here if input is a typed nil. Typed nils won't
// match the "input == nil" below so we check that here.
if inputVal.Kind() == reflect.Ptr && inputVal.IsNil() {
input = nil
}
}
if input == nil { if input == nil {
// If the data is nil, then we don't set anything, unless ZeroFields is set // If the data is nil, then we don't set anything, unless ZeroFields is set
// to true. // to true.
@ -237,7 +248,6 @@ func (d *Decoder) decode(name string, input interface{}, outVal reflect.Value) e
return nil return nil
} }
inputVal := reflect.ValueOf(input)
if !inputVal.IsValid() { if !inputVal.IsValid() {
// If the input value is invalid, then we just set the value // If the input value is invalid, then we just set the value
// to be the zero value. // to be the zero value.
@ -260,8 +270,8 @@ func (d *Decoder) decode(name string, input interface{}, outVal reflect.Value) e
} }
var err error var err error
inputKind := getKind(outVal) outputKind := getKind(outVal)
switch inputKind { switch outputKind {
case reflect.Bool: case reflect.Bool:
err = d.decodeBool(name, input, outVal) err = d.decodeBool(name, input, outVal)
case reflect.Interface: case reflect.Interface:
@ -288,7 +298,7 @@ func (d *Decoder) decode(name string, input interface{}, outVal reflect.Value) e
err = d.decodeFunc(name, input, outVal) err = d.decodeFunc(name, input, outVal)
default: default:
// If we reached this point then we weren't able to decode it // If we reached this point then we weren't able to decode it
return fmt.Errorf("%s: unsupported type: %s", name, inputKind) return fmt.Errorf("%s: unsupported type: %s", name, outputKind)
} }
// If we reached here, then we successfully decoded SOMETHING, so // If we reached here, then we successfully decoded SOMETHING, so
@ -306,7 +316,16 @@ func (d *Decoder) decodeBasic(name string, data interface{}, val reflect.Value)
if val.IsValid() && val.Elem().IsValid() { if val.IsValid() && val.Elem().IsValid() {
return d.decode(name, data, val.Elem()) return d.decode(name, data, val.Elem())
} }
dataVal := reflect.ValueOf(data) dataVal := reflect.ValueOf(data)
// If the input data is a pointer, and the assigned type is the dereference
// of that exact pointer, then indirect it so that we can assign it.
// Example: *string to string
if dataVal.Kind() == reflect.Ptr && dataVal.Type().Elem() == val.Type() {
dataVal = reflect.Indirect(dataVal)
}
if !dataVal.IsValid() { if !dataVal.IsValid() {
dataVal = reflect.Zero(val.Type()) dataVal = reflect.Zero(val.Type())
} }
@ -323,7 +342,7 @@ func (d *Decoder) decodeBasic(name string, data interface{}, val reflect.Value)
} }
func (d *Decoder) decodeString(name string, data interface{}, val reflect.Value) error { func (d *Decoder) decodeString(name string, data interface{}, val reflect.Value) error {
dataVal := reflect.ValueOf(data) dataVal := reflect.Indirect(reflect.ValueOf(data))
dataKind := getKind(dataVal) dataKind := getKind(dataVal)
converted := true converted := true
@ -375,7 +394,7 @@ func (d *Decoder) decodeString(name string, data interface{}, val reflect.Value)
} }
func (d *Decoder) decodeInt(name string, data interface{}, val reflect.Value) error { func (d *Decoder) decodeInt(name string, data interface{}, val reflect.Value) error {
dataVal := reflect.ValueOf(data) dataVal := reflect.Indirect(reflect.ValueOf(data))
dataKind := getKind(dataVal) dataKind := getKind(dataVal)
dataType := dataVal.Type() dataType := dataVal.Type()
@ -417,7 +436,7 @@ func (d *Decoder) decodeInt(name string, data interface{}, val reflect.Value) er
} }
func (d *Decoder) decodeUint(name string, data interface{}, val reflect.Value) error { func (d *Decoder) decodeUint(name string, data interface{}, val reflect.Value) error {
dataVal := reflect.ValueOf(data) dataVal := reflect.Indirect(reflect.ValueOf(data))
dataKind := getKind(dataVal) dataKind := getKind(dataVal)
switch { switch {
@ -460,7 +479,7 @@ func (d *Decoder) decodeUint(name string, data interface{}, val reflect.Value) e
} }
func (d *Decoder) decodeBool(name string, data interface{}, val reflect.Value) error { func (d *Decoder) decodeBool(name string, data interface{}, val reflect.Value) error {
dataVal := reflect.ValueOf(data) dataVal := reflect.Indirect(reflect.ValueOf(data))
dataKind := getKind(dataVal) dataKind := getKind(dataVal)
switch { switch {
@ -491,7 +510,7 @@ func (d *Decoder) decodeBool(name string, data interface{}, val reflect.Value) e
} }
func (d *Decoder) decodeFloat(name string, data interface{}, val reflect.Value) error { func (d *Decoder) decodeFloat(name string, data interface{}, val reflect.Value) error {
dataVal := reflect.ValueOf(data) dataVal := reflect.Indirect(reflect.ValueOf(data))
dataKind := getKind(dataVal) dataKind := getKind(dataVal)
dataType := dataVal.Type() dataType := dataVal.Type()
@ -595,6 +614,20 @@ func (d *Decoder) decodeMapFromMap(name string, dataVal reflect.Value, val refle
// Accumulate errors // Accumulate errors
errors := make([]string, 0) errors := make([]string, 0)
// If the input data is empty, then we just match what the input data is.
if dataVal.Len() == 0 {
if dataVal.IsNil() {
if !val.IsNil() {
val.Set(dataVal)
}
} else {
// Set to empty allocated value
val.Set(valMap)
}
return nil
}
for _, k := range dataVal.MapKeys() { for _, k := range dataVal.MapKeys() {
fieldName := fmt.Sprintf("%s[%s]", name, k) fieldName := fmt.Sprintf("%s[%s]", name, k)
@ -706,11 +739,33 @@ func (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val re
} }
func (d *Decoder) decodePtr(name string, data interface{}, val reflect.Value) error { func (d *Decoder) decodePtr(name string, data interface{}, val reflect.Value) error {
// If the input data is nil, then we want to just set the output
// pointer to be nil as well.
isNil := data == nil
if !isNil {
switch v := reflect.Indirect(reflect.ValueOf(data)); v.Kind() {
case reflect.Chan,
reflect.Func,
reflect.Interface,
reflect.Map,
reflect.Ptr,
reflect.Slice:
isNil = v.IsNil()
}
}
if isNil {
if !val.IsNil() && val.CanSet() {
nilValue := reflect.New(val.Type()).Elem()
val.Set(nilValue)
}
return nil
}
// Create an element of the concrete (non pointer) type and decode // Create an element of the concrete (non pointer) type and decode
// into that. Then set the value of the pointer to this type. // into that. Then set the value of the pointer to this type.
valType := val.Type() valType := val.Type()
valElemType := valType.Elem() valElemType := valType.Elem()
if val.CanSet() { if val.CanSet() {
realVal := val realVal := val
if realVal.IsNil() || d.config.ZeroFields { if realVal.IsNil() || d.config.ZeroFields {
@ -752,33 +807,44 @@ func (d *Decoder) decodeSlice(name string, data interface{}, val reflect.Value)
valSlice := val valSlice := val
if valSlice.IsNil() || d.config.ZeroFields { if valSlice.IsNil() || d.config.ZeroFields {
if d.config.WeaklyTypedInput {
switch {
// Slice and array we use the normal logic
case dataValKind == reflect.Slice, dataValKind == reflect.Array:
break
// Empty maps turn into empty slices
case dataValKind == reflect.Map:
if dataVal.Len() == 0 {
val.Set(reflect.MakeSlice(sliceType, 0, 0))
return nil
}
// Create slice of maps of other sizes
return d.decodeSlice(name, []interface{}{data}, val)
case dataValKind == reflect.String && valElemType.Kind() == reflect.Uint8:
return d.decodeSlice(name, []byte(dataVal.String()), val)
// All other types we try to convert to the slice type
// and "lift" it into it. i.e. a string becomes a string slice.
default:
// Just re-try this function with data as a slice.
return d.decodeSlice(name, []interface{}{data}, val)
}
}
// Check input type // Check input type
if dataValKind != reflect.Array && dataValKind != reflect.Slice { if dataValKind != reflect.Array && dataValKind != reflect.Slice {
if d.config.WeaklyTypedInput {
switch {
// Empty maps turn into empty slices
case dataValKind == reflect.Map:
if dataVal.Len() == 0 {
val.Set(reflect.MakeSlice(sliceType, 0, 0))
return nil
}
// Create slice of maps of other sizes
return d.decodeSlice(name, []interface{}{data}, val)
case dataValKind == reflect.String && valElemType.Kind() == reflect.Uint8:
return d.decodeSlice(name, []byte(dataVal.String()), val)
// All other types we try to convert to the slice type
// and "lift" it into it. i.e. a string becomes a string slice.
default:
// Just re-try this function with data as a slice.
return d.decodeSlice(name, []interface{}{data}, val)
}
}
return fmt.Errorf( return fmt.Errorf(
"'%s': source data must be an array or slice, got %s", name, dataValKind) "'%s': source data must be an array or slice, got %s", name, dataValKind)
} }
// If the input value is empty, then don't allocate since non-nil != nil
if dataVal.Len() == 0 {
return nil
}
// Make a new slice to hold our result, same size as the original data. // Make a new slice to hold our result, same size as the original data.
valSlice = reflect.MakeSlice(sliceType, dataVal.Len(), dataVal.Len()) valSlice = reflect.MakeSlice(sliceType, dataVal.Len(), dataVal.Len())
} }
@ -888,10 +954,29 @@ func (d *Decoder) decodeStruct(name string, data interface{}, val reflect.Value)
} }
dataValKind := dataVal.Kind() dataValKind := dataVal.Kind()
if dataValKind != reflect.Map { switch dataValKind {
return fmt.Errorf("'%s' expected a map, got '%s'", name, dataValKind) case reflect.Map:
} return d.decodeStructFromMap(name, dataVal, val)
case reflect.Struct:
// Not the most efficient way to do this but we can optimize later if
// we want to. To convert from struct to struct we go to map first
// as an intermediary.
m := make(map[string]interface{})
mval := reflect.Indirect(reflect.ValueOf(&m))
if err := d.decodeMapFromStruct(name, dataVal, mval, mval); err != nil {
return err
}
result := d.decodeStructFromMap(name, mval, val)
return result
default:
return fmt.Errorf("'%s' expected a map, got '%s'", name, dataVal.Kind())
}
}
func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) error {
dataValType := dataVal.Type() dataValType := dataVal.Type()
if kind := dataValType.Key().Kind(); kind != reflect.String && kind != reflect.Interface { if kind := dataValType.Key().Kind(); kind != reflect.String && kind != reflect.Interface {
return fmt.Errorf( return fmt.Errorf(

View File

@ -1,10 +1,9 @@
language: go language: go
go: go:
- 1.6.x
- 1.7.x
- 1.8.x
- 1.9.x
- 1.10.x - 1.10.x
- 1.11.x
- 1.12.x
- tip
install: install:
- go get -v -t ./... - go get -v -t ./...
@ -13,4 +12,4 @@ install:
- go install github.com/onsi/ginkgo/ginkgo - go install github.com/onsi/ginkgo/ginkgo
- export PATH=$PATH:$HOME/gopath/bin - export PATH=$PATH:$HOME/gopath/bin
script: $HOME/gopath/bin/ginkgo -r --randomizeAllSpecs --randomizeSuites --race --trace && go vet script: $HOME/gopath/bin/ginkgo -r --randomizeAllSpecs --randomizeSuites --race --trace && go vet

View File

@ -1,3 +1,23 @@
## 1.8.0
### New Features
- allow config of the vet flag for `go test` (#562) [3cd45fa]
- Support projects using go modules [d56ee76]
### Fixes and Minor Improvements
- chore(godoc): fixes typos in Measurement funcs [dbaca8e]
- Optimize focus to avoid allocations [f493786]
- Ensure generated test file names are underscored [505cc35]
## 1.7.0
### New Features
- Add JustAfterEach (#484) [0d4f080]
### Fixes
- Correctly round suite time in junit reporter [2445fc1]
- Avoid using -i argument to go test for Golang 1.10+ [46bbc26]
## 1.6.0 ## 1.6.0
### New Features ### New Features

View File

@ -20,7 +20,7 @@ import (
"fmt" "fmt"
) )
const VERSION = "1.6.0" const VERSION = "1.8.0"
type GinkgoConfigType struct { type GinkgoConfigType struct {
RandomSeed int64 RandomSeed int64

View File

@ -457,13 +457,13 @@ func FMeasure(text string, body interface{}, samples int) bool {
return true return true
} }
//You can mark Maeasurements as pending using PMeasure //You can mark Measurements as pending using PMeasure
func PMeasure(text string, _ ...interface{}) bool { func PMeasure(text string, _ ...interface{}) bool {
globalSuite.PushMeasureNode(text, func(b Benchmarker) {}, types.FlagTypePending, codelocation.New(1), 0) globalSuite.PushMeasureNode(text, func(b Benchmarker) {}, types.FlagTypePending, codelocation.New(1), 0)
return true return true
} }
//You can mark Maeasurements as pending using XMeasure //You can mark Measurements as pending using XMeasure
func XMeasure(text string, _ ...interface{}) bool { func XMeasure(text string, _ ...interface{}) bool {
globalSuite.PushMeasureNode(text, func(b Benchmarker) {}, types.FlagTypePending, codelocation.New(1), 0) globalSuite.PushMeasureNode(text, func(b Benchmarker) {}, types.FlagTypePending, codelocation.New(1), 0)
return true return true
@ -590,6 +590,16 @@ func JustBeforeEach(body interface{}, timeout ...float64) bool {
return true return true
} }
//JustAfterEach blocks are run after It blocks but *before* all AfterEach blocks. For more details,
//read the [documentation](http://onsi.github.io/ginkgo/#separating_creation_and_configuration_)
//
//Like It blocks, JustAfterEach blocks can be made asynchronous by providing a body function that accepts
//a Done channel
func JustAfterEach(body interface{}, timeout ...float64) bool {
globalSuite.PushJustAfterEachNode(body, codelocation.New(1), parseTimeout(timeout...))
return true
}
//AfterEach blocks are run after It blocks. When multiple AfterEach blocks are defined in nested //AfterEach blocks are run after It blocks. When multiple AfterEach blocks are defined in nested
//Describe and Context blocks the innermost AfterEach blocks are run first. //Describe and Context blocks the innermost AfterEach blocks are run first.
// //

View File

@ -40,3 +40,9 @@ func NewJustBeforeEachNode(body interface{}, codeLocation types.CodeLocation, ti
runner: newRunner(body, codeLocation, timeout, failer, types.SpecComponentTypeJustBeforeEach, componentIndex), runner: newRunner(body, codeLocation, timeout, failer, types.SpecComponentTypeJustBeforeEach, componentIndex),
} }
} }
func NewJustAfterEachNode(body interface{}, codeLocation types.CodeLocation, timeout time.Duration, failer *failer.Failer, componentIndex int) *SetupNode {
return &SetupNode{
runner: newRunner(body, codeLocation, timeout, failer, types.SpecComponentTypeJustAfterEach, componentIndex),
}
}

View File

@ -161,6 +161,18 @@ func (spec *Spec) runSample(sample int, writer io.Writer) {
innerMostContainerIndexToUnwind := -1 innerMostContainerIndexToUnwind := -1
defer func() { defer func() {
for i := innerMostContainerIndexToUnwind; i >= 0; i-- {
container := spec.containers[i]
for _, justAfterEach := range container.SetupNodesOfType(types.SpecComponentTypeJustAfterEach) {
spec.announceSetupNode(writer, "JustAfterEach", container, justAfterEach)
justAfterEachState, justAfterEachFailure := justAfterEach.Run()
if justAfterEachState != types.SpecStatePassed && spec.state == types.SpecStatePassed {
spec.state = justAfterEachState
spec.failure = justAfterEachFailure
}
}
}
for i := innerMostContainerIndexToUnwind; i >= 0; i-- { for i := innerMostContainerIndexToUnwind; i >= 0; i-- {
container := spec.containers[i] container := spec.containers[i]
for _, afterEach := range container.SetupNodesOfType(types.SpecComponentTypeAfterEach) { for _, afterEach := range container.SetupNodesOfType(types.SpecComponentTypeAfterEach) {

View File

@ -7,14 +7,21 @@ import (
) )
type Specs struct { type Specs struct {
specs []*Spec specs []*Spec
names []string
hasProgrammaticFocus bool hasProgrammaticFocus bool
RegexScansFilePath bool RegexScansFilePath bool
} }
func NewSpecs(specs []*Spec) *Specs { func NewSpecs(specs []*Spec) *Specs {
names := make([]string, len(specs))
for i, spec := range specs {
names[i] = spec.ConcatenatedString()
}
return &Specs{ return &Specs{
specs: specs, specs: specs,
names: names,
} }
} }
@ -30,10 +37,13 @@ func (e *Specs) Shuffle(r *rand.Rand) {
sort.Sort(e) sort.Sort(e)
permutation := r.Perm(len(e.specs)) permutation := r.Perm(len(e.specs))
shuffledSpecs := make([]*Spec, len(e.specs)) shuffledSpecs := make([]*Spec, len(e.specs))
names := make([]string, len(e.specs))
for i, j := range permutation { for i, j := range permutation {
shuffledSpecs[i] = e.specs[j] shuffledSpecs[i] = e.specs[j]
names[i] = e.names[j]
} }
e.specs = shuffledSpecs e.specs = shuffledSpecs
e.names = names
} }
func (e *Specs) ApplyFocus(description string, focusString string, skipString string) { func (e *Specs) ApplyFocus(description string, focusString string, skipString string) {
@ -64,33 +74,43 @@ func (e *Specs) applyProgrammaticFocus() {
// toMatch returns a byte[] to be used by regex matchers. When adding new behaviours to the matching function, // toMatch returns a byte[] to be used by regex matchers. When adding new behaviours to the matching function,
// this is the place which we append to. // this is the place which we append to.
func (e *Specs) toMatch(description string, spec *Spec) []byte { func (e *Specs) toMatch(description string, i int) []byte {
if i > len(e.names) {
return nil
}
if e.RegexScansFilePath { if e.RegexScansFilePath {
return []byte( return []byte(
description + " " + description + " " +
spec.ConcatenatedString() + " " + e.names[i] + " " +
spec.subject.CodeLocation().FileName) e.specs[i].subject.CodeLocation().FileName)
} else { } else {
return []byte( return []byte(
description + " " + description + " " +
spec.ConcatenatedString()) e.names[i])
} }
} }
func (e *Specs) applyRegExpFocusAndSkip(description string, focusString string, skipString string) { func (e *Specs) applyRegExpFocusAndSkip(description string, focusString string, skipString string) {
for _, spec := range e.specs { var focusFilter *regexp.Regexp
if focusString != "" {
focusFilter = regexp.MustCompile(focusString)
}
var skipFilter *regexp.Regexp
if skipString != "" {
skipFilter = regexp.MustCompile(skipString)
}
for i, spec := range e.specs {
matchesFocus := true matchesFocus := true
matchesSkip := false matchesSkip := false
toMatch := e.toMatch(description, spec) toMatch := e.toMatch(description, i)
if focusString != "" { if focusFilter != nil {
focusFilter := regexp.MustCompile(focusString)
matchesFocus = focusFilter.Match([]byte(toMatch)) matchesFocus = focusFilter.Match([]byte(toMatch))
} }
if skipString != "" { if skipFilter != nil {
skipFilter := regexp.MustCompile(skipString)
matchesSkip = skipFilter.Match([]byte(toMatch)) matchesSkip = skipFilter.Match([]byte(toMatch))
} }
@ -115,9 +135,10 @@ func (e *Specs) Len() int {
} }
func (e *Specs) Less(i, j int) bool { func (e *Specs) Less(i, j int) bool {
return e.specs[i].ConcatenatedString() < e.specs[j].ConcatenatedString() return e.names[i] < e.names[j]
} }
func (e *Specs) Swap(i, j int) { func (e *Specs) Swap(i, j int) {
e.names[i], e.names[j] = e.names[j], e.names[i]
e.specs[i], e.specs[j] = e.specs[j], e.specs[i] e.specs[i], e.specs[j] = e.specs[j], e.specs[i]
} }

View File

@ -175,6 +175,13 @@ func (suite *Suite) PushJustBeforeEachNode(body interface{}, codeLocation types.
suite.currentContainer.PushSetupNode(leafnodes.NewJustBeforeEachNode(body, codeLocation, timeout, suite.failer, suite.containerIndex)) suite.currentContainer.PushSetupNode(leafnodes.NewJustBeforeEachNode(body, codeLocation, timeout, suite.failer, suite.containerIndex))
} }
func (suite *Suite) PushJustAfterEachNode(body interface{}, codeLocation types.CodeLocation, timeout time.Duration) {
if suite.running {
suite.failer.Fail("You may only call JustAfterEach from within a Describe or Context", codeLocation)
}
suite.currentContainer.PushSetupNode(leafnodes.NewJustAfterEachNode(body, codeLocation, timeout, suite.failer, suite.containerIndex))
}
func (suite *Suite) PushAfterEachNode(body interface{}, codeLocation types.CodeLocation, timeout time.Duration) { func (suite *Suite) PushAfterEachNode(body interface{}, codeLocation types.CodeLocation, timeout time.Duration) {
if suite.running { if suite.running {
suite.failer.Fail("You may only call AfterEach from within a Describe, Context or When", codeLocation) suite.failer.Fail("You may only call AfterEach from within a Describe, Context or When", codeLocation)

View File

@ -121,7 +121,7 @@ func (reporter *JUnitReporter) SpecDidComplete(specSummary *types.SpecSummary) {
func (reporter *JUnitReporter) SpecSuiteDidEnd(summary *types.SuiteSummary) { func (reporter *JUnitReporter) SpecSuiteDidEnd(summary *types.SuiteSummary) {
reporter.suite.Tests = summary.NumberOfSpecsThatWillBeRun reporter.suite.Tests = summary.NumberOfSpecsThatWillBeRun
reporter.suite.Time = math.Trunc(summary.RunTime.Seconds() * 1000 / 1000) reporter.suite.Time = math.Trunc(summary.RunTime.Seconds()*1000) / 1000
reporter.suite.Failures = summary.NumberOfFailedSpecs reporter.suite.Failures = summary.NumberOfFailedSpecs
reporter.suite.Errors = 0 reporter.suite.Errors = 0
file, err := os.Create(reporter.filename) file, err := os.Create(reporter.filename)

View File

@ -159,6 +159,7 @@ const (
SpecComponentTypeAfterSuite SpecComponentTypeAfterSuite
SpecComponentTypeBeforeEach SpecComponentTypeBeforeEach
SpecComponentTypeJustBeforeEach SpecComponentTypeJustBeforeEach
SpecComponentTypeJustAfterEach
SpecComponentTypeAfterEach SpecComponentTypeAfterEach
SpecComponentTypeIt SpecComponentTypeIt
SpecComponentTypeMeasure SpecComponentTypeMeasure

View File

@ -1,16 +1,17 @@
language: go language: go
go: go:
- 1.6.x
- 1.7.x
- 1.8.x
- 1.9.x
- 1.10.x - 1.10.x
- 1.11.x - 1.11.x
- 1.12.x
env:
- GO111MODULE=on
install: install:
- env GO111MODULE=on go get -v ./... - go get -v ./...
- env GO111MODULE=on go build ./... - go build ./...
- go get github.com/onsi/ginkgo - go get github.com/onsi/ginkgo
- go install github.com/onsi/ginkgo/ginkgo - go install github.com/onsi/ginkgo/ginkgo
script: env GO111MODULE=on $HOME/gopath/bin/ginkgo -p -r --randomizeAllSpecs --failOnPending --randomizeSuites --race && env GO111MODULE=on go vet script: make test

View File

@ -1,3 +1,21 @@
## 1.5.0
### Features
- Added MatchKeys matchers [8b909fc]
### Fixes and Minor Improvements
- Add type aliases to remove stuttering [03b0461]
- Don't run session_test.go on windows (#324) [5533ce8]
## 1.4.3
### Fixes:
- ensure file name and line numbers are correctly reported for XUnit [6fff58f]
- Fixed matcher for content-type (#305) [69d9b43]
## 1.4.2 ## 1.4.2
### Fixes: ### Fixes:

6
vendor/github.com/onsi/gomega/Makefile generated vendored Normal file
View File

@ -0,0 +1,6 @@
test:
[ -z "`gofmt -s -w -l -e .`" ]
go vet
ginkgo -p -r --randomizeAllSpecs --failOnPending --randomizeSuites --race
.PHONY: test

View File

@ -8,6 +8,7 @@ import (
"net/http" "net/http"
"net/url" "net/url"
"reflect" "reflect"
"strings"
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
@ -55,6 +56,14 @@ func VerifyContentType(contentType string) http.HandlerFunc {
} }
} }
//VerifyMimeType returns a handler that verifies that a request has a specified mime type set
//in Content-Type header
func VerifyMimeType(mimeType string) http.HandlerFunc {
return func(w http.ResponseWriter, req *http.Request) {
Expect(strings.Split(req.Header.Get("Content-Type"), ";")[0]).Should(Equal(mimeType))
}
}
//VerifyBasicAuth returns a handler that verifies the request contains a BasicAuth Authorization header //VerifyBasicAuth returns a handler that verifies the request contains a BasicAuth Authorization header
//matching the passed in username and password //matching the passed in username and password
func VerifyBasicAuth(username string, password string) http.HandlerFunc { func VerifyBasicAuth(username string, password string) http.HandlerFunc {
@ -109,7 +118,7 @@ func VerifyBody(expectedBody []byte) http.HandlerFunc {
//VerifyJSON also verifies that the request's content type is application/json //VerifyJSON also verifies that the request's content type is application/json
func VerifyJSON(expectedJSON string) http.HandlerFunc { func VerifyJSON(expectedJSON string) http.HandlerFunc {
return CombineHandlers( return CombineHandlers(
VerifyContentType("application/json"), VerifyMimeType("application/json"),
func(w http.ResponseWriter, req *http.Request) { func(w http.ResponseWriter, req *http.Request) {
body, err := ioutil.ReadAll(req.Body) body, err := ioutil.ReadAll(req.Body)
req.Body.Close() req.Body.Close()

View File

@ -24,7 +24,7 @@ import (
"github.com/onsi/gomega/types" "github.com/onsi/gomega/types"
) )
const GOMEGA_VERSION = "1.4.2" const GOMEGA_VERSION = "1.5.0"
const nilFailHandlerPanic = `You are trying to make an assertion, but Gomega's fail handler is nil. const nilFailHandlerPanic = `You are trying to make an assertion, but Gomega's fail handler is nil.
If you're using Ginkgo then you probably forgot to put your assertion in an It(). If you're using Ginkgo then you probably forgot to put your assertion in an It().
@ -39,25 +39,32 @@ var defaultEventuallyPollingInterval = 10 * time.Millisecond
var defaultConsistentlyDuration = 100 * time.Millisecond var defaultConsistentlyDuration = 100 * time.Millisecond
var defaultConsistentlyPollingInterval = 10 * time.Millisecond var defaultConsistentlyPollingInterval = 10 * time.Millisecond
//RegisterFailHandler connects Ginkgo to Gomega. When a matcher fails // RegisterFailHandler connects Ginkgo to Gomega. When a matcher fails
//the fail handler passed into RegisterFailHandler is called. // the fail handler passed into RegisterFailHandler is called.
func RegisterFailHandler(handler types.GomegaFailHandler) { func RegisterFailHandler(handler types.GomegaFailHandler) {
RegisterFailHandlerWithT(testingtsupport.EmptyTWithHelper{}, handler)
}
// RegisterFailHandlerWithT ensures that the given types.TWithHelper and fail handler
// are used globally.
func RegisterFailHandlerWithT(t types.TWithHelper, handler types.GomegaFailHandler) {
if handler == nil { if handler == nil {
globalFailWrapper = nil globalFailWrapper = nil
return return
} }
globalFailWrapper = &types.GomegaFailWrapper{ globalFailWrapper = &types.GomegaFailWrapper{
Fail: handler, Fail: handler,
TWithHelper: testingtsupport.EmptyTWithHelper{}, TWithHelper: t,
} }
} }
//RegisterTestingT connects Gomega to Golang's XUnit style // RegisterTestingT connects Gomega to Golang's XUnit style
//Testing.T tests. It is now deprecated and you should use NewGomegaWithT() instead. // Testing.T tests. It is now deprecated and you should use NewWithT() instead.
// //
//Legacy Documentation: // Legacy Documentation:
// //
//You'll need to call this at the top of each XUnit style test: // You'll need to call this at the top of each XUnit style test:
// //
// func TestFarmHasCow(t *testing.T) { // func TestFarmHasCow(t *testing.T) {
// RegisterTestingT(t) // RegisterTestingT(t)
@ -70,22 +77,27 @@ func RegisterFailHandler(handler types.GomegaFailHandler) {
// pass `t` down to the matcher itself). This means that you cannot run the XUnit style tests // pass `t` down to the matcher itself). This means that you cannot run the XUnit style tests
// in parallel as the global fail handler cannot point to more than one testing.T at a time. // in parallel as the global fail handler cannot point to more than one testing.T at a time.
// //
// NewGomegaWithT() does not have this limitation // NewWithT() does not have this limitation
// //
// (As an aside: Ginkgo gets around this limitation by running parallel tests in different *processes*). // (As an aside: Ginkgo gets around this limitation by running parallel tests in different *processes*).
func RegisterTestingT(t types.GomegaTestingT) { func RegisterTestingT(t types.GomegaTestingT) {
RegisterFailHandler(testingtsupport.BuildTestingTGomegaFailWrapper(t).Fail) tWithHelper, hasHelper := t.(types.TWithHelper)
if !hasHelper {
RegisterFailHandler(testingtsupport.BuildTestingTGomegaFailWrapper(t).Fail)
return
}
RegisterFailHandlerWithT(tWithHelper, testingtsupport.BuildTestingTGomegaFailWrapper(t).Fail)
} }
//InterceptGomegaHandlers runs a given callback and returns an array of // InterceptGomegaFailures runs a given callback and returns an array of
//failure messages generated by any Gomega assertions within the callback. // failure messages generated by any Gomega assertions within the callback.
// //
//This is accomplished by temporarily replacing the *global* fail handler // This is accomplished by temporarily replacing the *global* fail handler
//with a fail handler that simply annotates failures. The original fail handler // with a fail handler that simply annotates failures. The original fail handler
//is reset when InterceptGomegaFailures returns. // is reset when InterceptGomegaFailures returns.
// //
//This is most useful when testing custom matchers, but can also be used to check // This is most useful when testing custom matchers, but can also be used to check
//on a value using a Gomega assertion without causing a test failure. // on a value using a Gomega assertion without causing a test failure.
func InterceptGomegaFailures(f func()) []string { func InterceptGomegaFailures(f func()) []string {
originalHandler := globalFailWrapper.Fail originalHandler := globalFailWrapper.Fail
failures := []string{} failures := []string{}
@ -97,108 +109,108 @@ func InterceptGomegaFailures(f func()) []string {
return failures return failures
} }
//Ω wraps an actual value allowing assertions to be made on it: // Ω wraps an actual value allowing assertions to be made on it:
// Ω("foo").Should(Equal("foo")) // Ω("foo").Should(Equal("foo"))
// //
//If Ω is passed more than one argument it will pass the *first* argument to the matcher. // If Ω is passed more than one argument it will pass the *first* argument to the matcher.
//All subsequent arguments will be required to be nil/zero. // All subsequent arguments will be required to be nil/zero.
// //
//This is convenient if you want to make an assertion on a method/function that returns // This is convenient if you want to make an assertion on a method/function that returns
//a value and an error - a common patter in Go. // a value and an error - a common patter in Go.
// //
//For example, given a function with signature: // For example, given a function with signature:
// func MyAmazingThing() (int, error) // func MyAmazingThing() (int, error)
// //
//Then: // Then:
// Ω(MyAmazingThing()).Should(Equal(3)) // Ω(MyAmazingThing()).Should(Equal(3))
//Will succeed only if `MyAmazingThing()` returns `(3, nil)` // Will succeed only if `MyAmazingThing()` returns `(3, nil)`
// //
//Ω and Expect are identical // Ω and Expect are identical
func Ω(actual interface{}, extra ...interface{}) GomegaAssertion { func Ω(actual interface{}, extra ...interface{}) Assertion {
return ExpectWithOffset(0, actual, extra...) return ExpectWithOffset(0, actual, extra...)
} }
//Expect wraps an actual value allowing assertions to be made on it: // Expect wraps an actual value allowing assertions to be made on it:
// Expect("foo").To(Equal("foo")) // Expect("foo").To(Equal("foo"))
// //
//If Expect is passed more than one argument it will pass the *first* argument to the matcher. // If Expect is passed more than one argument it will pass the *first* argument to the matcher.
//All subsequent arguments will be required to be nil/zero. // All subsequent arguments will be required to be nil/zero.
// //
//This is convenient if you want to make an assertion on a method/function that returns // This is convenient if you want to make an assertion on a method/function that returns
//a value and an error - a common patter in Go. // a value and an error - a common patter in Go.
// //
//For example, given a function with signature: // For example, given a function with signature:
// func MyAmazingThing() (int, error) // func MyAmazingThing() (int, error)
// //
//Then: // Then:
// Expect(MyAmazingThing()).Should(Equal(3)) // Expect(MyAmazingThing()).Should(Equal(3))
//Will succeed only if `MyAmazingThing()` returns `(3, nil)` // Will succeed only if `MyAmazingThing()` returns `(3, nil)`
// //
//Expect and Ω are identical // Expect and Ω are identical
func Expect(actual interface{}, extra ...interface{}) GomegaAssertion { func Expect(actual interface{}, extra ...interface{}) Assertion {
return ExpectWithOffset(0, actual, extra...) return ExpectWithOffset(0, actual, extra...)
} }
//ExpectWithOffset wraps an actual value allowing assertions to be made on it: // ExpectWithOffset wraps an actual value allowing assertions to be made on it:
// ExpectWithOffset(1, "foo").To(Equal("foo")) // ExpectWithOffset(1, "foo").To(Equal("foo"))
// //
//Unlike `Expect` and `Ω`, `ExpectWithOffset` takes an additional integer argument // Unlike `Expect` and `Ω`, `ExpectWithOffset` takes an additional integer argument
//this is used to modify the call-stack offset when computing line numbers. // this is used to modify the call-stack offset when computing line numbers.
// //
//This is most useful in helper functions that make assertions. If you want Gomega's // This is most useful in helper functions that make assertions. If you want Gomega's
//error message to refer to the calling line in the test (as opposed to the line in the helper function) // error message to refer to the calling line in the test (as opposed to the line in the helper function)
//set the first argument of `ExpectWithOffset` appropriately. // set the first argument of `ExpectWithOffset` appropriately.
func ExpectWithOffset(offset int, actual interface{}, extra ...interface{}) GomegaAssertion { func ExpectWithOffset(offset int, actual interface{}, extra ...interface{}) Assertion {
if globalFailWrapper == nil { if globalFailWrapper == nil {
panic(nilFailHandlerPanic) panic(nilFailHandlerPanic)
} }
return assertion.New(actual, globalFailWrapper, offset, extra...) return assertion.New(actual, globalFailWrapper, offset, extra...)
} }
//Eventually wraps an actual value allowing assertions to be made on it. // Eventually wraps an actual value allowing assertions to be made on it.
//The assertion is tried periodically until it passes or a timeout occurs. // The assertion is tried periodically until it passes or a timeout occurs.
// //
//Both the timeout and polling interval are configurable as optional arguments: // Both the timeout and polling interval are configurable as optional arguments:
//The first optional argument is the timeout // The first optional argument is the timeout
//The second optional argument is the polling interval // The second optional argument is the polling interval
// //
//Both intervals can either be specified as time.Duration, parsable duration strings or as floats/integers. In the // Both intervals can either be specified as time.Duration, parsable duration strings or as floats/integers. In the
//last case they are interpreted as seconds. // last case they are interpreted as seconds.
// //
//If Eventually is passed an actual that is a function taking no arguments and returning at least one value, // If Eventually is passed an actual that is a function taking no arguments and returning at least one value,
//then Eventually will call the function periodically and try the matcher against the function's first return value. // then Eventually will call the function periodically and try the matcher against the function's first return value.
// //
//Example: // Example:
// //
// Eventually(func() int { // Eventually(func() int {
// return thingImPolling.Count() // return thingImPolling.Count()
// }).Should(BeNumerically(">=", 17)) // }).Should(BeNumerically(">=", 17))
// //
//Note that this example could be rewritten: // Note that this example could be rewritten:
// //
// Eventually(thingImPolling.Count).Should(BeNumerically(">=", 17)) // Eventually(thingImPolling.Count).Should(BeNumerically(">=", 17))
// //
//If the function returns more than one value, then Eventually will pass the first value to the matcher and // If the function returns more than one value, then Eventually will pass the first value to the matcher and
//assert that all other values are nil/zero. // assert that all other values are nil/zero.
//This allows you to pass Eventually a function that returns a value and an error - a common pattern in Go. // This allows you to pass Eventually a function that returns a value and an error - a common pattern in Go.
// //
//For example, consider a method that returns a value and an error: // For example, consider a method that returns a value and an error:
// func FetchFromDB() (string, error) // func FetchFromDB() (string, error)
// //
//Then // Then
// Eventually(FetchFromDB).Should(Equal("hasselhoff")) // Eventually(FetchFromDB).Should(Equal("hasselhoff"))
// //
//Will pass only if the the returned error is nil and the returned string passes the matcher. // Will pass only if the the returned error is nil and the returned string passes the matcher.
// //
//Eventually's default timeout is 1 second, and its default polling interval is 10ms // Eventually's default timeout is 1 second, and its default polling interval is 10ms
func Eventually(actual interface{}, intervals ...interface{}) GomegaAsyncAssertion { func Eventually(actual interface{}, intervals ...interface{}) AsyncAssertion {
return EventuallyWithOffset(0, actual, intervals...) return EventuallyWithOffset(0, actual, intervals...)
} }
//EventuallyWithOffset operates like Eventually but takes an additional // EventuallyWithOffset operates like Eventually but takes an additional
//initial argument to indicate an offset in the call stack. This is useful when building helper // initial argument to indicate an offset in the call stack. This is useful when building helper
//functions that contain matchers. To learn more, read about `ExpectWithOffset`. // functions that contain matchers. To learn more, read about `ExpectWithOffset`.
func EventuallyWithOffset(offset int, actual interface{}, intervals ...interface{}) GomegaAsyncAssertion { func EventuallyWithOffset(offset int, actual interface{}, intervals ...interface{}) AsyncAssertion {
if globalFailWrapper == nil { if globalFailWrapper == nil {
panic(nilFailHandlerPanic) panic(nilFailHandlerPanic)
} }
@ -213,37 +225,37 @@ func EventuallyWithOffset(offset int, actual interface{}, intervals ...interface
return asyncassertion.New(asyncassertion.AsyncAssertionTypeEventually, actual, globalFailWrapper, timeoutInterval, pollingInterval, offset) return asyncassertion.New(asyncassertion.AsyncAssertionTypeEventually, actual, globalFailWrapper, timeoutInterval, pollingInterval, offset)
} }
//Consistently wraps an actual value allowing assertions to be made on it. // Consistently wraps an actual value allowing assertions to be made on it.
//The assertion is tried periodically and is required to pass for a period of time. // The assertion is tried periodically and is required to pass for a period of time.
// //
//Both the total time and polling interval are configurable as optional arguments: // Both the total time and polling interval are configurable as optional arguments:
//The first optional argument is the duration that Consistently will run for // The first optional argument is the duration that Consistently will run for
//The second optional argument is the polling interval // The second optional argument is the polling interval
// //
//Both intervals can either be specified as time.Duration, parsable duration strings or as floats/integers. In the // Both intervals can either be specified as time.Duration, parsable duration strings or as floats/integers. In the
//last case they are interpreted as seconds. // last case they are interpreted as seconds.
// //
//If Consistently is passed an actual that is a function taking no arguments and returning at least one value, // If Consistently is passed an actual that is a function taking no arguments and returning at least one value,
//then Consistently will call the function periodically and try the matcher against the function's first return value. // then Consistently will call the function periodically and try the matcher against the function's first return value.
// //
//If the function returns more than one value, then Consistently will pass the first value to the matcher and // If the function returns more than one value, then Consistently will pass the first value to the matcher and
//assert that all other values are nil/zero. // assert that all other values are nil/zero.
//This allows you to pass Consistently a function that returns a value and an error - a common pattern in Go. // This allows you to pass Consistently a function that returns a value and an error - a common pattern in Go.
// //
//Consistently is useful in cases where you want to assert that something *does not happen* over a period of tiem. // Consistently is useful in cases where you want to assert that something *does not happen* over a period of tiem.
//For example, you want to assert that a goroutine does *not* send data down a channel. In this case, you could: // For example, you want to assert that a goroutine does *not* send data down a channel. In this case, you could:
// //
// Consistently(channel).ShouldNot(Receive()) // Consistently(channel).ShouldNot(Receive())
// //
//Consistently's default duration is 100ms, and its default polling interval is 10ms // Consistently's default duration is 100ms, and its default polling interval is 10ms
func Consistently(actual interface{}, intervals ...interface{}) GomegaAsyncAssertion { func Consistently(actual interface{}, intervals ...interface{}) AsyncAssertion {
return ConsistentlyWithOffset(0, actual, intervals...) return ConsistentlyWithOffset(0, actual, intervals...)
} }
//ConsistentlyWithOffset operates like Consistnetly but takes an additional // ConsistentlyWithOffset operates like Consistnetly but takes an additional
//initial argument to indicate an offset in the call stack. This is useful when building helper // initial argument to indicate an offset in the call stack. This is useful when building helper
//functions that contain matchers. To learn more, read about `ExpectWithOffset`. // functions that contain matchers. To learn more, read about `ExpectWithOffset`.
func ConsistentlyWithOffset(offset int, actual interface{}, intervals ...interface{}) GomegaAsyncAssertion { func ConsistentlyWithOffset(offset int, actual interface{}, intervals ...interface{}) AsyncAssertion {
if globalFailWrapper == nil { if globalFailWrapper == nil {
panic(nilFailHandlerPanic) panic(nilFailHandlerPanic)
} }
@ -258,59 +270,62 @@ func ConsistentlyWithOffset(offset int, actual interface{}, intervals ...interfa
return asyncassertion.New(asyncassertion.AsyncAssertionTypeConsistently, actual, globalFailWrapper, timeoutInterval, pollingInterval, offset) return asyncassertion.New(asyncassertion.AsyncAssertionTypeConsistently, actual, globalFailWrapper, timeoutInterval, pollingInterval, offset)
} }
//Set the default timeout duration for Eventually. Eventually will repeatedly poll your condition until it succeeds, or until this timeout elapses. // SetDefaultEventuallyTimeout sets the default timeout duration for Eventually. Eventually will repeatedly poll your condition until it succeeds, or until this timeout elapses.
func SetDefaultEventuallyTimeout(t time.Duration) { func SetDefaultEventuallyTimeout(t time.Duration) {
defaultEventuallyTimeout = t defaultEventuallyTimeout = t
} }
//Set the default polling interval for Eventually. // SetDefaultEventuallyPollingInterval sets the default polling interval for Eventually.
func SetDefaultEventuallyPollingInterval(t time.Duration) { func SetDefaultEventuallyPollingInterval(t time.Duration) {
defaultEventuallyPollingInterval = t defaultEventuallyPollingInterval = t
} }
//Set the default duration for Consistently. Consistently will verify that your condition is satsified for this long. // SetDefaultConsistentlyDuration sets the default duration for Consistently. Consistently will verify that your condition is satsified for this long.
func SetDefaultConsistentlyDuration(t time.Duration) { func SetDefaultConsistentlyDuration(t time.Duration) {
defaultConsistentlyDuration = t defaultConsistentlyDuration = t
} }
//Set the default polling interval for Consistently. // SetDefaultConsistentlyPollingInterval sets the default polling interval for Consistently.
func SetDefaultConsistentlyPollingInterval(t time.Duration) { func SetDefaultConsistentlyPollingInterval(t time.Duration) {
defaultConsistentlyPollingInterval = t defaultConsistentlyPollingInterval = t
} }
//GomegaAsyncAssertion is returned by Eventually and Consistently and polls the actual value passed into Eventually against // AsyncAssertion is returned by Eventually and Consistently and polls the actual value passed into Eventually against
//the matcher passed to the Should and ShouldNot methods. // the matcher passed to the Should and ShouldNot methods.
// //
//Both Should and ShouldNot take a variadic optionalDescription argument. This is passed on to // Both Should and ShouldNot take a variadic optionalDescription argument. This is passed on to
//fmt.Sprintf() and is used to annotate failure messages. This allows you to make your failure messages more // fmt.Sprintf() and is used to annotate failure messages. This allows you to make your failure messages more
//descriptive // descriptive.
// //
//Both Should and ShouldNot return a boolean that is true if the assertion passed and false if it failed. // Both Should and ShouldNot return a boolean that is true if the assertion passed and false if it failed.
// //
//Example: // Example:
// //
// Eventually(myChannel).Should(Receive(), "Something should have come down the pipe.") // Eventually(myChannel).Should(Receive(), "Something should have come down the pipe.")
// Consistently(myChannel).ShouldNot(Receive(), "Nothing should have come down the pipe.") // Consistently(myChannel).ShouldNot(Receive(), "Nothing should have come down the pipe.")
type GomegaAsyncAssertion interface { type AsyncAssertion interface {
Should(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool Should(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool
ShouldNot(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool ShouldNot(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool
} }
//GomegaAssertion is returned by Ω and Expect and compares the actual value to the matcher // GomegaAsyncAssertion is deprecated in favor of AsyncAssertion, which does not stutter.
//passed to the Should/ShouldNot and To/ToNot/NotTo methods. type GomegaAsyncAssertion = AsyncAssertion
// Assertion is returned by Ω and Expect and compares the actual value to the matcher
// passed to the Should/ShouldNot and To/ToNot/NotTo methods.
// //
//Typically Should/ShouldNot are used with Ω and To/ToNot/NotTo are used with Expect // Typically Should/ShouldNot are used with Ω and To/ToNot/NotTo are used with Expect
//though this is not enforced. // though this is not enforced.
// //
//All methods take a variadic optionalDescription argument. This is passed on to fmt.Sprintf() // All methods take a variadic optionalDescription argument. This is passed on to fmt.Sprintf()
//and is used to annotate failure messages. // and is used to annotate failure messages.
// //
//All methods return a bool that is true if hte assertion passed and false if it failed. // All methods return a bool that is true if hte assertion passed and false if it failed.
// //
//Example: // Example:
// //
// Ω(farm.HasCow()).Should(BeTrue(), "Farm %v should have a cow", farm) // Ω(farm.HasCow()).Should(BeTrue(), "Farm %v should have a cow", farm)
type GomegaAssertion interface { type Assertion interface {
Should(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool Should(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool
ShouldNot(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool ShouldNot(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool
@ -319,39 +334,50 @@ type GomegaAssertion interface {
NotTo(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool NotTo(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool
} }
//OmegaMatcher is deprecated in favor of the better-named and better-organized types.GomegaMatcher but sticks around to support existing code that uses it // GomegaAssertion is deprecated in favor of Assertion, which does not stutter.
type GomegaAssertion = Assertion
// OmegaMatcher is deprecated in favor of the better-named and better-organized types.GomegaMatcher but sticks around to support existing code that uses it
type OmegaMatcher types.GomegaMatcher type OmegaMatcher types.GomegaMatcher
//GomegaWithT wraps a *testing.T and provides `Expect`, `Eventually`, and `Consistently` methods. This allows you to leverage // WithT wraps a *testing.T and provides `Expect`, `Eventually`, and `Consistently` methods. This allows you to leverage
//Gomega's rich ecosystem of matchers in standard `testing` test suites. // Gomega's rich ecosystem of matchers in standard `testing` test suites.
// //
//Use `NewGomegaWithT` to instantiate a `GomegaWithT` // Use `NewWithT` to instantiate a `WithT`
type GomegaWithT struct { type WithT struct {
t types.GomegaTestingT t types.GomegaTestingT
} }
//NewGomegaWithT takes a *testing.T and returngs a `GomegaWithT` allowing you to use `Expect`, `Eventually`, and `Consistently` along with // GomegaWithT is deprecated in favor of gomega.WithT, which does not stutter.
//Gomega's rich ecosystem of matchers in standard `testing` test suits. type GomegaWithT = WithT
// NewWithT takes a *testing.T and returngs a `gomega.WithT` allowing you to use `Expect`, `Eventually`, and `Consistently` along with
// Gomega's rich ecosystem of matchers in standard `testing` test suits.
// //
// func TestFarmHasCow(t *testing.T) { // func TestFarmHasCow(t *testing.T) {
// g := GomegaWithT(t) // g := gomega.NewWithT(t)
// //
// f := farm.New([]string{"Cow", "Horse"}) // f := farm.New([]string{"Cow", "Horse"})
// g.Expect(f.HasCow()).To(BeTrue(), "Farm should have cow") // g.Expect(f.HasCow()).To(BeTrue(), "Farm should have cow")
// } // }
func NewGomegaWithT(t types.GomegaTestingT) *GomegaWithT { func NewWithT(t types.GomegaTestingT) *WithT {
return &GomegaWithT{ return &WithT{
t: t, t: t,
} }
} }
//See documentation for Expect // NewGomegaWithT is deprecated in favor of gomega.NewWithT, which does not stutter.
func (g *GomegaWithT) Expect(actual interface{}, extra ...interface{}) GomegaAssertion { func NewGomegaWithT(t types.GomegaTestingT) *GomegaWithT {
return NewWithT(t)
}
// Expect is used to make assertions. See documentation for Expect.
func (g *WithT) Expect(actual interface{}, extra ...interface{}) Assertion {
return assertion.New(actual, testingtsupport.BuildTestingTGomegaFailWrapper(g.t), 0, extra...) return assertion.New(actual, testingtsupport.BuildTestingTGomegaFailWrapper(g.t), 0, extra...)
} }
//See documentation for Eventually // Eventually is used to make asynchronous assertions. See documentation for Eventually.
func (g *GomegaWithT) Eventually(actual interface{}, intervals ...interface{}) GomegaAsyncAssertion { func (g *WithT) Eventually(actual interface{}, intervals ...interface{}) AsyncAssertion {
timeoutInterval := defaultEventuallyTimeout timeoutInterval := defaultEventuallyTimeout
pollingInterval := defaultEventuallyPollingInterval pollingInterval := defaultEventuallyPollingInterval
if len(intervals) > 0 { if len(intervals) > 0 {
@ -363,8 +389,8 @@ func (g *GomegaWithT) Eventually(actual interface{}, intervals ...interface{}) G
return asyncassertion.New(asyncassertion.AsyncAssertionTypeEventually, actual, testingtsupport.BuildTestingTGomegaFailWrapper(g.t), timeoutInterval, pollingInterval, 0) return asyncassertion.New(asyncassertion.AsyncAssertionTypeEventually, actual, testingtsupport.BuildTestingTGomegaFailWrapper(g.t), timeoutInterval, pollingInterval, 0)
} }
//See documentation for Consistently // Consistently is used to make asynchronous assertions. See documentation for Consistently.
func (g *GomegaWithT) Consistently(actual interface{}, intervals ...interface{}) GomegaAsyncAssertion { func (g *WithT) Consistently(actual interface{}, intervals ...interface{}) AsyncAssertion {
timeoutInterval := defaultConsistentlyDuration timeoutInterval := defaultConsistentlyDuration
pollingInterval := defaultConsistentlyPollingInterval pollingInterval := defaultConsistentlyPollingInterval
if len(intervals) > 0 { if len(intervals) > 0 {

View File

@ -23,8 +23,8 @@ func (matcher *BeClosedMatcher) Match(actual interface{}) (success bool, err err
} }
winnerIndex, _, open := reflect.Select([]reflect.SelectCase{ winnerIndex, _, open := reflect.Select([]reflect.SelectCase{
reflect.SelectCase{Dir: reflect.SelectRecv, Chan: channelValue}, {Dir: reflect.SelectRecv, Chan: channelValue},
reflect.SelectCase{Dir: reflect.SelectDefault}, {Dir: reflect.SelectDefault},
}) })
var closed bool var closed bool

View File

@ -42,8 +42,8 @@ func (matcher *BeSentMatcher) Match(actual interface{}) (success bool, err error
}() }()
winnerIndex, _, _ := reflect.Select([]reflect.SelectCase{ winnerIndex, _, _ := reflect.Select([]reflect.SelectCase{
reflect.SelectCase{Dir: reflect.SelectSend, Chan: channelValue, Send: argValue}, {Dir: reflect.SelectSend, Chan: channelValue, Send: argValue},
reflect.SelectCase{Dir: reflect.SelectDefault}, {Dir: reflect.SelectDefault},
}) })
var didSend bool var didSend bool

View File

@ -29,5 +29,5 @@ func (matcher *HaveOccurredMatcher) FailureMessage(actual interface{}) (message
} }
func (matcher *HaveOccurredMatcher) NegatedFailureMessage(actual interface{}) (message string) { func (matcher *HaveOccurredMatcher) NegatedFailureMessage(actual interface{}) (message string) {
return fmt.Sprintf("Expected error:\n%s\n%s\n%s", format.Object(actual, 1), format.IndentString(actual.(error).Error(), 1), "not to have occurred") return fmt.Sprintf("Unexpected error:\n%s\n%s\n%s", format.Object(actual, 1), format.IndentString(actual.(error).Error(), 1), "occurred")
} }

View File

@ -70,7 +70,7 @@ func parseXmlContent(content string) (*xmlNode, error) {
if err == io.EOF { if err == io.EOF {
break break
} }
return nil, fmt.Errorf("failed to decode next token: %v", err) return nil, fmt.Errorf("failed to decode next token: %v", err) // untested section
} }
lastNodeIndex := len(allNodes) - 1 lastNodeIndex := len(allNodes) - 1
@ -94,7 +94,7 @@ func parseXmlContent(content string) (*xmlNode, error) {
case xml.CharData: case xml.CharData:
lastNode.Content = append(lastNode.Content, tok.Copy()...) lastNode.Content = append(lastNode.Content, tok.Copy()...)
case xml.Comment: case xml.Comment:
lastNode.Comments = append(lastNode.Comments, tok.Copy()) lastNode.Comments = append(lastNode.Comments, tok.Copy()) // untested section
case xml.ProcInst: case xml.ProcInst:
lastNode.ProcInsts = append(lastNode.ProcInsts, tok.Copy()) lastNode.ProcInsts = append(lastNode.ProcInsts, tok.Copy())
} }

View File

@ -53,11 +53,11 @@ func normalise(input string) string {
var val interface{} var val interface{}
err := yaml.Unmarshal([]byte(input), &val) err := yaml.Unmarshal([]byte(input), &val)
if err != nil { if err != nil {
panic(err) // guarded by Match panic(err) // unreachable since Match already calls Unmarshal
} }
output, err := yaml.Marshal(val) output, err := yaml.Marshal(val)
if err != nil { if err != nil {
panic(err) // guarded by Unmarshal panic(err) // untested section, unreachable since we Unmarshal above
} }
return strings.TrimSpace(string(output)) return strings.TrimSpace(string(output))
} }

View File

@ -39,8 +39,8 @@ func (matcher *ReceiveMatcher) Match(actual interface{}) (success bool, err erro
} }
winnerIndex, value, open := reflect.Select([]reflect.SelectCase{ winnerIndex, value, open := reflect.Select([]reflect.SelectCase{
reflect.SelectCase{Dir: reflect.SelectRecv, Chan: channelValue}, {Dir: reflect.SelectRecv, Chan: channelValue},
reflect.SelectCase{Dir: reflect.SelectDefault}, {Dir: reflect.SelectDefault},
}) })
var closed bool var closed bool

View File

@ -14,12 +14,12 @@ type BipartiteGraph struct {
func NewBipartiteGraph(leftValues, rightValues []interface{}, neighbours func(interface{}, interface{}) (bool, error)) (*BipartiteGraph, error) { func NewBipartiteGraph(leftValues, rightValues []interface{}, neighbours func(interface{}, interface{}) (bool, error)) (*BipartiteGraph, error) {
left := NodeOrderedSet{} left := NodeOrderedSet{}
for i, _ := range leftValues { for i := range leftValues {
left = append(left, Node{Id: i}) left = append(left, Node{Id: i})
} }
right := NodeOrderedSet{} right := NodeOrderedSet{}
for j, _ := range rightValues { for j := range rightValues {
right = append(right, Node{Id: j + len(left)}) right = append(right, Node{Id: j + len(left)})
} }

2
vendor/github.com/pelletier/go-toml/.dockerignore generated vendored Normal file
View File

@ -0,0 +1,2 @@
cmd/tomll/tomll
cmd/tomljson/tomljson

View File

@ -1,2 +1,5 @@
test_program/test_program_bin test_program/test_program_bin
fuzz/ fuzz/
cmd/tomll/tomll
cmd/tomljson/tomljson
cmd/tomltestgen/tomltestgen

View File

@ -1,23 +1,22 @@
sudo: false sudo: false
language: go language: go
go: go:
- 1.8.x - 1.11.x
- 1.9.x - 1.12.x
- 1.10.x
- tip - tip
matrix: matrix:
allow_failures: allow_failures:
- go: tip - go: tip
fast_finish: true fast_finish: true
env:
- GO111MODULE=on
script: script:
- if [ -n "$(go fmt ./...)" ]; then exit 1; fi - if [ -n "$(go fmt ./...)" ]; then exit 1; fi
- ./test.sh - go test github.com/pelletier/go-toml -race -coverprofile=coverage.txt -covermode=atomic
- go test github.com/pelletier/go-toml/cmd/tomljson
- go test github.com/pelletier/go-toml/cmd/tomll
- go test github.com/pelletier/go-toml/query
- ./benchmark.sh $TRAVIS_BRANCH https://github.com/$TRAVIS_REPO_SLUG.git - ./benchmark.sh $TRAVIS_BRANCH https://github.com/$TRAVIS_REPO_SLUG.git
before_install:
- go get github.com/axw/gocov/gocov
- go get github.com/mattn/goveralls
- if ! go get code.google.com/p/go.tools/cmd/cover; then go get golang.org/x/tools/cmd/cover; fi
branches:
only: [master]
after_success: after_success:
- $HOME/gopath/bin/goveralls -service=travis-ci -coverprofile=coverage.out -repotoken $COVERALLS_TOKEN - bash <(curl -s https://codecov.io/bash)

132
vendor/github.com/pelletier/go-toml/CONTRIBUTING.md generated vendored Normal file
View File

@ -0,0 +1,132 @@
## Contributing
Thank you for your interest in go-toml! We appreciate you considering
contributing to go-toml!
The main goal is the project is to provide an easy-to-use TOML
implementation for Go that gets the job done and gets out of your way
dealing with TOML is probably not the central piece of your project.
As the single maintainer of go-toml, time is scarce. All help, big or
small, is more than welcomed!
### Ask questions
Any question you may have, somebody else might have it too. Always feel
free to ask them on the [issues tracker][issues-tracker]. We will try to
answer them as clearly and quickly as possible, time permitting.
Asking questions also helps us identify areas where the documentation needs
improvement, or new features that weren't envisioned before. Sometimes, a
seemingly innocent question leads to the fix of a bug. Don't hesitate and
ask away!
### Improve the documentation
The best way to share your knowledge and experience with go-toml is to
improve the documentation. Fix a typo, clarify an interface, add an
example, anything goes!
The documentation is present in the [README][readme] and thorough the
source code. On release, it gets updated on [GoDoc][godoc]. To make a
change to the documentation, create a pull request with your proposed
changes. For simple changes like that, the easiest way to go is probably
the "Fork this project and edit the file" button on Github, displayed at
the top right of the file. Unless it's a trivial change (for example a
typo), provide a little bit of context in your pull request description or
commit message.
### Report a bug
Found a bug! Sorry to hear that :(. Help us and other track them down and
fix by reporting it. [File a new bug report][bug-report] on the [issues
tracker][issues-tracker]. The template should provide enough guidance on
what to include. When in doubt: add more details! By reducing ambiguity and
providing more information, it decreases back and forth and saves everyone
time.
### Code changes
Want to contribute a patch? Very happy to hear that!
First, some high-level rules:
* A short proposal with some POC code is better than a lengthy piece of
text with no code. Code speaks louder than words.
* No backward-incompatible patch will be accepted unless discussed.
Sometimes it's hard, and Go's lack of versioning by default does not
help, but we try not to break people's programs unless we absolutely have
to.
* If you are writing a new feature or extending an existing one, make sure
to write some documentation.
* Bug fixes need to be accompanied with regression tests.
* New code needs to be tested.
* Your commit messages need to explain why the change is needed, even if
already included in the PR description.
It does sound like a lot, but those best practices are here to save time
overall and continuously improve the quality of the project, which is
something everyone benefits from.
#### Get started
The fairly standard code contribution process looks like that:
1. [Fork the project][fork].
2. Make your changes, commit on any branch you like.
3. [Open up a pull request][pull-request]
4. Review, potential ask for changes.
5. Merge. You're in!
Feel free to ask for help! You can create draft pull requests to gather
some early feedback!
#### Run the tests
You can run tests for go-toml using Go's test tool: `go test ./...`.
When creating a pull requests, all tests will be ran on Linux on a few Go
versions (Travis CI), and on Windows using the latest Go version
(AppVeyor).
#### Style
Try to look around and follow the same format and structure as the rest of
the code. We enforce using `go fmt` on the whole code base.
---
### Maintainers-only
#### Merge pull request
Checklist:
* Passing CI.
* Does not introduce backward-incompatible changes (unless discussed).
* Has relevant doc changes.
* Has relevant unit tests.
1. Merge using "squash and merge".
2. Make sure to edit the commit message to keep all the useful information
nice and clean.
3. Make sure the commit title is clear and contains the PR number (#123).
#### New release
1. Go to [releases][releases]. Click on "X commits to master since this
release".
2. Make note of all the changes. Look for backward incompatible changes,
new features, and bug fixes.
3. Pick the new version using the above and semver.
4. Create a [new release][new-release].
5. Follow the same format as [1.1.0][release-110].
[issues-tracker]: https://github.com/pelletier/go-toml/issues
[bug-report]: https://github.com/pelletier/go-toml/issues/new?template=bug_report.md
[godoc]: https://godoc.org/github.com/pelletier/go-toml
[readme]: ./README.md
[fork]: https://help.github.com/articles/fork-a-repo
[pull-request]: https://help.github.com/en/articles/creating-a-pull-request
[releases]: https://github.com/pelletier/go-toml/releases
[new-release]: https://github.com/pelletier/go-toml/releases/new
[release-110]: https://github.com/pelletier/go-toml/releases/tag/v1.1.0

10
vendor/github.com/pelletier/go-toml/Dockerfile generated vendored Normal file
View File

@ -0,0 +1,10 @@
FROM golang:1.12-alpine3.9 as builder
WORKDIR /go/src/github.com/pelletier/go-toml
COPY . .
ENV CGO_ENABLED=0
ENV GOOS=linux
RUN go install ./...
FROM scratch
COPY --from=builder /go/bin/tomll /usr/bin/tomll
COPY --from=builder /go/bin/tomljson /usr/bin/tomljson

View File

@ -0,0 +1,5 @@
**Issue:** add link to pelletier/go-toml issue here
Explanation of what this pull request does.
More detailed description of the decisions being made and the reasons why (if the patch is non-trivial).

View File

@ -8,8 +8,10 @@ This library supports TOML version
[![GoDoc](https://godoc.org/github.com/pelletier/go-toml?status.svg)](http://godoc.org/github.com/pelletier/go-toml) [![GoDoc](https://godoc.org/github.com/pelletier/go-toml?status.svg)](http://godoc.org/github.com/pelletier/go-toml)
[![license](https://img.shields.io/github/license/pelletier/go-toml.svg)](https://github.com/pelletier/go-toml/blob/master/LICENSE) [![license](https://img.shields.io/github/license/pelletier/go-toml.svg)](https://github.com/pelletier/go-toml/blob/master/LICENSE)
[![Build Status](https://travis-ci.org/pelletier/go-toml.svg?branch=master)](https://travis-ci.org/pelletier/go-toml) [![Build Status](https://travis-ci.org/pelletier/go-toml.svg?branch=master)](https://travis-ci.org/pelletier/go-toml)
[![Coverage Status](https://coveralls.io/repos/github/pelletier/go-toml/badge.svg?branch=master)](https://coveralls.io/github/pelletier/go-toml?branch=master) [![Windows Build status](https://ci.appveyor.com/api/projects/status/4aepwwjori266hkt/branch/master?svg=true)](https://ci.appveyor.com/project/pelletier/go-toml/branch/master)
[![codecov](https://codecov.io/gh/pelletier/go-toml/branch/master/graph/badge.svg)](https://codecov.io/gh/pelletier/go-toml)
[![Go Report Card](https://goreportcard.com/badge/github.com/pelletier/go-toml)](https://goreportcard.com/report/github.com/pelletier/go-toml) [![Go Report Card](https://goreportcard.com/badge/github.com/pelletier/go-toml)](https://goreportcard.com/report/github.com/pelletier/go-toml)
[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fpelletier%2Fgo-toml.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fpelletier%2Fgo-toml?ref=badge_shield)
## Features ## Features
@ -99,6 +101,23 @@ Go-toml provides two handy command line tools:
tomljson --help tomljson --help
``` ```
### Docker image
Those tools are also availble as a Docker image from
[dockerhub](https://hub.docker.com/r/pelletier/go-toml). For example, to
use `tomljson`:
```
docker run -v $PWD:/workdir pelletier/go-toml tomljson /workdir/example.toml
```
Only master (`latest`) and tagged versions are published to dockerhub. You
can build your own image as usual:
```
docker build -t go-toml .
```
## Contribute ## Contribute
Feel free to report bugs and patches using GitHub's pull requests system on Feel free to report bugs and patches using GitHub's pull requests system on
@ -107,12 +126,7 @@ much appreciated!
### Run tests ### Run tests
You have to make sure two kind of tests run: `go test ./...`
1. The Go unit tests
2. The TOML examples base
You can run both of them using `./test.sh`.
### Fuzzing ### Fuzzing

34
vendor/github.com/pelletier/go-toml/appveyor.yml generated vendored Normal file
View File

@ -0,0 +1,34 @@
version: "{build}"
# Source Config
clone_folder: c:\gopath\src\github.com\pelletier\go-toml
# Build host
environment:
GOPATH: c:\gopath
DEPTESTBYPASS501: 1
GOVERSION: 1.12
GO111MODULE: on
init:
- git config --global core.autocrlf input
# Build
install:
# Install the specific Go version.
- rmdir c:\go /s /q
- appveyor DownloadFile https://storage.googleapis.com/golang/go%GOVERSION%.windows-amd64.msi
- msiexec /i go%GOVERSION%.windows-amd64.msi /q
- choco install bzr
- set Path=c:\go\bin;c:\gopath\bin;C:\Program Files (x86)\Bazaar\;C:\Program Files\Mercurial\%Path%
- go version
- go env
build: false
deploy: false
test_script:
- go test github.com/pelletier/go-toml
- go test github.com/pelletier/go-toml/cmd/tomljson
- go test github.com/pelletier/go-toml/cmd/tomll
- go test github.com/pelletier/go-toml/query

9
vendor/github.com/pelletier/go-toml/go.mod generated vendored Normal file
View File

@ -0,0 +1,9 @@
module github.com/pelletier/go-toml
go 1.12
require (
github.com/BurntSushi/toml v0.3.1
github.com/davecgh/go-spew v1.1.1
gopkg.in/yaml.v2 v2.2.2
)

7
vendor/github.com/pelletier/go-toml/go.sum generated vendored Normal file
View File

@ -0,0 +1,7 @@
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

View File

@ -3,79 +3,107 @@
package toml package toml
import ( import (
"bytes"
"errors" "errors"
"fmt" "fmt"
"unicode" "unicode"
) )
// Convert the bare key group string to an array. // Convert the bare key group string to an array.
// The input supports double quotation to allow "." inside the key name, // The input supports double quotation and single quotation,
// but escape sequences are not supported. Lexers must unescape them beforehand. // but escape sequences are not supported. Lexers must unescape them beforehand.
func parseKey(key string) ([]string, error) { func parseKey(key string) ([]string, error) {
groups := []string{} runes := []rune(key)
var buffer bytes.Buffer var groups []string
inQuotes := false
wasInQuotes := false
ignoreSpace := true
expectDot := false
for _, char := range key { if len(key) == 0 {
if ignoreSpace { return nil, errors.New("empty key")
if char == ' ' { }
continue
} idx := 0
ignoreSpace = false for idx < len(runes) {
for ; idx < len(runes) && isSpace(runes[idx]); idx++ {
// skip leading whitespace
} }
switch char { if idx >= len(runes) {
case '"': break
if inQuotes { }
groups = append(groups, buffer.String()) r := runes[idx]
buffer.Reset() if isValidBareChar(r) {
wasInQuotes = true // parse bare key
} startIdx := idx
inQuotes = !inQuotes endIdx := -1
expectDot = false idx++
case '.': for idx < len(runes) {
if inQuotes { r = runes[idx]
buffer.WriteRune(char) if isValidBareChar(r) {
} else { idx++
if !wasInQuotes { } else if r == '.' {
if buffer.Len() == 0 { endIdx = idx
return nil, errors.New("empty table key") break
} else if isSpace(r) {
endIdx = idx
for ; idx < len(runes) && isSpace(runes[idx]); idx++ {
// skip trailing whitespace
} }
groups = append(groups, buffer.String()) if idx < len(runes) && runes[idx] != '.' {
buffer.Reset() return nil, fmt.Errorf("invalid key character after whitespace: %c", runes[idx])
}
break
} else {
return nil, fmt.Errorf("invalid bare key character: %c", r)
} }
ignoreSpace = true
expectDot = false
wasInQuotes = false
} }
case ' ': if endIdx == -1 {
if inQuotes { endIdx = idx
buffer.WriteRune(char)
} else {
expectDot = true
} }
default: groups = append(groups, string(runes[startIdx:endIdx]))
if !inQuotes && !isValidBareChar(char) { } else if r == '\'' {
return nil, fmt.Errorf("invalid bare character: %c", char) // parse single quoted key
idx++
startIdx := idx
for {
if idx >= len(runes) {
return nil, fmt.Errorf("unclosed single-quoted key")
}
r = runes[idx]
if r == '\'' {
groups = append(groups, string(runes[startIdx:idx]))
idx++
break
}
idx++
} }
if !inQuotes && expectDot { } else if r == '"' {
return nil, errors.New("what?") // parse double quoted key
idx++
startIdx := idx
for {
if idx >= len(runes) {
return nil, fmt.Errorf("unclosed double-quoted key")
}
r = runes[idx]
if r == '"' {
groups = append(groups, string(runes[startIdx:idx]))
idx++
break
}
idx++
} }
buffer.WriteRune(char) } else if r == '.' {
expectDot = false idx++
if idx >= len(runes) {
return nil, fmt.Errorf("unexpected end of key")
}
r = runes[idx]
if !isValidBareChar(r) && r != '\'' && r != '"' && r != ' ' {
return nil, fmt.Errorf("expecting key part after dot")
}
} else {
return nil, fmt.Errorf("invalid key character: %c", r)
} }
} }
if inQuotes {
return nil, errors.New("mismatched quotes")
}
if buffer.Len() > 0 {
groups = append(groups, buffer.String())
}
if len(groups) == 0 { if len(groups) == 0 {
return nil, errors.New("empty key") return nil, fmt.Errorf("empty key")
} }
return groups, nil return groups, nil
} }

View File

@ -309,7 +309,7 @@ func (l *tomlLexer) lexKey() tomlLexStateFn {
if err != nil { if err != nil {
return l.errorf(err.Error()) return l.errorf(err.Error())
} }
growingString += str growingString += "\"" + str + "\""
l.next() l.next()
continue continue
} else if r == '\'' { } else if r == '\'' {
@ -318,13 +318,15 @@ func (l *tomlLexer) lexKey() tomlLexStateFn {
if err != nil { if err != nil {
return l.errorf(err.Error()) return l.errorf(err.Error())
} }
growingString += str growingString += "'" + str + "'"
l.next() l.next()
continue continue
} else if r == '\n' { } else if r == '\n' {
return l.errorf("keys cannot contain new lines") return l.errorf("keys cannot contain new lines")
} else if isSpace(r) { } else if isSpace(r) {
break break
} else if r == '.' {
// skip
} else if !isValidBareChar(r) { } else if !isValidBareChar(r) {
return l.errorf("keys cannot contain %c character", r) return l.errorf("keys cannot contain %c character", r)
} }

View File

@ -6,20 +6,28 @@ import (
"fmt" "fmt"
"io" "io"
"reflect" "reflect"
"sort"
"strconv" "strconv"
"strings" "strings"
"time" "time"
) )
const tagKeyMultiline = "multiline" const (
tagFieldName = "toml"
tagFieldComment = "comment"
tagCommented = "commented"
tagMultiline = "multiline"
tagDefault = "default"
)
type tomlOpts struct { type tomlOpts struct {
name string name string
comment string comment string
commented bool commented bool
multiline bool multiline bool
include bool include bool
omitempty bool omitempty bool
defaultValue string
} }
type encOpts struct { type encOpts struct {
@ -31,10 +39,37 @@ var encOptsDefaults = encOpts{
quoteMapKeys: false, quoteMapKeys: false,
} }
type annotation struct {
tag string
comment string
commented string
multiline string
defaultValue string
}
var annotationDefault = annotation{
tag: tagFieldName,
comment: tagFieldComment,
commented: tagCommented,
multiline: tagMultiline,
defaultValue: tagDefault,
}
type marshalOrder int
// Orders the Encoder can write the fields to the output stream.
const (
// Sort fields alphabetically.
OrderAlphabetical marshalOrder = iota + 1
// Preserve the order the fields are encountered. For example, the order of fields in
// a struct.
OrderPreserve
)
var timeType = reflect.TypeOf(time.Time{}) var timeType = reflect.TypeOf(time.Time{})
var marshalerType = reflect.TypeOf(new(Marshaler)).Elem() var marshalerType = reflect.TypeOf(new(Marshaler)).Elem()
// Check if the given marshall type maps to a Tree primitive // Check if the given marshal type maps to a Tree primitive
func isPrimitive(mtype reflect.Type) bool { func isPrimitive(mtype reflect.Type) bool {
switch mtype.Kind() { switch mtype.Kind() {
case reflect.Ptr: case reflect.Ptr:
@ -56,7 +91,7 @@ func isPrimitive(mtype reflect.Type) bool {
} }
} }
// Check if the given marshall type maps to a Tree slice // Check if the given marshal type maps to a Tree slice
func isTreeSlice(mtype reflect.Type) bool { func isTreeSlice(mtype reflect.Type) bool {
switch mtype.Kind() { switch mtype.Kind() {
case reflect.Slice: case reflect.Slice:
@ -66,7 +101,7 @@ func isTreeSlice(mtype reflect.Type) bool {
} }
} }
// Check if the given marshall type maps to a non-Tree slice // Check if the given marshal type maps to a non-Tree slice
func isOtherSlice(mtype reflect.Type) bool { func isOtherSlice(mtype reflect.Type) bool {
switch mtype.Kind() { switch mtype.Kind() {
case reflect.Ptr: case reflect.Ptr:
@ -78,7 +113,7 @@ func isOtherSlice(mtype reflect.Type) bool {
} }
} }
// Check if the given marshall type maps to a Tree // Check if the given marshal type maps to a Tree
func isTree(mtype reflect.Type) bool { func isTree(mtype reflect.Type) bool {
switch mtype.Kind() { switch mtype.Kind() {
case reflect.Map: case reflect.Map:
@ -136,6 +171,8 @@ Tree primitive types and corresponding marshal types:
string string, pointers to same string string, pointers to same
bool bool, pointers to same bool bool, pointers to same
time.Time time.Time{}, pointers to same time.Time time.Time{}, pointers to same
For additional flexibility, use the Encoder API.
*/ */
func Marshal(v interface{}) ([]byte, error) { func Marshal(v interface{}) ([]byte, error) {
return NewEncoder(nil).marshal(v) return NewEncoder(nil).marshal(v)
@ -145,13 +182,21 @@ func Marshal(v interface{}) ([]byte, error) {
type Encoder struct { type Encoder struct {
w io.Writer w io.Writer
encOpts encOpts
annotation
line int
col int
order marshalOrder
} }
// NewEncoder returns a new encoder that writes to w. // NewEncoder returns a new encoder that writes to w.
func NewEncoder(w io.Writer) *Encoder { func NewEncoder(w io.Writer) *Encoder {
return &Encoder{ return &Encoder{
w: w, w: w,
encOpts: encOptsDefaults, encOpts: encOptsDefaults,
annotation: annotationDefault,
line: 0,
col: 1,
order: OrderAlphabetical,
} }
} }
@ -197,11 +242,49 @@ func (e *Encoder) ArraysWithOneElementPerLine(v bool) *Encoder {
return e return e
} }
// Order allows to change in which order fields will be written to the output stream.
func (e *Encoder) Order(ord marshalOrder) *Encoder {
e.order = ord
return e
}
// SetTagName allows changing default tag "toml"
func (e *Encoder) SetTagName(v string) *Encoder {
e.tag = v
return e
}
// SetTagComment allows changing default tag "comment"
func (e *Encoder) SetTagComment(v string) *Encoder {
e.comment = v
return e
}
// SetTagCommented allows changing default tag "commented"
func (e *Encoder) SetTagCommented(v string) *Encoder {
e.commented = v
return e
}
// SetTagMultiline allows changing default tag "multiline"
func (e *Encoder) SetTagMultiline(v string) *Encoder {
e.multiline = v
return e
}
func (e *Encoder) marshal(v interface{}) ([]byte, error) { func (e *Encoder) marshal(v interface{}) ([]byte, error) {
mtype := reflect.TypeOf(v) mtype := reflect.TypeOf(v)
if mtype.Kind() != reflect.Struct {
return []byte{}, errors.New("Only a struct can be marshaled to TOML") switch mtype.Kind() {
case reflect.Struct, reflect.Map:
case reflect.Ptr:
if mtype.Elem().Kind() != reflect.Struct {
return []byte{}, errors.New("Only pointer to struct can be marshaled to TOML")
}
default:
return []byte{}, errors.New("Only a struct or map can be marshaled to TOML")
} }
sval := reflect.ValueOf(v) sval := reflect.ValueOf(v)
if isCustomMarshaler(mtype) { if isCustomMarshaler(mtype) {
return callCustomMarshaler(sval) return callCustomMarshaler(sval)
@ -212,22 +295,27 @@ func (e *Encoder) marshal(v interface{}) ([]byte, error) {
} }
var buf bytes.Buffer var buf bytes.Buffer
_, err = t.writeTo(&buf, "", "", 0, e.arraysOneElementPerLine) _, err = t.writeToOrdered(&buf, "", "", 0, e.arraysOneElementPerLine, e.order)
return buf.Bytes(), err return buf.Bytes(), err
} }
// Create next tree with a position based on Encoder.line
func (e *Encoder) nextTree() *Tree {
return newTreeWithPosition(Position{Line: e.line, Col: 1})
}
// Convert given marshal struct or map value to toml tree // Convert given marshal struct or map value to toml tree
func (e *Encoder) valueToTree(mtype reflect.Type, mval reflect.Value) (*Tree, error) { func (e *Encoder) valueToTree(mtype reflect.Type, mval reflect.Value) (*Tree, error) {
if mtype.Kind() == reflect.Ptr { if mtype.Kind() == reflect.Ptr {
return e.valueToTree(mtype.Elem(), mval.Elem()) return e.valueToTree(mtype.Elem(), mval.Elem())
} }
tval := newTree() tval := e.nextTree()
switch mtype.Kind() { switch mtype.Kind() {
case reflect.Struct: case reflect.Struct:
for i := 0; i < mtype.NumField(); i++ { for i := 0; i < mtype.NumField(); i++ {
mtypef, mvalf := mtype.Field(i), mval.Field(i) mtypef, mvalf := mtype.Field(i), mval.Field(i)
opts := tomlOptions(mtypef) opts := tomlOptions(mtypef, e.annotation)
if opts.include && (!opts.omitempty || !isZero(mvalf)) { if opts.include && (!opts.omitempty || !isZero(mvalf)) {
val, err := e.valueToToml(mtypef.Type, mvalf) val, err := e.valueToToml(mtypef.Type, mvalf)
if err != nil { if err != nil {
@ -242,7 +330,26 @@ func (e *Encoder) valueToTree(mtype reflect.Type, mval reflect.Value) (*Tree, er
} }
} }
case reflect.Map: case reflect.Map:
for _, key := range mval.MapKeys() { keys := mval.MapKeys()
if e.order == OrderPreserve && len(keys) > 0 {
// Sorting []reflect.Value is not straight forward.
//
// OrderPreserve will support deterministic results when string is used
// as the key to maps.
typ := keys[0].Type()
kind := keys[0].Kind()
if kind == reflect.String {
ikeys := make([]string, len(keys))
for i := range keys {
ikeys[i] = keys[i].Interface().(string)
}
sort.Strings(ikeys)
for i := range ikeys {
keys[i] = reflect.ValueOf(ikeys[i]).Convert(typ)
}
}
}
for _, key := range keys {
mvalf := mval.MapIndex(key) mvalf := mval.MapIndex(key)
val, err := e.valueToToml(mtype.Elem(), mvalf) val, err := e.valueToToml(mtype.Elem(), mvalf)
if err != nil { if err != nil {
@ -290,6 +397,7 @@ func (e *Encoder) valueToOtherSlice(mtype reflect.Type, mval reflect.Value) (int
// Convert given marshal value to toml value // Convert given marshal value to toml value
func (e *Encoder) valueToToml(mtype reflect.Type, mval reflect.Value) (interface{}, error) { func (e *Encoder) valueToToml(mtype reflect.Type, mval reflect.Value) (interface{}, error) {
e.line++
if mtype.Kind() == reflect.Ptr { if mtype.Kind() == reflect.Ptr {
return e.valueToToml(mtype.Elem(), mval.Elem()) return e.valueToToml(mtype.Elem(), mval.Elem())
} }
@ -307,6 +415,9 @@ func (e *Encoder) valueToToml(mtype reflect.Type, mval reflect.Value) (interface
case reflect.Bool: case reflect.Bool:
return mval.Bool(), nil return mval.Bool(), nil
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
if mtype.Kind() == reflect.Int64 && mtype == reflect.TypeOf(time.Duration(1)) {
return fmt.Sprint(mval), nil
}
return mval.Int(), nil return mval.Int(), nil
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return mval.Uint(), nil return mval.Uint(), nil
@ -326,7 +437,7 @@ func (e *Encoder) valueToToml(mtype reflect.Type, mval reflect.Value) (interface
// Neither Unmarshaler interfaces nor UnmarshalTOML functions are supported for // Neither Unmarshaler interfaces nor UnmarshalTOML functions are supported for
// sub-structs, and only definite types can be unmarshaled. // sub-structs, and only definite types can be unmarshaled.
func (t *Tree) Unmarshal(v interface{}) error { func (t *Tree) Unmarshal(v interface{}) error {
d := Decoder{tval: t} d := Decoder{tval: t, tagName: tagFieldName}
return d.unmarshal(v) return d.unmarshal(v)
} }
@ -347,6 +458,14 @@ func (t *Tree) Marshal() ([]byte, error) {
// The following struct annotations are supported: // The following struct annotations are supported:
// //
// toml:"Field" Overrides the field's name to map to. // toml:"Field" Overrides the field's name to map to.
// default:"foo" Provides a default value.
//
// For default values, only fields of the following types are supported:
// * string
// * bool
// * int
// * int64
// * float64
// //
// See Marshal() documentation for types mapping table. // See Marshal() documentation for types mapping table.
func Unmarshal(data []byte, v interface{}) error { func Unmarshal(data []byte, v interface{}) error {
@ -362,6 +481,7 @@ type Decoder struct {
r io.Reader r io.Reader
tval *Tree tval *Tree
encOpts encOpts
tagName string
} }
// NewDecoder returns a new decoder that reads from r. // NewDecoder returns a new decoder that reads from r.
@ -369,6 +489,7 @@ func NewDecoder(r io.Reader) *Decoder {
return &Decoder{ return &Decoder{
r: r, r: r,
encOpts: encOptsDefaults, encOpts: encOptsDefaults,
tagName: tagFieldName,
} }
} }
@ -385,13 +506,27 @@ func (d *Decoder) Decode(v interface{}) error {
return d.unmarshal(v) return d.unmarshal(v)
} }
// SetTagName allows changing default tag "toml"
func (d *Decoder) SetTagName(v string) *Decoder {
d.tagName = v
return d
}
func (d *Decoder) unmarshal(v interface{}) error { func (d *Decoder) unmarshal(v interface{}) error {
mtype := reflect.TypeOf(v) mtype := reflect.TypeOf(v)
if mtype.Kind() != reflect.Ptr || mtype.Elem().Kind() != reflect.Struct { if mtype.Kind() != reflect.Ptr {
return errors.New("Only a pointer to struct can be unmarshaled from TOML") return errors.New("only a pointer to struct or map can be unmarshaled from TOML")
} }
sval, err := d.valueFromTree(mtype.Elem(), d.tval) elem := mtype.Elem()
switch elem.Kind() {
case reflect.Struct, reflect.Map:
default:
return errors.New("only a pointer to struct or map can be unmarshaled from TOML")
}
sval, err := d.valueFromTree(elem, d.tval)
if err != nil { if err != nil {
return err return err
} }
@ -410,10 +545,18 @@ func (d *Decoder) valueFromTree(mtype reflect.Type, tval *Tree) (reflect.Value,
mval = reflect.New(mtype).Elem() mval = reflect.New(mtype).Elem()
for i := 0; i < mtype.NumField(); i++ { for i := 0; i < mtype.NumField(); i++ {
mtypef := mtype.Field(i) mtypef := mtype.Field(i)
opts := tomlOptions(mtypef) an := annotation{tag: d.tagName}
opts := tomlOptions(mtypef, an)
if opts.include { if opts.include {
baseKey := opts.name baseKey := opts.name
keysToTry := []string{baseKey, strings.ToLower(baseKey), strings.ToTitle(baseKey)} keysToTry := []string{
baseKey,
strings.ToLower(baseKey),
strings.ToTitle(baseKey),
strings.ToLower(string(baseKey[0])) + baseKey[1:],
}
found := false
for _, key := range keysToTry { for _, key := range keysToTry {
exists := tval.Has(key) exists := tval.Has(key)
if !exists { if !exists {
@ -425,8 +568,42 @@ func (d *Decoder) valueFromTree(mtype reflect.Type, tval *Tree) (reflect.Value,
return mval, formatError(err, tval.GetPosition(key)) return mval, formatError(err, tval.GetPosition(key))
} }
mval.Field(i).Set(mvalf) mval.Field(i).Set(mvalf)
found = true
break break
} }
if !found && opts.defaultValue != "" {
mvalf := mval.Field(i)
var val interface{}
var err error
switch mvalf.Kind() {
case reflect.Bool:
val, err = strconv.ParseBool(opts.defaultValue)
if err != nil {
return mval.Field(i), err
}
case reflect.Int:
val, err = strconv.Atoi(opts.defaultValue)
if err != nil {
return mval.Field(i), err
}
case reflect.String:
val = opts.defaultValue
case reflect.Int64:
val, err = strconv.ParseInt(opts.defaultValue, 10, 64)
if err != nil {
return mval.Field(i), err
}
case reflect.Float64:
val, err = strconv.ParseFloat(opts.defaultValue, 64)
if err != nil {
return mval.Field(i), err
}
default:
return mval.Field(i), fmt.Errorf("unsuported field type for default option")
}
mval.Field(i).Set(reflect.ValueOf(val))
}
} }
} }
case reflect.Map: case reflect.Map:
@ -438,7 +615,7 @@ func (d *Decoder) valueFromTree(mtype reflect.Type, tval *Tree) (reflect.Value,
if err != nil { if err != nil {
return mval, formatError(err, tval.GetPosition(key)) return mval, formatError(err, tval.GetPosition(key))
} }
mval.SetMapIndex(reflect.ValueOf(key), mvalf) mval.SetMapIndex(reflect.ValueOf(key).Convert(mtype.Key()), mvalf)
} }
} }
return mval, nil return mval, nil
@ -476,20 +653,20 @@ func (d *Decoder) valueFromToml(mtype reflect.Type, tval interface{}) (reflect.V
return d.unwrapPointer(mtype, tval) return d.unwrapPointer(mtype, tval)
} }
switch tval.(type) { switch t := tval.(type) {
case *Tree: case *Tree:
if isTree(mtype) { if isTree(mtype) {
return d.valueFromTree(mtype, tval.(*Tree)) return d.valueFromTree(mtype, t)
} }
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to a tree", tval, tval) return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to a tree", tval, tval)
case []*Tree: case []*Tree:
if isTreeSlice(mtype) { if isTreeSlice(mtype) {
return d.valueFromTreeSlice(mtype, tval.([]*Tree)) return d.valueFromTreeSlice(mtype, t)
} }
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to trees", tval, tval) return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to trees", tval, tval)
case []interface{}: case []interface{}:
if isOtherSlice(mtype) { if isOtherSlice(mtype) {
return d.valueFromOtherSlice(mtype, tval.([]interface{})) return d.valueFromOtherSlice(mtype, t)
} }
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to a slice", tval, tval) return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to a slice", tval, tval)
default: default:
@ -512,10 +689,17 @@ func (d *Decoder) valueFromToml(mtype reflect.Type, tval interface{}) (reflect.V
return val.Convert(mtype), nil return val.Convert(mtype), nil
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
val := reflect.ValueOf(tval) val := reflect.ValueOf(tval)
if mtype.Kind() == reflect.Int64 && mtype == reflect.TypeOf(time.Duration(1)) && val.Kind() == reflect.String {
d, err := time.ParseDuration(val.String())
if err != nil {
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v. %s", tval, tval, mtype.String(), err)
}
return reflect.ValueOf(d), nil
}
if !val.Type().ConvertibleTo(mtype) { if !val.Type().ConvertibleTo(mtype) {
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v", tval, tval, mtype.String()) return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v", tval, tval, mtype.String())
} }
if reflect.Indirect(reflect.New(mtype)).OverflowInt(val.Int()) { if reflect.Indirect(reflect.New(mtype)).OverflowInt(val.Convert(mtype).Int()) {
return reflect.ValueOf(nil), fmt.Errorf("%v(%T) would overflow %v", tval, tval, mtype.String()) return reflect.ValueOf(nil), fmt.Errorf("%v(%T) would overflow %v", tval, tval, mtype.String())
} }
@ -525,10 +709,11 @@ func (d *Decoder) valueFromToml(mtype reflect.Type, tval interface{}) (reflect.V
if !val.Type().ConvertibleTo(mtype) { if !val.Type().ConvertibleTo(mtype) {
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v", tval, tval, mtype.String()) return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v", tval, tval, mtype.String())
} }
if val.Int() < 0 {
if val.Convert(reflect.TypeOf(int(1))).Int() < 0 {
return reflect.ValueOf(nil), fmt.Errorf("%v(%T) is negative so does not fit in %v", tval, tval, mtype.String()) return reflect.ValueOf(nil), fmt.Errorf("%v(%T) is negative so does not fit in %v", tval, tval, mtype.String())
} }
if reflect.Indirect(reflect.New(mtype)).OverflowUint(uint64(val.Int())) { if reflect.Indirect(reflect.New(mtype)).OverflowUint(uint64(val.Convert(mtype).Uint())) {
return reflect.ValueOf(nil), fmt.Errorf("%v(%T) would overflow %v", tval, tval, mtype.String()) return reflect.ValueOf(nil), fmt.Errorf("%v(%T) would overflow %v", tval, tval, mtype.String())
} }
@ -538,7 +723,7 @@ func (d *Decoder) valueFromToml(mtype reflect.Type, tval interface{}) (reflect.V
if !val.Type().ConvertibleTo(mtype) { if !val.Type().ConvertibleTo(mtype) {
return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v", tval, tval, mtype.String()) return reflect.ValueOf(nil), fmt.Errorf("Can't convert %v(%T) to %v", tval, tval, mtype.String())
} }
if reflect.Indirect(reflect.New(mtype)).OverflowFloat(val.Float()) { if reflect.Indirect(reflect.New(mtype)).OverflowFloat(val.Convert(mtype).Float()) {
return reflect.ValueOf(nil), fmt.Errorf("%v(%T) would overflow %v", tval, tval, mtype.String()) return reflect.ValueOf(nil), fmt.Errorf("%v(%T) would overflow %v", tval, tval, mtype.String())
} }
@ -559,16 +744,25 @@ func (d *Decoder) unwrapPointer(mtype reflect.Type, tval interface{}) (reflect.V
return mval, nil return mval, nil
} }
func tomlOptions(vf reflect.StructField) tomlOpts { func tomlOptions(vf reflect.StructField, an annotation) tomlOpts {
tag := vf.Tag.Get("toml") tag := vf.Tag.Get(an.tag)
parse := strings.Split(tag, ",") parse := strings.Split(tag, ",")
var comment string var comment string
if c := vf.Tag.Get("comment"); c != "" { if c := vf.Tag.Get(an.comment); c != "" {
comment = c comment = c
} }
commented, _ := strconv.ParseBool(vf.Tag.Get("commented")) commented, _ := strconv.ParseBool(vf.Tag.Get(an.commented))
multiline, _ := strconv.ParseBool(vf.Tag.Get(tagKeyMultiline)) multiline, _ := strconv.ParseBool(vf.Tag.Get(an.multiline))
result := tomlOpts{name: vf.Name, comment: comment, commented: commented, multiline: multiline, include: true, omitempty: false} defaultValue := vf.Tag.Get(tagDefault)
result := tomlOpts{
name: vf.Name,
comment: comment,
commented: commented,
multiline: multiline,
include: true,
omitempty: false,
defaultValue: defaultValue,
}
if parse[0] != "" { if parse[0] != "" {
if parse[0] == "-" && len(parse) == 1 { if parse[0] == "-" && len(parse) == 1 {
result.include = false result.include = false

Some files were not shown because too many files have changed in this diff Show More