Use goose library for running plugin migrations
- Removes dependency on goose binary existing in plugin execution environment
This commit is contained in:
parent
f0bcf930f4
commit
0f95267e84
168
Gopkg.lock
generated
168
Gopkg.lock
generated
@ -2,50 +2,39 @@
|
|||||||
|
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:48a213e9dc4880bbbd6999309a476fa4d3cc67560aa7127154cf8ea95bd464c2"
|
|
||||||
name = "github.com/allegro/bigcache"
|
name = "github.com/allegro/bigcache"
|
||||||
packages = [
|
packages = [
|
||||||
".",
|
".",
|
||||||
"queue",
|
"queue"
|
||||||
]
|
]
|
||||||
pruneopts = ""
|
|
||||||
revision = "f31987a23e44c5121ef8c8b2f2ea2e8ffa37b068"
|
revision = "f31987a23e44c5121ef8c8b2f2ea2e8ffa37b068"
|
||||||
version = "v1.1.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 = "ff33da284e760fcdb03c33d37a719e5ed30ba844"
|
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 = "cff30e1d23fc9e800b2b5b4b41ef1817dda07e9f"
|
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"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:aaeffbff5bd24654cb4c190ed75d6c7b57b4f5d6741914c1a7a6bb7447e756c5"
|
|
||||||
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"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:90d36f5b581e95e00ced808cd48824ed6c320c25887828cce461bdef4cb7bc7c"
|
|
||||||
name = "github.com/ethereum/go-ethereum"
|
name = "github.com/ethereum/go-ethereum"
|
||||||
packages = [
|
packages = [
|
||||||
".",
|
".",
|
||||||
@ -81,64 +70,50 @@
|
|||||||
"params",
|
"params",
|
||||||
"rlp",
|
"rlp",
|
||||||
"rpc",
|
"rpc",
|
||||||
"trie",
|
"trie"
|
||||||
]
|
]
|
||||||
pruneopts = ""
|
|
||||||
revision = "cd79bc61a983d6482579d12cdd239b37bbfa12ef"
|
revision = "cd79bc61a983d6482579d12cdd239b37bbfa12ef"
|
||||||
|
|
||||||
[[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"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:a01080d20c45c031c13f3828c56e58f4f51d926a482ad10cc0316225097eb7ea"
|
|
||||||
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 = ["proto"]
|
packages = ["proto"]
|
||||||
pruneopts = ""
|
|
||||||
revision = "aa810b61a9c79d51363740d207bb46cf8e620ed5"
|
revision = "aa810b61a9c79d51363740d207bb46cf8e620ed5"
|
||||||
version = "v1.2.0"
|
version = "v1.2.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:2a5888946cdbc8aa360fd43301f9fc7869d663f60d5eedae7d4e6e5e4f06f2bf"
|
|
||||||
name = "github.com/golang/snappy"
|
name = "github.com/golang/snappy"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
pruneopts = ""
|
|
||||||
revision = "2e65f85255dbc3072edf28d6b5b8efc472979f5a"
|
revision = "2e65f85255dbc3072edf28d6b5b8efc472979f5a"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:5247b135b5492aa232a731acdcb52b08f32b874cb398f21ab460396eadbe866b"
|
|
||||||
name = "github.com/google/uuid"
|
name = "github.com/google/uuid"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
pruneopts = ""
|
|
||||||
revision = "d460ce9f8df2e77fb1ba55ca87fafed96c607494"
|
revision = "d460ce9f8df2e77fb1ba55ca87fafed96c607494"
|
||||||
version = "v1.0.0"
|
version = "v1.0.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:9c776d7d9c54b7ed89f119e449983c3f24c0023e75001d6092442412ebca6b94"
|
|
||||||
name = "github.com/hashicorp/golang-lru"
|
name = "github.com/hashicorp/golang-lru"
|
||||||
packages = [
|
packages = [
|
||||||
".",
|
".",
|
||||||
"simplelru",
|
"simplelru"
|
||||||
]
|
]
|
||||||
pruneopts = ""
|
|
||||||
revision = "0fb14efe8c47ae851c0034ed7a448854d3d34cf3"
|
revision = "0fb14efe8c47ae851c0034ed7a448854d3d34cf3"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:d14365c51dd1d34d5c79833ec91413bfbb166be978724f15701e17080dc06dec"
|
|
||||||
name = "github.com/hashicorp/hcl"
|
name = "github.com/hashicorp/hcl"
|
||||||
packages = [
|
packages = [
|
||||||
".",
|
".",
|
||||||
@ -150,29 +125,25 @@
|
|||||||
"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"
|
branch = "master"
|
||||||
digest = "1:b6e4cc26365c004808649862e22069de09594a9222143399a7a04904e9f7018c"
|
|
||||||
name = "github.com/huin/goupnp"
|
name = "github.com/huin/goupnp"
|
||||||
packages = [
|
packages = [
|
||||||
".",
|
".",
|
||||||
@ -181,83 +152,65 @@
|
|||||||
"httpu",
|
"httpu",
|
||||||
"scpd",
|
"scpd",
|
||||||
"soap",
|
"soap",
|
||||||
"ssdp",
|
"ssdp"
|
||||||
]
|
]
|
||||||
pruneopts = ""
|
|
||||||
revision = "1395d1447324cbea88d249fbfcfd70ea878fdfca"
|
revision = "1395d1447324cbea88d249fbfcfd70ea878fdfca"
|
||||||
|
|
||||||
[[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 = "0dae4fefe7c0e190f7b5a78dac28a1c82cc8d849"
|
revision = "0dae4fefe7c0e190f7b5a78dac28a1c82cc8d849"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:6a874e3ddfb9db2b42bd8c85b6875407c702fa868eed20634ff489bc896ccfd3"
|
|
||||||
name = "github.com/konsorten/go-windows-terminal-sequences"
|
name = "github.com/konsorten/go-windows-terminal-sequences"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
pruneopts = ""
|
|
||||||
revision = "5c8c8bd35d3832f5d134ae1e1e375b69a4d25242"
|
revision = "5c8c8bd35d3832f5d134ae1e1e375b69a4d25242"
|
||||||
version = "v1.0.1"
|
version = "v1.0.1"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:29145d7af4adafd72a79df5e41456ac9e232d5a28c1cd4dacf3ff008a217fc10"
|
|
||||||
name = "github.com/lib/pq"
|
name = "github.com/lib/pq"
|
||||||
packages = [
|
packages = [
|
||||||
".",
|
".",
|
||||||
"oid",
|
"oid"
|
||||||
]
|
]
|
||||||
pruneopts = ""
|
|
||||||
revision = "4ded0e9383f75c197b3a2aaa6d590ac52df6fd79"
|
revision = "4ded0e9383f75c197b3a2aaa6d590ac52df6fd79"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:961dc3b1d11f969370533390fdf203813162980c858e1dabe827b60940c909a5"
|
|
||||||
name = "github.com/magiconair/properties"
|
name = "github.com/magiconair/properties"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
pruneopts = ""
|
|
||||||
revision = "c2353362d570a7bfa228149c62842019201cfb71"
|
revision = "c2353362d570a7bfa228149c62842019201cfb71"
|
||||||
version = "v1.8.0"
|
version = "v1.8.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:096a8a9182648da3d00ff243b88407838902b6703fc12657f76890e08d1899bf"
|
|
||||||
name = "github.com/mitchellh/go-homedir"
|
name = "github.com/mitchellh/go-homedir"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
pruneopts = ""
|
|
||||||
revision = "ae18d6b8b3205b561c79e8e5f69bff09736185f4"
|
revision = "ae18d6b8b3205b561c79e8e5f69bff09736185f4"
|
||||||
version = "v1.0.0"
|
version = "v1.0.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:5219b4506253ccc598f9340677162a42d6a78f340a4cc6df2d62db4d0593c4e9"
|
|
||||||
name = "github.com/mitchellh/mapstructure"
|
name = "github.com/mitchellh/mapstructure"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
pruneopts = ""
|
|
||||||
revision = "fa473d140ef3c6adf42d6b391fe76707f1f243c8"
|
revision = "fa473d140ef3c6adf42d6b391fe76707f1f243c8"
|
||||||
version = "v1.0.0"
|
version = "v1.0.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:a7fd918fb5bd2188436785c0424f8a50b4addfedf37a2b14d796be2a927b8007"
|
|
||||||
name = "github.com/onsi/ginkgo"
|
name = "github.com/onsi/ginkgo"
|
||||||
packages = [
|
packages = [
|
||||||
".",
|
".",
|
||||||
@ -277,14 +230,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 = "3774a09d95489ccaa16032e0770d08ea77ba6184"
|
revision = "3774a09d95489ccaa16032e0770d08ea77ba6184"
|
||||||
version = "v1.6.0"
|
version = "v1.6.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:3ecd0a37c4a90c12a97e31c398cdbc173824351aa891898ee178120bfe71c478"
|
|
||||||
name = "github.com/onsi/gomega"
|
name = "github.com/onsi/gomega"
|
||||||
packages = [
|
packages = [
|
||||||
".",
|
".",
|
||||||
@ -299,106 +250,94 @@
|
|||||||
"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 = "7615b9433f86a8bdf29709bf288bc4fd0636a369"
|
revision = "7615b9433f86a8bdf29709bf288bc4fd0636a369"
|
||||||
version = "v1.4.2"
|
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 = "c01d1270ff3e442a8a57cddc1c92dc1138598194"
|
revision = "c01d1270ff3e442a8a57cddc1c92dc1138598194"
|
||||||
version = "v1.2.0"
|
version = "v1.2.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:7143292549152d009ca9e9c493b74736a2ebd93f921bea8a4b308d7cc5edc6b3"
|
name = "github.com/pkg/errors"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "ba968bfe8b2f7e042a574c888954fccecfa385b4"
|
||||||
|
version = "v0.8.1"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/pressly/goose"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "e4b98955473e91a12fc7d8816c28d06376d1d92c"
|
||||||
|
version = "v2.6.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
name = "github.com/rjeczalik/notify"
|
name = "github.com/rjeczalik/notify"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
pruneopts = ""
|
|
||||||
revision = "0f065fa99b48b842c3fd3e2c8b194c6f2b69f6b8"
|
revision = "0f065fa99b48b842c3fd3e2c8b194c6f2b69f6b8"
|
||||||
version = "v0.9.1"
|
version = "v0.9.1"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:78c9cf43ddeacd0e472f412082227a0fac2ae107ee60e9112156f9371f9912cf"
|
|
||||||
name = "github.com/rs/cors"
|
name = "github.com/rs/cors"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
pruneopts = ""
|
|
||||||
revision = "3fb1b69b103a84de38a19c3c6ec073dd6caa4d3f"
|
revision = "3fb1b69b103a84de38a19c3c6ec073dd6caa4d3f"
|
||||||
version = "v1.5.0"
|
version = "v1.5.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:9d57e200ef5ccc4217fe0a34287308bac652435e7c6513f6263e0493d2245c56"
|
|
||||||
name = "github.com/sirupsen/logrus"
|
name = "github.com/sirupsen/logrus"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
pruneopts = ""
|
|
||||||
revision = "bcd833dfe83d3cebad139e4a29ed79cb2318bf95"
|
revision = "bcd833dfe83d3cebad139e4a29ed79cb2318bf95"
|
||||||
version = "v1.2.0"
|
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 = "d40851caa0d747393da1ffb28f7f9d8b4eeffebd"
|
revision = "d40851caa0d747393da1ffb28f7f9d8b4eeffebd"
|
||||||
version = "v1.1.2"
|
version = "v1.1.2"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:d0b38ba6da419a6d4380700218eeec8623841d44a856bb57369c172fbf692ab4"
|
|
||||||
name = "github.com/spf13/cast"
|
name = "github.com/spf13/cast"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
pruneopts = ""
|
|
||||||
revision = "8965335b8c7107321228e3e3702cab9832751bac"
|
revision = "8965335b8c7107321228e3e3702cab9832751bac"
|
||||||
version = "v1.2.0"
|
version = "v1.2.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:a1403cc8a94b8d7956ee5e9694badef0e7b051af289caad1cf668331e3ffa4f6"
|
|
||||||
name = "github.com/spf13/cobra"
|
name = "github.com/spf13/cobra"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
pruneopts = ""
|
|
||||||
revision = "ef82de70bb3f60c65fb8eebacbb2d122ef517385"
|
revision = "ef82de70bb3f60c65fb8eebacbb2d122ef517385"
|
||||||
version = "v0.0.3"
|
version = "v0.0.3"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:9ceffa4ab5f7195ecf18b3a7fff90c837a9ed5e22e66d18069e4bccfe1f52aa0"
|
|
||||||
name = "github.com/spf13/jwalterweatherman"
|
name = "github.com/spf13/jwalterweatherman"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
pruneopts = ""
|
|
||||||
revision = "4a4406e478ca629068e7768fc33f3f044173c0a6"
|
revision = "4a4406e478ca629068e7768fc33f3f044173c0a6"
|
||||||
version = "v1.0.0"
|
version = "v1.0.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:0a52bcb568386d98f4894575d53ce3e456f56471de6897bb8b9de13c33d9340e"
|
|
||||||
name = "github.com/spf13/pflag"
|
name = "github.com/spf13/pflag"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
pruneopts = ""
|
|
||||||
revision = "9a97c102cda95a86cec2345a6f09f55a939babf5"
|
revision = "9a97c102cda95a86cec2345a6f09f55a939babf5"
|
||||||
version = "v1.0.2"
|
version = "v1.0.2"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:ac25ea6cc1156aca9611411274b4a0bdd83a623845df6985aab508253955cc66"
|
|
||||||
name = "github.com/spf13/viper"
|
name = "github.com/spf13/viper"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
pruneopts = ""
|
|
||||||
revision = "8fb642006536c8d3760c99d4fa2389f5e2205631"
|
revision = "8fb642006536c8d3760c99d4fa2389f5e2205631"
|
||||||
version = "v1.2.0"
|
version = "v1.2.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:ce5194e5afac308cc34e500cab45b4ce88a0742d689e3cf7e37b607ad76bed2f"
|
|
||||||
name = "github.com/syndtr/goleveldb"
|
name = "github.com/syndtr/goleveldb"
|
||||||
packages = [
|
packages = [
|
||||||
"leveldb",
|
"leveldb",
|
||||||
@ -412,59 +351,49 @@
|
|||||||
"leveldb/opt",
|
"leveldb/opt",
|
||||||
"leveldb/storage",
|
"leveldb/storage",
|
||||||
"leveldb/table",
|
"leveldb/table",
|
||||||
"leveldb/util",
|
"leveldb/util"
|
||||||
]
|
]
|
||||||
pruneopts = ""
|
|
||||||
revision = "ae2bd5eed72d46b28834ec3f60db3a3ebedd8dbd"
|
revision = "ae2bd5eed72d46b28834ec3f60db3a3ebedd8dbd"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:59b49c47c11a48f1054529207f65907c014ecf5f9a7c0d9c0f1616dec7b062ed"
|
|
||||||
name = "golang.org/x/crypto"
|
name = "golang.org/x/crypto"
|
||||||
packages = [
|
packages = [
|
||||||
"pbkdf2",
|
"pbkdf2",
|
||||||
"scrypt",
|
"scrypt",
|
||||||
"sha3",
|
"sha3",
|
||||||
"ssh/terminal",
|
"ssh/terminal"
|
||||||
]
|
]
|
||||||
pruneopts = ""
|
|
||||||
revision = "ff983b9c42bc9fbf91556e191cc8efb585c16908"
|
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",
|
"websocket"
|
||||||
]
|
]
|
||||||
pruneopts = ""
|
|
||||||
revision = "26e67e76b6c3f6ce91f7c52def5af501b4e0f3a2"
|
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 = "1d60e4601c6fd243af51cc01ddf169918a5407ca"
|
revision = "1d60e4601c6fd243af51cc01ddf169918a5407ca"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:70d519d5cddeb60ceda2db88c24c340b1b2d7efb25ab54bacb38f57ea1998df7"
|
|
||||||
name = "golang.org/x/sys"
|
name = "golang.org/x/sys"
|
||||||
packages = [
|
packages = [
|
||||||
"unix",
|
"unix",
|
||||||
"windows",
|
"windows"
|
||||||
]
|
]
|
||||||
pruneopts = ""
|
|
||||||
revision = "d641721ec2dead6fe5ca284096fe4b1fcd49e427"
|
revision = "d641721ec2dead6fe5ca284096fe4b1fcd49e427"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:5acd3512b047305d49e8763eef7ba423901e85d5dd2fd1e71778a0ea8de10bd4"
|
|
||||||
name = "golang.org/x/text"
|
name = "golang.org/x/text"
|
||||||
packages = [
|
packages = [
|
||||||
"encoding",
|
"encoding",
|
||||||
@ -486,78 +415,39 @@
|
|||||||
"runes",
|
"runes",
|
||||||
"transform",
|
"transform",
|
||||||
"unicode/cldr",
|
"unicode/cldr",
|
||||||
"unicode/norm",
|
"unicode/norm"
|
||||||
]
|
]
|
||||||
pruneopts = ""
|
|
||||||
revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0"
|
revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0"
|
||||||
version = "v0.3.0"
|
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]]
|
||||||
digest = "1:f0620375dd1f6251d9973b5f2596228cc8042e887cd7f827e4220bc1ce8c30e2"
|
|
||||||
name = "gopkg.in/yaml.v2"
|
name = "gopkg.in/yaml.v2"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
pruneopts = ""
|
|
||||||
revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183"
|
revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183"
|
||||||
version = "v2.2.1"
|
version = "v2.2.1"
|
||||||
|
|
||||||
[solve-meta]
|
[solve-meta]
|
||||||
analyzer-name = "dep"
|
analyzer-name = "dep"
|
||||||
analyzer-version = 1
|
analyzer-version = 1
|
||||||
input-imports = [
|
inputs-digest = "d41c963e87b06f7edd9135e30472894a114d0d8298454e6b2dae7ff25ac3c62a"
|
||||||
"github.com/dave/jennifer/jen",
|
|
||||||
"github.com/ethereum/go-ethereum",
|
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi",
|
|
||||||
"github.com/ethereum/go-ethereum/accounts/abi/bind",
|
|
||||||
"github.com/ethereum/go-ethereum/common",
|
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil",
|
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb",
|
|
||||||
"github.com/ethereum/go-ethereum/core/types",
|
|
||||||
"github.com/ethereum/go-ethereum/crypto",
|
|
||||||
"github.com/ethereum/go-ethereum/ethclient",
|
|
||||||
"github.com/ethereum/go-ethereum/ethdb",
|
|
||||||
"github.com/ethereum/go-ethereum/p2p",
|
|
||||||
"github.com/ethereum/go-ethereum/p2p/discv5",
|
|
||||||
"github.com/ethereum/go-ethereum/rlp",
|
|
||||||
"github.com/ethereum/go-ethereum/rpc",
|
|
||||||
"github.com/hashicorp/golang-lru",
|
|
||||||
"github.com/hpcloud/tail",
|
|
||||||
"github.com/jmoiron/sqlx",
|
|
||||||
"github.com/lib/pq",
|
|
||||||
"github.com/mitchellh/go-homedir",
|
|
||||||
"github.com/onsi/ginkgo",
|
|
||||||
"github.com/onsi/gomega",
|
|
||||||
"github.com/onsi/gomega/ghttp",
|
|
||||||
"github.com/sirupsen/logrus",
|
|
||||||
"github.com/spf13/cobra",
|
|
||||||
"github.com/spf13/viper",
|
|
||||||
"golang.org/x/net/context",
|
|
||||||
"golang.org/x/sync/errgroup",
|
|
||||||
"gopkg.in/tomb.v1",
|
|
||||||
]
|
|
||||||
solver-name = "gps-cdcl"
|
solver-name = "gps-cdcl"
|
||||||
solver-version = 1
|
solver-version = 1
|
||||||
|
@ -17,13 +17,15 @@
|
|||||||
package manager
|
package manager
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"database/sql"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/lib/pq"
|
||||||
|
"github.com/pressly/goose"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/config"
|
"github.com/vulcanize/vulcanizedb/pkg/config"
|
||||||
"github.com/vulcanize/vulcanizedb/pkg/plugin/helpers"
|
"github.com/vulcanize/vulcanizedb/pkg/plugin/helpers"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -36,6 +38,7 @@ type manager struct {
|
|||||||
GenConfig config.Plugin
|
GenConfig config.Plugin
|
||||||
DBConfig config.Database
|
DBConfig config.Database
|
||||||
tmpMigDir string
|
tmpMigDir string
|
||||||
|
db *sql.DB
|
||||||
}
|
}
|
||||||
|
|
||||||
// Manager requires both filled in generator and database configs
|
// Manager requires both filled in generator and database configs
|
||||||
@ -46,6 +49,22 @@ func NewMigrationManager(gc config.Plugin, dbc config.Database) *manager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *manager) setDB() error {
|
||||||
|
var pgStr string
|
||||||
|
if len(m.DBConfig.User) > 0 && len(m.DBConfig.Password) > 0 {
|
||||||
|
pgStr = fmt.Sprintf("postgresql://%s:%s@%s:%d/%s?sslmode=disable",
|
||||||
|
m.DBConfig.User, m.DBConfig.Password, m.DBConfig.Hostname, m.DBConfig.Port, m.DBConfig.Name)
|
||||||
|
} else {
|
||||||
|
pgStr = fmt.Sprintf("postgres://%s:%d/%s?sslmode=disable", m.DBConfig.Hostname, m.DBConfig.Port, m.DBConfig.Name)
|
||||||
|
}
|
||||||
|
dbConnector, err := pq.NewConnector(pgStr)
|
||||||
|
if err != nil {
|
||||||
|
return errors.New(fmt.Sprintf("can't connect to db: %s", err.Error()))
|
||||||
|
}
|
||||||
|
m.db = sql.OpenDB(dbConnector)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (m *manager) RunMigrations() error {
|
func (m *manager) RunMigrations() error {
|
||||||
// Get paths to db migrations from the plugin config
|
// Get paths to db migrations from the plugin config
|
||||||
paths, err := m.GenConfig.GetMigrationsPaths()
|
paths, err := m.GenConfig.GetMigrationsPaths()
|
||||||
@ -122,28 +141,23 @@ func (m *manager) createMigrationCopies(paths []string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *manager) fixAndRun(path string) error {
|
func (m *manager) fixAndRun(path string) error {
|
||||||
|
// Setup DB if not set
|
||||||
|
if m.db == nil {
|
||||||
|
setErr := m.setDB()
|
||||||
|
if setErr != nil {
|
||||||
|
return errors.New(fmt.Sprintf("could not open db: %s", setErr.Error()))
|
||||||
|
}
|
||||||
|
}
|
||||||
// Fix the migrations
|
// Fix the migrations
|
||||||
cmd := exec.Command("goose", "fix")
|
fixErr := goose.Fix(m.tmpMigDir)
|
||||||
cmd.Dir = m.tmpMigDir
|
if fixErr != nil {
|
||||||
err := cmd.Run()
|
return errors.New(fmt.Sprintf("version fixing for plugin migrations at %s failed: %s", path, fixErr.Error()))
|
||||||
if err != nil {
|
|
||||||
return errors.New(fmt.Sprintf("version fixing for plugin migrations at %s failed: %s", path, err.Error()))
|
|
||||||
}
|
}
|
||||||
// Run the copied migrations with goose
|
// Run the copied migrations with goose
|
||||||
var pgStr string
|
upErr := goose.Up(m.db, m.tmpMigDir)
|
||||||
if len(m.DBConfig.User) > 0 && len(m.DBConfig.Password) > 0 {
|
if upErr != nil {
|
||||||
pgStr = fmt.Sprintf("postgresql://%s:%s@%s:%d/%s?sslmode=disable",
|
return errors.New(fmt.Sprintf("db migrations for plugin transformers at %s failed: %s", path, upErr.Error()))
|
||||||
m.DBConfig.User, m.DBConfig.Password, m.DBConfig.Hostname, m.DBConfig.Port, m.DBConfig.Name)
|
|
||||||
} else {
|
|
||||||
pgStr = fmt.Sprintf("postgres://%s:%d/%s?sslmode=disable", m.DBConfig.Hostname, m.DBConfig.Port, m.DBConfig.Name)
|
|
||||||
}
|
}
|
||||||
cmd = exec.Command("goose", "postgres", pgStr, "up")
|
|
||||||
cmd.Dir = m.tmpMigDir
|
|
||||||
err = cmd.Run()
|
|
||||||
if err != nil {
|
|
||||||
return errors.New(fmt.Sprintf("db migrations for plugin transformers at %s failed: %s", path, err.Error()))
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
24
vendor/github.com/pkg/errors/.gitignore
generated
vendored
Normal file
24
vendor/github.com/pkg/errors/.gitignore
generated
vendored
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||||
|
*.o
|
||||||
|
*.a
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Folders
|
||||||
|
_obj
|
||||||
|
_test
|
||||||
|
|
||||||
|
# Architecture specific extensions/prefixes
|
||||||
|
*.[568vq]
|
||||||
|
[568vq].out
|
||||||
|
|
||||||
|
*.cgo1.go
|
||||||
|
*.cgo2.c
|
||||||
|
_cgo_defun.c
|
||||||
|
_cgo_gotypes.go
|
||||||
|
_cgo_export.*
|
||||||
|
|
||||||
|
_testmain.go
|
||||||
|
|
||||||
|
*.exe
|
||||||
|
*.test
|
||||||
|
*.prof
|
15
vendor/github.com/pkg/errors/.travis.yml
generated
vendored
Normal file
15
vendor/github.com/pkg/errors/.travis.yml
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
language: go
|
||||||
|
go_import_path: github.com/pkg/errors
|
||||||
|
go:
|
||||||
|
- 1.4.x
|
||||||
|
- 1.5.x
|
||||||
|
- 1.6.x
|
||||||
|
- 1.7.x
|
||||||
|
- 1.8.x
|
||||||
|
- 1.9.x
|
||||||
|
- 1.10.x
|
||||||
|
- 1.11.x
|
||||||
|
- tip
|
||||||
|
|
||||||
|
script:
|
||||||
|
- go test -v ./...
|
23
vendor/github.com/pkg/errors/LICENSE
generated
vendored
Normal file
23
vendor/github.com/pkg/errors/LICENSE
generated
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
Copyright (c) 2015, Dave Cheney <dave@cheney.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:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
52
vendor/github.com/pkg/errors/README.md
generated
vendored
Normal file
52
vendor/github.com/pkg/errors/README.md
generated
vendored
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
# errors [![Travis-CI](https://travis-ci.org/pkg/errors.svg)](https://travis-ci.org/pkg/errors) [![AppVeyor](https://ci.appveyor.com/api/projects/status/b98mptawhudj53ep/branch/master?svg=true)](https://ci.appveyor.com/project/davecheney/errors/branch/master) [![GoDoc](https://godoc.org/github.com/pkg/errors?status.svg)](http://godoc.org/github.com/pkg/errors) [![Report card](https://goreportcard.com/badge/github.com/pkg/errors)](https://goreportcard.com/report/github.com/pkg/errors) [![Sourcegraph](https://sourcegraph.com/github.com/pkg/errors/-/badge.svg)](https://sourcegraph.com/github.com/pkg/errors?badge)
|
||||||
|
|
||||||
|
Package errors provides simple error handling primitives.
|
||||||
|
|
||||||
|
`go get github.com/pkg/errors`
|
||||||
|
|
||||||
|
The traditional error handling idiom in Go is roughly akin to
|
||||||
|
```go
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
```
|
||||||
|
which applied recursively up the call stack results in error reports without context or debugging information. The errors package allows programmers to add context to the failure path in their code in a way that does not destroy the original value of the error.
|
||||||
|
|
||||||
|
## Adding context to an error
|
||||||
|
|
||||||
|
The errors.Wrap function returns a new error that adds context to the original error. For example
|
||||||
|
```go
|
||||||
|
_, err := ioutil.ReadAll(r)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "read failed")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
## Retrieving the cause of an error
|
||||||
|
|
||||||
|
Using `errors.Wrap` constructs a stack of errors, adding context to the preceding error. Depending on the nature of the error it may be necessary to reverse the operation of errors.Wrap to retrieve the original error for inspection. Any error value which implements this interface can be inspected by `errors.Cause`.
|
||||||
|
```go
|
||||||
|
type causer interface {
|
||||||
|
Cause() error
|
||||||
|
}
|
||||||
|
```
|
||||||
|
`errors.Cause` will recursively retrieve the topmost error which does not implement `causer`, which is assumed to be the original cause. For example:
|
||||||
|
```go
|
||||||
|
switch err := errors.Cause(err).(type) {
|
||||||
|
case *MyError:
|
||||||
|
// handle specifically
|
||||||
|
default:
|
||||||
|
// unknown error
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
[Read the package documentation for more information](https://godoc.org/github.com/pkg/errors).
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
We welcome pull requests, bug fixes and issue reports. With that said, the bar for adding new symbols to this package is intentionally set high.
|
||||||
|
|
||||||
|
Before proposing a change, please discuss your change by raising an issue.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
BSD-2-Clause
|
32
vendor/github.com/pkg/errors/appveyor.yml
generated
vendored
Normal file
32
vendor/github.com/pkg/errors/appveyor.yml
generated
vendored
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
version: build-{build}.{branch}
|
||||||
|
|
||||||
|
clone_folder: C:\gopath\src\github.com\pkg\errors
|
||||||
|
shallow_clone: true # for startup speed
|
||||||
|
|
||||||
|
environment:
|
||||||
|
GOPATH: C:\gopath
|
||||||
|
|
||||||
|
platform:
|
||||||
|
- x64
|
||||||
|
|
||||||
|
# http://www.appveyor.com/docs/installed-software
|
||||||
|
install:
|
||||||
|
# some helpful output for debugging builds
|
||||||
|
- go version
|
||||||
|
- go env
|
||||||
|
# pre-installed MinGW at C:\MinGW is 32bit only
|
||||||
|
# but MSYS2 at C:\msys64 has mingw64
|
||||||
|
- set PATH=C:\msys64\mingw64\bin;%PATH%
|
||||||
|
- gcc --version
|
||||||
|
- g++ --version
|
||||||
|
|
||||||
|
build_script:
|
||||||
|
- go install -v ./...
|
||||||
|
|
||||||
|
test_script:
|
||||||
|
- set PATH=C:\gopath\bin;%PATH%
|
||||||
|
- go test -v ./...
|
||||||
|
|
||||||
|
#artifacts:
|
||||||
|
# - path: '%GOPATH%\bin\*.exe'
|
||||||
|
deploy: off
|
63
vendor/github.com/pkg/errors/bench_test.go
generated
vendored
Normal file
63
vendor/github.com/pkg/errors/bench_test.go
generated
vendored
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
// +build go1.7
|
||||||
|
|
||||||
|
package errors
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
stderrors "errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
func noErrors(at, depth int) error {
|
||||||
|
if at >= depth {
|
||||||
|
return stderrors.New("no error")
|
||||||
|
}
|
||||||
|
return noErrors(at+1, depth)
|
||||||
|
}
|
||||||
|
|
||||||
|
func yesErrors(at, depth int) error {
|
||||||
|
if at >= depth {
|
||||||
|
return New("ye error")
|
||||||
|
}
|
||||||
|
return yesErrors(at+1, depth)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GlobalE is an exported global to store the result of benchmark results,
|
||||||
|
// preventing the compiler from optimising the benchmark functions away.
|
||||||
|
var GlobalE error
|
||||||
|
|
||||||
|
func BenchmarkErrors(b *testing.B) {
|
||||||
|
type run struct {
|
||||||
|
stack int
|
||||||
|
std bool
|
||||||
|
}
|
||||||
|
runs := []run{
|
||||||
|
{10, false},
|
||||||
|
{10, true},
|
||||||
|
{100, false},
|
||||||
|
{100, true},
|
||||||
|
{1000, false},
|
||||||
|
{1000, true},
|
||||||
|
}
|
||||||
|
for _, r := range runs {
|
||||||
|
part := "pkg/errors"
|
||||||
|
if r.std {
|
||||||
|
part = "errors"
|
||||||
|
}
|
||||||
|
name := fmt.Sprintf("%s-stack-%d", part, r.stack)
|
||||||
|
b.Run(name, func(b *testing.B) {
|
||||||
|
var err error
|
||||||
|
f := yesErrors
|
||||||
|
if r.std {
|
||||||
|
f = noErrors
|
||||||
|
}
|
||||||
|
b.ReportAllocs()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
err = f(0, r.stack)
|
||||||
|
}
|
||||||
|
b.StopTimer()
|
||||||
|
GlobalE = err
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
282
vendor/github.com/pkg/errors/errors.go
generated
vendored
Normal file
282
vendor/github.com/pkg/errors/errors.go
generated
vendored
Normal file
@ -0,0 +1,282 @@
|
|||||||
|
// Package errors provides simple error handling primitives.
|
||||||
|
//
|
||||||
|
// The traditional error handling idiom in Go is roughly akin to
|
||||||
|
//
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// which when applied recursively up the call stack results in error reports
|
||||||
|
// without context or debugging information. The errors package allows
|
||||||
|
// programmers to add context to the failure path in their code in a way
|
||||||
|
// that does not destroy the original value of the error.
|
||||||
|
//
|
||||||
|
// Adding context to an error
|
||||||
|
//
|
||||||
|
// The errors.Wrap function returns a new error that adds context to the
|
||||||
|
// original error by recording a stack trace at the point Wrap is called,
|
||||||
|
// together with the supplied message. For example
|
||||||
|
//
|
||||||
|
// _, err := ioutil.ReadAll(r)
|
||||||
|
// if err != nil {
|
||||||
|
// return errors.Wrap(err, "read failed")
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// If additional control is required, the errors.WithStack and
|
||||||
|
// errors.WithMessage functions destructure errors.Wrap into its component
|
||||||
|
// operations: annotating an error with a stack trace and with a message,
|
||||||
|
// respectively.
|
||||||
|
//
|
||||||
|
// Retrieving the cause of an error
|
||||||
|
//
|
||||||
|
// Using errors.Wrap constructs a stack of errors, adding context to the
|
||||||
|
// preceding error. Depending on the nature of the error it may be necessary
|
||||||
|
// to reverse the operation of errors.Wrap to retrieve the original error
|
||||||
|
// for inspection. Any error value which implements this interface
|
||||||
|
//
|
||||||
|
// type causer interface {
|
||||||
|
// Cause() error
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// can be inspected by errors.Cause. errors.Cause will recursively retrieve
|
||||||
|
// the topmost error that does not implement causer, which is assumed to be
|
||||||
|
// the original cause. For example:
|
||||||
|
//
|
||||||
|
// switch err := errors.Cause(err).(type) {
|
||||||
|
// case *MyError:
|
||||||
|
// // handle specifically
|
||||||
|
// default:
|
||||||
|
// // unknown error
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Although the causer interface is not exported by this package, it is
|
||||||
|
// considered a part of its stable public interface.
|
||||||
|
//
|
||||||
|
// Formatted printing of errors
|
||||||
|
//
|
||||||
|
// All error values returned from this package implement fmt.Formatter and can
|
||||||
|
// be formatted by the fmt package. The following verbs are supported:
|
||||||
|
//
|
||||||
|
// %s print the error. If the error has a Cause it will be
|
||||||
|
// printed recursively.
|
||||||
|
// %v see %s
|
||||||
|
// %+v extended format. Each Frame of the error's StackTrace will
|
||||||
|
// be printed in detail.
|
||||||
|
//
|
||||||
|
// Retrieving the stack trace of an error or wrapper
|
||||||
|
//
|
||||||
|
// New, Errorf, Wrap, and Wrapf record a stack trace at the point they are
|
||||||
|
// invoked. This information can be retrieved with the following interface:
|
||||||
|
//
|
||||||
|
// type stackTracer interface {
|
||||||
|
// StackTrace() errors.StackTrace
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// The returned errors.StackTrace type is defined as
|
||||||
|
//
|
||||||
|
// type StackTrace []Frame
|
||||||
|
//
|
||||||
|
// The Frame type represents a call site in the stack trace. Frame supports
|
||||||
|
// the fmt.Formatter interface that can be used for printing information about
|
||||||
|
// the stack trace of this error. For example:
|
||||||
|
//
|
||||||
|
// if err, ok := err.(stackTracer); ok {
|
||||||
|
// for _, f := range err.StackTrace() {
|
||||||
|
// fmt.Printf("%+s:%d", f)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Although the stackTracer interface is not exported by this package, it is
|
||||||
|
// considered a part of its stable public interface.
|
||||||
|
//
|
||||||
|
// See the documentation for Frame.Format for more details.
|
||||||
|
package errors
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
// New returns an error with the supplied message.
|
||||||
|
// New also records the stack trace at the point it was called.
|
||||||
|
func New(message string) error {
|
||||||
|
return &fundamental{
|
||||||
|
msg: message,
|
||||||
|
stack: callers(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Errorf formats according to a format specifier and returns the string
|
||||||
|
// as a value that satisfies error.
|
||||||
|
// Errorf also records the stack trace at the point it was called.
|
||||||
|
func Errorf(format string, args ...interface{}) error {
|
||||||
|
return &fundamental{
|
||||||
|
msg: fmt.Sprintf(format, args...),
|
||||||
|
stack: callers(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fundamental is an error that has a message and a stack, but no caller.
|
||||||
|
type fundamental struct {
|
||||||
|
msg string
|
||||||
|
*stack
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fundamental) Error() string { return f.msg }
|
||||||
|
|
||||||
|
func (f *fundamental) Format(s fmt.State, verb rune) {
|
||||||
|
switch verb {
|
||||||
|
case 'v':
|
||||||
|
if s.Flag('+') {
|
||||||
|
io.WriteString(s, f.msg)
|
||||||
|
f.stack.Format(s, verb)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fallthrough
|
||||||
|
case 's':
|
||||||
|
io.WriteString(s, f.msg)
|
||||||
|
case 'q':
|
||||||
|
fmt.Fprintf(s, "%q", f.msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithStack annotates err with a stack trace at the point WithStack was called.
|
||||||
|
// If err is nil, WithStack returns nil.
|
||||||
|
func WithStack(err error) error {
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &withStack{
|
||||||
|
err,
|
||||||
|
callers(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type withStack struct {
|
||||||
|
error
|
||||||
|
*stack
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *withStack) Cause() error { return w.error }
|
||||||
|
|
||||||
|
func (w *withStack) Format(s fmt.State, verb rune) {
|
||||||
|
switch verb {
|
||||||
|
case 'v':
|
||||||
|
if s.Flag('+') {
|
||||||
|
fmt.Fprintf(s, "%+v", w.Cause())
|
||||||
|
w.stack.Format(s, verb)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fallthrough
|
||||||
|
case 's':
|
||||||
|
io.WriteString(s, w.Error())
|
||||||
|
case 'q':
|
||||||
|
fmt.Fprintf(s, "%q", w.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrap returns an error annotating err with a stack trace
|
||||||
|
// at the point Wrap is called, and the supplied message.
|
||||||
|
// If err is nil, Wrap returns nil.
|
||||||
|
func Wrap(err error, message string) error {
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
err = &withMessage{
|
||||||
|
cause: err,
|
||||||
|
msg: message,
|
||||||
|
}
|
||||||
|
return &withStack{
|
||||||
|
err,
|
||||||
|
callers(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrapf returns an error annotating err with a stack trace
|
||||||
|
// at the point Wrapf is called, and the format specifier.
|
||||||
|
// If err is nil, Wrapf returns nil.
|
||||||
|
func Wrapf(err error, format string, args ...interface{}) error {
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
err = &withMessage{
|
||||||
|
cause: err,
|
||||||
|
msg: fmt.Sprintf(format, args...),
|
||||||
|
}
|
||||||
|
return &withStack{
|
||||||
|
err,
|
||||||
|
callers(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithMessage annotates err with a new message.
|
||||||
|
// If err is nil, WithMessage returns nil.
|
||||||
|
func WithMessage(err error, message string) error {
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &withMessage{
|
||||||
|
cause: err,
|
||||||
|
msg: message,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithMessagef annotates err with the format specifier.
|
||||||
|
// If err is nil, WithMessagef returns nil.
|
||||||
|
func WithMessagef(err error, format string, args ...interface{}) error {
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &withMessage{
|
||||||
|
cause: err,
|
||||||
|
msg: fmt.Sprintf(format, args...),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type withMessage struct {
|
||||||
|
cause error
|
||||||
|
msg string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *withMessage) Error() string { return w.msg + ": " + w.cause.Error() }
|
||||||
|
func (w *withMessage) Cause() error { return w.cause }
|
||||||
|
|
||||||
|
func (w *withMessage) Format(s fmt.State, verb rune) {
|
||||||
|
switch verb {
|
||||||
|
case 'v':
|
||||||
|
if s.Flag('+') {
|
||||||
|
fmt.Fprintf(s, "%+v\n", w.Cause())
|
||||||
|
io.WriteString(s, w.msg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fallthrough
|
||||||
|
case 's', 'q':
|
||||||
|
io.WriteString(s, w.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cause returns the underlying cause of the error, if possible.
|
||||||
|
// An error value has a cause if it implements the following
|
||||||
|
// interface:
|
||||||
|
//
|
||||||
|
// type causer interface {
|
||||||
|
// Cause() error
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// If the error does not implement Cause, the original error will
|
||||||
|
// be returned. If the error is nil, nil will be returned without further
|
||||||
|
// investigation.
|
||||||
|
func Cause(err error) error {
|
||||||
|
type causer interface {
|
||||||
|
Cause() error
|
||||||
|
}
|
||||||
|
|
||||||
|
for err != nil {
|
||||||
|
cause, ok := err.(causer)
|
||||||
|
if !ok {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
err = cause.Cause()
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
251
vendor/github.com/pkg/errors/errors_test.go
generated
vendored
Normal file
251
vendor/github.com/pkg/errors/errors_test.go
generated
vendored
Normal file
@ -0,0 +1,251 @@
|
|||||||
|
package errors
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNew(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
err string
|
||||||
|
want error
|
||||||
|
}{
|
||||||
|
{"", fmt.Errorf("")},
|
||||||
|
{"foo", fmt.Errorf("foo")},
|
||||||
|
{"foo", New("foo")},
|
||||||
|
{"string with format specifiers: %v", errors.New("string with format specifiers: %v")},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
got := New(tt.err)
|
||||||
|
if got.Error() != tt.want.Error() {
|
||||||
|
t.Errorf("New.Error(): got: %q, want %q", got, tt.want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWrapNil(t *testing.T) {
|
||||||
|
got := Wrap(nil, "no error")
|
||||||
|
if got != nil {
|
||||||
|
t.Errorf("Wrap(nil, \"no error\"): got %#v, expected nil", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWrap(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
err error
|
||||||
|
message string
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{io.EOF, "read error", "read error: EOF"},
|
||||||
|
{Wrap(io.EOF, "read error"), "client error", "client error: read error: EOF"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
got := Wrap(tt.err, tt.message).Error()
|
||||||
|
if got != tt.want {
|
||||||
|
t.Errorf("Wrap(%v, %q): got: %v, want %v", tt.err, tt.message, got, tt.want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type nilError struct{}
|
||||||
|
|
||||||
|
func (nilError) Error() string { return "nil error" }
|
||||||
|
|
||||||
|
func TestCause(t *testing.T) {
|
||||||
|
x := New("error")
|
||||||
|
tests := []struct {
|
||||||
|
err error
|
||||||
|
want error
|
||||||
|
}{{
|
||||||
|
// nil error is nil
|
||||||
|
err: nil,
|
||||||
|
want: nil,
|
||||||
|
}, {
|
||||||
|
// explicit nil error is nil
|
||||||
|
err: (error)(nil),
|
||||||
|
want: nil,
|
||||||
|
}, {
|
||||||
|
// typed nil is nil
|
||||||
|
err: (*nilError)(nil),
|
||||||
|
want: (*nilError)(nil),
|
||||||
|
}, {
|
||||||
|
// uncaused error is unaffected
|
||||||
|
err: io.EOF,
|
||||||
|
want: io.EOF,
|
||||||
|
}, {
|
||||||
|
// caused error returns cause
|
||||||
|
err: Wrap(io.EOF, "ignored"),
|
||||||
|
want: io.EOF,
|
||||||
|
}, {
|
||||||
|
err: x, // return from errors.New
|
||||||
|
want: x,
|
||||||
|
}, {
|
||||||
|
WithMessage(nil, "whoops"),
|
||||||
|
nil,
|
||||||
|
}, {
|
||||||
|
WithMessage(io.EOF, "whoops"),
|
||||||
|
io.EOF,
|
||||||
|
}, {
|
||||||
|
WithStack(nil),
|
||||||
|
nil,
|
||||||
|
}, {
|
||||||
|
WithStack(io.EOF),
|
||||||
|
io.EOF,
|
||||||
|
}}
|
||||||
|
|
||||||
|
for i, tt := range tests {
|
||||||
|
got := Cause(tt.err)
|
||||||
|
if !reflect.DeepEqual(got, tt.want) {
|
||||||
|
t.Errorf("test %d: got %#v, want %#v", i+1, got, tt.want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWrapfNil(t *testing.T) {
|
||||||
|
got := Wrapf(nil, "no error")
|
||||||
|
if got != nil {
|
||||||
|
t.Errorf("Wrapf(nil, \"no error\"): got %#v, expected nil", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWrapf(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
err error
|
||||||
|
message string
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{io.EOF, "read error", "read error: EOF"},
|
||||||
|
{Wrapf(io.EOF, "read error without format specifiers"), "client error", "client error: read error without format specifiers: EOF"},
|
||||||
|
{Wrapf(io.EOF, "read error with %d format specifier", 1), "client error", "client error: read error with 1 format specifier: EOF"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
got := Wrapf(tt.err, tt.message).Error()
|
||||||
|
if got != tt.want {
|
||||||
|
t.Errorf("Wrapf(%v, %q): got: %v, want %v", tt.err, tt.message, got, tt.want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestErrorf(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
err error
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{Errorf("read error without format specifiers"), "read error without format specifiers"},
|
||||||
|
{Errorf("read error with %d format specifier", 1), "read error with 1 format specifier"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
got := tt.err.Error()
|
||||||
|
if got != tt.want {
|
||||||
|
t.Errorf("Errorf(%v): got: %q, want %q", tt.err, got, tt.want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWithStackNil(t *testing.T) {
|
||||||
|
got := WithStack(nil)
|
||||||
|
if got != nil {
|
||||||
|
t.Errorf("WithStack(nil): got %#v, expected nil", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWithStack(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
err error
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{io.EOF, "EOF"},
|
||||||
|
{WithStack(io.EOF), "EOF"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
got := WithStack(tt.err).Error()
|
||||||
|
if got != tt.want {
|
||||||
|
t.Errorf("WithStack(%v): got: %v, want %v", tt.err, got, tt.want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWithMessageNil(t *testing.T) {
|
||||||
|
got := WithMessage(nil, "no error")
|
||||||
|
if got != nil {
|
||||||
|
t.Errorf("WithMessage(nil, \"no error\"): got %#v, expected nil", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWithMessage(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
err error
|
||||||
|
message string
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{io.EOF, "read error", "read error: EOF"},
|
||||||
|
{WithMessage(io.EOF, "read error"), "client error", "client error: read error: EOF"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
got := WithMessage(tt.err, tt.message).Error()
|
||||||
|
if got != tt.want {
|
||||||
|
t.Errorf("WithMessage(%v, %q): got: %q, want %q", tt.err, tt.message, got, tt.want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWithMessagefNil(t *testing.T) {
|
||||||
|
got := WithMessagef(nil, "no error")
|
||||||
|
if got != nil {
|
||||||
|
t.Errorf("WithMessage(nil, \"no error\"): got %#v, expected nil", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWithMessagef(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
err error
|
||||||
|
message string
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{io.EOF, "read error", "read error: EOF"},
|
||||||
|
{WithMessagef(io.EOF, "read error without format specifier"), "client error", "client error: read error without format specifier: EOF"},
|
||||||
|
{WithMessagef(io.EOF, "read error with %d format specifier", 1), "client error", "client error: read error with 1 format specifier: EOF"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
got := WithMessagef(tt.err, tt.message).Error()
|
||||||
|
if got != tt.want {
|
||||||
|
t.Errorf("WithMessage(%v, %q): got: %q, want %q", tt.err, tt.message, got, tt.want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// errors.New, etc values are not expected to be compared by value
|
||||||
|
// but the change in errors#27 made them incomparable. Assert that
|
||||||
|
// various kinds of errors have a functional equality operator, even
|
||||||
|
// if the result of that equality is always false.
|
||||||
|
func TestErrorEquality(t *testing.T) {
|
||||||
|
vals := []error{
|
||||||
|
nil,
|
||||||
|
io.EOF,
|
||||||
|
errors.New("EOF"),
|
||||||
|
New("EOF"),
|
||||||
|
Errorf("EOF"),
|
||||||
|
Wrap(io.EOF, "EOF"),
|
||||||
|
Wrapf(io.EOF, "EOF%d", 2),
|
||||||
|
WithMessage(nil, "whoops"),
|
||||||
|
WithMessage(io.EOF, "whoops"),
|
||||||
|
WithStack(io.EOF),
|
||||||
|
WithStack(nil),
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range vals {
|
||||||
|
for j := range vals {
|
||||||
|
_ = vals[i] == vals[j] // mustn't panic
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
205
vendor/github.com/pkg/errors/example_test.go
generated
vendored
Normal file
205
vendor/github.com/pkg/errors/example_test.go
generated
vendored
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
package errors_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ExampleNew() {
|
||||||
|
err := errors.New("whoops")
|
||||||
|
fmt.Println(err)
|
||||||
|
|
||||||
|
// Output: whoops
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleNew_printf() {
|
||||||
|
err := errors.New("whoops")
|
||||||
|
fmt.Printf("%+v", err)
|
||||||
|
|
||||||
|
// Example output:
|
||||||
|
// whoops
|
||||||
|
// github.com/pkg/errors_test.ExampleNew_printf
|
||||||
|
// /home/dfc/src/github.com/pkg/errors/example_test.go:17
|
||||||
|
// testing.runExample
|
||||||
|
// /home/dfc/go/src/testing/example.go:114
|
||||||
|
// testing.RunExamples
|
||||||
|
// /home/dfc/go/src/testing/example.go:38
|
||||||
|
// testing.(*M).Run
|
||||||
|
// /home/dfc/go/src/testing/testing.go:744
|
||||||
|
// main.main
|
||||||
|
// /github.com/pkg/errors/_test/_testmain.go:106
|
||||||
|
// runtime.main
|
||||||
|
// /home/dfc/go/src/runtime/proc.go:183
|
||||||
|
// runtime.goexit
|
||||||
|
// /home/dfc/go/src/runtime/asm_amd64.s:2059
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleWithMessage() {
|
||||||
|
cause := errors.New("whoops")
|
||||||
|
err := errors.WithMessage(cause, "oh noes")
|
||||||
|
fmt.Println(err)
|
||||||
|
|
||||||
|
// Output: oh noes: whoops
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleWithStack() {
|
||||||
|
cause := errors.New("whoops")
|
||||||
|
err := errors.WithStack(cause)
|
||||||
|
fmt.Println(err)
|
||||||
|
|
||||||
|
// Output: whoops
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleWithStack_printf() {
|
||||||
|
cause := errors.New("whoops")
|
||||||
|
err := errors.WithStack(cause)
|
||||||
|
fmt.Printf("%+v", err)
|
||||||
|
|
||||||
|
// Example Output:
|
||||||
|
// whoops
|
||||||
|
// github.com/pkg/errors_test.ExampleWithStack_printf
|
||||||
|
// /home/fabstu/go/src/github.com/pkg/errors/example_test.go:55
|
||||||
|
// testing.runExample
|
||||||
|
// /usr/lib/go/src/testing/example.go:114
|
||||||
|
// testing.RunExamples
|
||||||
|
// /usr/lib/go/src/testing/example.go:38
|
||||||
|
// testing.(*M).Run
|
||||||
|
// /usr/lib/go/src/testing/testing.go:744
|
||||||
|
// main.main
|
||||||
|
// github.com/pkg/errors/_test/_testmain.go:106
|
||||||
|
// runtime.main
|
||||||
|
// /usr/lib/go/src/runtime/proc.go:183
|
||||||
|
// runtime.goexit
|
||||||
|
// /usr/lib/go/src/runtime/asm_amd64.s:2086
|
||||||
|
// github.com/pkg/errors_test.ExampleWithStack_printf
|
||||||
|
// /home/fabstu/go/src/github.com/pkg/errors/example_test.go:56
|
||||||
|
// testing.runExample
|
||||||
|
// /usr/lib/go/src/testing/example.go:114
|
||||||
|
// testing.RunExamples
|
||||||
|
// /usr/lib/go/src/testing/example.go:38
|
||||||
|
// testing.(*M).Run
|
||||||
|
// /usr/lib/go/src/testing/testing.go:744
|
||||||
|
// main.main
|
||||||
|
// github.com/pkg/errors/_test/_testmain.go:106
|
||||||
|
// runtime.main
|
||||||
|
// /usr/lib/go/src/runtime/proc.go:183
|
||||||
|
// runtime.goexit
|
||||||
|
// /usr/lib/go/src/runtime/asm_amd64.s:2086
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleWrap() {
|
||||||
|
cause := errors.New("whoops")
|
||||||
|
err := errors.Wrap(cause, "oh noes")
|
||||||
|
fmt.Println(err)
|
||||||
|
|
||||||
|
// Output: oh noes: whoops
|
||||||
|
}
|
||||||
|
|
||||||
|
func fn() error {
|
||||||
|
e1 := errors.New("error")
|
||||||
|
e2 := errors.Wrap(e1, "inner")
|
||||||
|
e3 := errors.Wrap(e2, "middle")
|
||||||
|
return errors.Wrap(e3, "outer")
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleCause() {
|
||||||
|
err := fn()
|
||||||
|
fmt.Println(err)
|
||||||
|
fmt.Println(errors.Cause(err))
|
||||||
|
|
||||||
|
// Output: outer: middle: inner: error
|
||||||
|
// error
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleWrap_extended() {
|
||||||
|
err := fn()
|
||||||
|
fmt.Printf("%+v\n", err)
|
||||||
|
|
||||||
|
// Example output:
|
||||||
|
// error
|
||||||
|
// github.com/pkg/errors_test.fn
|
||||||
|
// /home/dfc/src/github.com/pkg/errors/example_test.go:47
|
||||||
|
// github.com/pkg/errors_test.ExampleCause_printf
|
||||||
|
// /home/dfc/src/github.com/pkg/errors/example_test.go:63
|
||||||
|
// testing.runExample
|
||||||
|
// /home/dfc/go/src/testing/example.go:114
|
||||||
|
// testing.RunExamples
|
||||||
|
// /home/dfc/go/src/testing/example.go:38
|
||||||
|
// testing.(*M).Run
|
||||||
|
// /home/dfc/go/src/testing/testing.go:744
|
||||||
|
// main.main
|
||||||
|
// /github.com/pkg/errors/_test/_testmain.go:104
|
||||||
|
// runtime.main
|
||||||
|
// /home/dfc/go/src/runtime/proc.go:183
|
||||||
|
// runtime.goexit
|
||||||
|
// /home/dfc/go/src/runtime/asm_amd64.s:2059
|
||||||
|
// github.com/pkg/errors_test.fn
|
||||||
|
// /home/dfc/src/github.com/pkg/errors/example_test.go:48: inner
|
||||||
|
// github.com/pkg/errors_test.fn
|
||||||
|
// /home/dfc/src/github.com/pkg/errors/example_test.go:49: middle
|
||||||
|
// github.com/pkg/errors_test.fn
|
||||||
|
// /home/dfc/src/github.com/pkg/errors/example_test.go:50: outer
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleWrapf() {
|
||||||
|
cause := errors.New("whoops")
|
||||||
|
err := errors.Wrapf(cause, "oh noes #%d", 2)
|
||||||
|
fmt.Println(err)
|
||||||
|
|
||||||
|
// Output: oh noes #2: whoops
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleErrorf_extended() {
|
||||||
|
err := errors.Errorf("whoops: %s", "foo")
|
||||||
|
fmt.Printf("%+v", err)
|
||||||
|
|
||||||
|
// Example output:
|
||||||
|
// whoops: foo
|
||||||
|
// github.com/pkg/errors_test.ExampleErrorf
|
||||||
|
// /home/dfc/src/github.com/pkg/errors/example_test.go:101
|
||||||
|
// testing.runExample
|
||||||
|
// /home/dfc/go/src/testing/example.go:114
|
||||||
|
// testing.RunExamples
|
||||||
|
// /home/dfc/go/src/testing/example.go:38
|
||||||
|
// testing.(*M).Run
|
||||||
|
// /home/dfc/go/src/testing/testing.go:744
|
||||||
|
// main.main
|
||||||
|
// /github.com/pkg/errors/_test/_testmain.go:102
|
||||||
|
// runtime.main
|
||||||
|
// /home/dfc/go/src/runtime/proc.go:183
|
||||||
|
// runtime.goexit
|
||||||
|
// /home/dfc/go/src/runtime/asm_amd64.s:2059
|
||||||
|
}
|
||||||
|
|
||||||
|
func Example_stackTrace() {
|
||||||
|
type stackTracer interface {
|
||||||
|
StackTrace() errors.StackTrace
|
||||||
|
}
|
||||||
|
|
||||||
|
err, ok := errors.Cause(fn()).(stackTracer)
|
||||||
|
if !ok {
|
||||||
|
panic("oops, err does not implement stackTracer")
|
||||||
|
}
|
||||||
|
|
||||||
|
st := err.StackTrace()
|
||||||
|
fmt.Printf("%+v", st[0:2]) // top two frames
|
||||||
|
|
||||||
|
// Example output:
|
||||||
|
// github.com/pkg/errors_test.fn
|
||||||
|
// /home/dfc/src/github.com/pkg/errors/example_test.go:47
|
||||||
|
// github.com/pkg/errors_test.Example_stackTrace
|
||||||
|
// /home/dfc/src/github.com/pkg/errors/example_test.go:127
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleCause_printf() {
|
||||||
|
err := errors.Wrap(func() error {
|
||||||
|
return func() error {
|
||||||
|
return errors.Errorf("hello %s", fmt.Sprintf("world"))
|
||||||
|
}()
|
||||||
|
}(), "failed")
|
||||||
|
|
||||||
|
fmt.Printf("%v", err)
|
||||||
|
|
||||||
|
// Output: failed: hello world
|
||||||
|
}
|
535
vendor/github.com/pkg/errors/format_test.go
generated
vendored
Normal file
535
vendor/github.com/pkg/errors/format_test.go
generated
vendored
Normal file
@ -0,0 +1,535 @@
|
|||||||
|
package errors
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFormatNew(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
error
|
||||||
|
format string
|
||||||
|
want string
|
||||||
|
}{{
|
||||||
|
New("error"),
|
||||||
|
"%s",
|
||||||
|
"error",
|
||||||
|
}, {
|
||||||
|
New("error"),
|
||||||
|
"%v",
|
||||||
|
"error",
|
||||||
|
}, {
|
||||||
|
New("error"),
|
||||||
|
"%+v",
|
||||||
|
"error\n" +
|
||||||
|
"github.com/pkg/errors.TestFormatNew\n" +
|
||||||
|
"\t.+/github.com/pkg/errors/format_test.go:26",
|
||||||
|
}, {
|
||||||
|
New("error"),
|
||||||
|
"%q",
|
||||||
|
`"error"`,
|
||||||
|
}}
|
||||||
|
|
||||||
|
for i, tt := range tests {
|
||||||
|
testFormatRegexp(t, i, tt.error, tt.format, tt.want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFormatErrorf(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
error
|
||||||
|
format string
|
||||||
|
want string
|
||||||
|
}{{
|
||||||
|
Errorf("%s", "error"),
|
||||||
|
"%s",
|
||||||
|
"error",
|
||||||
|
}, {
|
||||||
|
Errorf("%s", "error"),
|
||||||
|
"%v",
|
||||||
|
"error",
|
||||||
|
}, {
|
||||||
|
Errorf("%s", "error"),
|
||||||
|
"%+v",
|
||||||
|
"error\n" +
|
||||||
|
"github.com/pkg/errors.TestFormatErrorf\n" +
|
||||||
|
"\t.+/github.com/pkg/errors/format_test.go:56",
|
||||||
|
}}
|
||||||
|
|
||||||
|
for i, tt := range tests {
|
||||||
|
testFormatRegexp(t, i, tt.error, tt.format, tt.want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFormatWrap(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
error
|
||||||
|
format string
|
||||||
|
want string
|
||||||
|
}{{
|
||||||
|
Wrap(New("error"), "error2"),
|
||||||
|
"%s",
|
||||||
|
"error2: error",
|
||||||
|
}, {
|
||||||
|
Wrap(New("error"), "error2"),
|
||||||
|
"%v",
|
||||||
|
"error2: error",
|
||||||
|
}, {
|
||||||
|
Wrap(New("error"), "error2"),
|
||||||
|
"%+v",
|
||||||
|
"error\n" +
|
||||||
|
"github.com/pkg/errors.TestFormatWrap\n" +
|
||||||
|
"\t.+/github.com/pkg/errors/format_test.go:82",
|
||||||
|
}, {
|
||||||
|
Wrap(io.EOF, "error"),
|
||||||
|
"%s",
|
||||||
|
"error: EOF",
|
||||||
|
}, {
|
||||||
|
Wrap(io.EOF, "error"),
|
||||||
|
"%v",
|
||||||
|
"error: EOF",
|
||||||
|
}, {
|
||||||
|
Wrap(io.EOF, "error"),
|
||||||
|
"%+v",
|
||||||
|
"EOF\n" +
|
||||||
|
"error\n" +
|
||||||
|
"github.com/pkg/errors.TestFormatWrap\n" +
|
||||||
|
"\t.+/github.com/pkg/errors/format_test.go:96",
|
||||||
|
}, {
|
||||||
|
Wrap(Wrap(io.EOF, "error1"), "error2"),
|
||||||
|
"%+v",
|
||||||
|
"EOF\n" +
|
||||||
|
"error1\n" +
|
||||||
|
"github.com/pkg/errors.TestFormatWrap\n" +
|
||||||
|
"\t.+/github.com/pkg/errors/format_test.go:103\n",
|
||||||
|
}, {
|
||||||
|
Wrap(New("error with space"), "context"),
|
||||||
|
"%q",
|
||||||
|
`"context: error with space"`,
|
||||||
|
}}
|
||||||
|
|
||||||
|
for i, tt := range tests {
|
||||||
|
testFormatRegexp(t, i, tt.error, tt.format, tt.want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFormatWrapf(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
error
|
||||||
|
format string
|
||||||
|
want string
|
||||||
|
}{{
|
||||||
|
Wrapf(io.EOF, "error%d", 2),
|
||||||
|
"%s",
|
||||||
|
"error2: EOF",
|
||||||
|
}, {
|
||||||
|
Wrapf(io.EOF, "error%d", 2),
|
||||||
|
"%v",
|
||||||
|
"error2: EOF",
|
||||||
|
}, {
|
||||||
|
Wrapf(io.EOF, "error%d", 2),
|
||||||
|
"%+v",
|
||||||
|
"EOF\n" +
|
||||||
|
"error2\n" +
|
||||||
|
"github.com/pkg/errors.TestFormatWrapf\n" +
|
||||||
|
"\t.+/github.com/pkg/errors/format_test.go:134",
|
||||||
|
}, {
|
||||||
|
Wrapf(New("error"), "error%d", 2),
|
||||||
|
"%s",
|
||||||
|
"error2: error",
|
||||||
|
}, {
|
||||||
|
Wrapf(New("error"), "error%d", 2),
|
||||||
|
"%v",
|
||||||
|
"error2: error",
|
||||||
|
}, {
|
||||||
|
Wrapf(New("error"), "error%d", 2),
|
||||||
|
"%+v",
|
||||||
|
"error\n" +
|
||||||
|
"github.com/pkg/errors.TestFormatWrapf\n" +
|
||||||
|
"\t.+/github.com/pkg/errors/format_test.go:149",
|
||||||
|
}}
|
||||||
|
|
||||||
|
for i, tt := range tests {
|
||||||
|
testFormatRegexp(t, i, tt.error, tt.format, tt.want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFormatWithStack(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
error
|
||||||
|
format string
|
||||||
|
want []string
|
||||||
|
}{{
|
||||||
|
WithStack(io.EOF),
|
||||||
|
"%s",
|
||||||
|
[]string{"EOF"},
|
||||||
|
}, {
|
||||||
|
WithStack(io.EOF),
|
||||||
|
"%v",
|
||||||
|
[]string{"EOF"},
|
||||||
|
}, {
|
||||||
|
WithStack(io.EOF),
|
||||||
|
"%+v",
|
||||||
|
[]string{"EOF",
|
||||||
|
"github.com/pkg/errors.TestFormatWithStack\n" +
|
||||||
|
"\t.+/github.com/pkg/errors/format_test.go:175"},
|
||||||
|
}, {
|
||||||
|
WithStack(New("error")),
|
||||||
|
"%s",
|
||||||
|
[]string{"error"},
|
||||||
|
}, {
|
||||||
|
WithStack(New("error")),
|
||||||
|
"%v",
|
||||||
|
[]string{"error"},
|
||||||
|
}, {
|
||||||
|
WithStack(New("error")),
|
||||||
|
"%+v",
|
||||||
|
[]string{"error",
|
||||||
|
"github.com/pkg/errors.TestFormatWithStack\n" +
|
||||||
|
"\t.+/github.com/pkg/errors/format_test.go:189",
|
||||||
|
"github.com/pkg/errors.TestFormatWithStack\n" +
|
||||||
|
"\t.+/github.com/pkg/errors/format_test.go:189"},
|
||||||
|
}, {
|
||||||
|
WithStack(WithStack(io.EOF)),
|
||||||
|
"%+v",
|
||||||
|
[]string{"EOF",
|
||||||
|
"github.com/pkg/errors.TestFormatWithStack\n" +
|
||||||
|
"\t.+/github.com/pkg/errors/format_test.go:197",
|
||||||
|
"github.com/pkg/errors.TestFormatWithStack\n" +
|
||||||
|
"\t.+/github.com/pkg/errors/format_test.go:197"},
|
||||||
|
}, {
|
||||||
|
WithStack(WithStack(Wrapf(io.EOF, "message"))),
|
||||||
|
"%+v",
|
||||||
|
[]string{"EOF",
|
||||||
|
"message",
|
||||||
|
"github.com/pkg/errors.TestFormatWithStack\n" +
|
||||||
|
"\t.+/github.com/pkg/errors/format_test.go:205",
|
||||||
|
"github.com/pkg/errors.TestFormatWithStack\n" +
|
||||||
|
"\t.+/github.com/pkg/errors/format_test.go:205",
|
||||||
|
"github.com/pkg/errors.TestFormatWithStack\n" +
|
||||||
|
"\t.+/github.com/pkg/errors/format_test.go:205"},
|
||||||
|
}, {
|
||||||
|
WithStack(Errorf("error%d", 1)),
|
||||||
|
"%+v",
|
||||||
|
[]string{"error1",
|
||||||
|
"github.com/pkg/errors.TestFormatWithStack\n" +
|
||||||
|
"\t.+/github.com/pkg/errors/format_test.go:216",
|
||||||
|
"github.com/pkg/errors.TestFormatWithStack\n" +
|
||||||
|
"\t.+/github.com/pkg/errors/format_test.go:216"},
|
||||||
|
}}
|
||||||
|
|
||||||
|
for i, tt := range tests {
|
||||||
|
testFormatCompleteCompare(t, i, tt.error, tt.format, tt.want, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFormatWithMessage(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
error
|
||||||
|
format string
|
||||||
|
want []string
|
||||||
|
}{{
|
||||||
|
WithMessage(New("error"), "error2"),
|
||||||
|
"%s",
|
||||||
|
[]string{"error2: error"},
|
||||||
|
}, {
|
||||||
|
WithMessage(New("error"), "error2"),
|
||||||
|
"%v",
|
||||||
|
[]string{"error2: error"},
|
||||||
|
}, {
|
||||||
|
WithMessage(New("error"), "error2"),
|
||||||
|
"%+v",
|
||||||
|
[]string{
|
||||||
|
"error",
|
||||||
|
"github.com/pkg/errors.TestFormatWithMessage\n" +
|
||||||
|
"\t.+/github.com/pkg/errors/format_test.go:244",
|
||||||
|
"error2"},
|
||||||
|
}, {
|
||||||
|
WithMessage(io.EOF, "addition1"),
|
||||||
|
"%s",
|
||||||
|
[]string{"addition1: EOF"},
|
||||||
|
}, {
|
||||||
|
WithMessage(io.EOF, "addition1"),
|
||||||
|
"%v",
|
||||||
|
[]string{"addition1: EOF"},
|
||||||
|
}, {
|
||||||
|
WithMessage(io.EOF, "addition1"),
|
||||||
|
"%+v",
|
||||||
|
[]string{"EOF", "addition1"},
|
||||||
|
}, {
|
||||||
|
WithMessage(WithMessage(io.EOF, "addition1"), "addition2"),
|
||||||
|
"%v",
|
||||||
|
[]string{"addition2: addition1: EOF"},
|
||||||
|
}, {
|
||||||
|
WithMessage(WithMessage(io.EOF, "addition1"), "addition2"),
|
||||||
|
"%+v",
|
||||||
|
[]string{"EOF", "addition1", "addition2"},
|
||||||
|
}, {
|
||||||
|
Wrap(WithMessage(io.EOF, "error1"), "error2"),
|
||||||
|
"%+v",
|
||||||
|
[]string{"EOF", "error1", "error2",
|
||||||
|
"github.com/pkg/errors.TestFormatWithMessage\n" +
|
||||||
|
"\t.+/github.com/pkg/errors/format_test.go:272"},
|
||||||
|
}, {
|
||||||
|
WithMessage(Errorf("error%d", 1), "error2"),
|
||||||
|
"%+v",
|
||||||
|
[]string{"error1",
|
||||||
|
"github.com/pkg/errors.TestFormatWithMessage\n" +
|
||||||
|
"\t.+/github.com/pkg/errors/format_test.go:278",
|
||||||
|
"error2"},
|
||||||
|
}, {
|
||||||
|
WithMessage(WithStack(io.EOF), "error"),
|
||||||
|
"%+v",
|
||||||
|
[]string{
|
||||||
|
"EOF",
|
||||||
|
"github.com/pkg/errors.TestFormatWithMessage\n" +
|
||||||
|
"\t.+/github.com/pkg/errors/format_test.go:285",
|
||||||
|
"error"},
|
||||||
|
}, {
|
||||||
|
WithMessage(Wrap(WithStack(io.EOF), "inside-error"), "outside-error"),
|
||||||
|
"%+v",
|
||||||
|
[]string{
|
||||||
|
"EOF",
|
||||||
|
"github.com/pkg/errors.TestFormatWithMessage\n" +
|
||||||
|
"\t.+/github.com/pkg/errors/format_test.go:293",
|
||||||
|
"inside-error",
|
||||||
|
"github.com/pkg/errors.TestFormatWithMessage\n" +
|
||||||
|
"\t.+/github.com/pkg/errors/format_test.go:293",
|
||||||
|
"outside-error"},
|
||||||
|
}}
|
||||||
|
|
||||||
|
for i, tt := range tests {
|
||||||
|
testFormatCompleteCompare(t, i, tt.error, tt.format, tt.want, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFormatGeneric(t *testing.T) {
|
||||||
|
starts := []struct {
|
||||||
|
err error
|
||||||
|
want []string
|
||||||
|
}{
|
||||||
|
{New("new-error"), []string{
|
||||||
|
"new-error",
|
||||||
|
"github.com/pkg/errors.TestFormatGeneric\n" +
|
||||||
|
"\t.+/github.com/pkg/errors/format_test.go:315"},
|
||||||
|
}, {Errorf("errorf-error"), []string{
|
||||||
|
"errorf-error",
|
||||||
|
"github.com/pkg/errors.TestFormatGeneric\n" +
|
||||||
|
"\t.+/github.com/pkg/errors/format_test.go:319"},
|
||||||
|
}, {errors.New("errors-new-error"), []string{
|
||||||
|
"errors-new-error"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
wrappers := []wrapper{
|
||||||
|
{
|
||||||
|
func(err error) error { return WithMessage(err, "with-message") },
|
||||||
|
[]string{"with-message"},
|
||||||
|
}, {
|
||||||
|
func(err error) error { return WithStack(err) },
|
||||||
|
[]string{
|
||||||
|
"github.com/pkg/errors.(func·002|TestFormatGeneric.func2)\n\t" +
|
||||||
|
".+/github.com/pkg/errors/format_test.go:333",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
func(err error) error { return Wrap(err, "wrap-error") },
|
||||||
|
[]string{
|
||||||
|
"wrap-error",
|
||||||
|
"github.com/pkg/errors.(func·003|TestFormatGeneric.func3)\n\t" +
|
||||||
|
".+/github.com/pkg/errors/format_test.go:339",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
func(err error) error { return Wrapf(err, "wrapf-error%d", 1) },
|
||||||
|
[]string{
|
||||||
|
"wrapf-error1",
|
||||||
|
"github.com/pkg/errors.(func·004|TestFormatGeneric.func4)\n\t" +
|
||||||
|
".+/github.com/pkg/errors/format_test.go:346",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for s := range starts {
|
||||||
|
err := starts[s].err
|
||||||
|
want := starts[s].want
|
||||||
|
testFormatCompleteCompare(t, s, err, "%+v", want, false)
|
||||||
|
testGenericRecursive(t, err, want, wrappers, 3)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testFormatRegexp(t *testing.T, n int, arg interface{}, format, want string) {
|
||||||
|
got := fmt.Sprintf(format, arg)
|
||||||
|
gotLines := strings.SplitN(got, "\n", -1)
|
||||||
|
wantLines := strings.SplitN(want, "\n", -1)
|
||||||
|
|
||||||
|
if len(wantLines) > len(gotLines) {
|
||||||
|
t.Errorf("test %d: wantLines(%d) > gotLines(%d):\n got: %q\nwant: %q", n+1, len(wantLines), len(gotLines), got, want)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, w := range wantLines {
|
||||||
|
match, err := regexp.MatchString(w, gotLines[i])
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if !match {
|
||||||
|
t.Errorf("test %d: line %d: fmt.Sprintf(%q, err):\n got: %q\nwant: %q", n+1, i+1, format, got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var stackLineR = regexp.MustCompile(`\.`)
|
||||||
|
|
||||||
|
// parseBlocks parses input into a slice, where:
|
||||||
|
// - incase entry contains a newline, its a stacktrace
|
||||||
|
// - incase entry contains no newline, its a solo line.
|
||||||
|
//
|
||||||
|
// Detecting stack boundaries only works incase the WithStack-calls are
|
||||||
|
// to be found on the same line, thats why it is optionally here.
|
||||||
|
//
|
||||||
|
// Example use:
|
||||||
|
//
|
||||||
|
// for _, e := range blocks {
|
||||||
|
// if strings.ContainsAny(e, "\n") {
|
||||||
|
// // Match as stack
|
||||||
|
// } else {
|
||||||
|
// // Match as line
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
func parseBlocks(input string, detectStackboundaries bool) ([]string, error) {
|
||||||
|
var blocks []string
|
||||||
|
|
||||||
|
stack := ""
|
||||||
|
wasStack := false
|
||||||
|
lines := map[string]bool{} // already found lines
|
||||||
|
|
||||||
|
for _, l := range strings.Split(input, "\n") {
|
||||||
|
isStackLine := stackLineR.MatchString(l)
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case !isStackLine && wasStack:
|
||||||
|
blocks = append(blocks, stack, l)
|
||||||
|
stack = ""
|
||||||
|
lines = map[string]bool{}
|
||||||
|
case isStackLine:
|
||||||
|
if wasStack {
|
||||||
|
// Detecting two stacks after another, possible cause lines match in
|
||||||
|
// our tests due to WithStack(WithStack(io.EOF)) on same line.
|
||||||
|
if detectStackboundaries {
|
||||||
|
if lines[l] {
|
||||||
|
if len(stack) == 0 {
|
||||||
|
return nil, errors.New("len of block must not be zero here")
|
||||||
|
}
|
||||||
|
|
||||||
|
blocks = append(blocks, stack)
|
||||||
|
stack = l
|
||||||
|
lines = map[string]bool{l: true}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stack = stack + "\n" + l
|
||||||
|
} else {
|
||||||
|
stack = l
|
||||||
|
}
|
||||||
|
lines[l] = true
|
||||||
|
case !isStackLine && !wasStack:
|
||||||
|
blocks = append(blocks, l)
|
||||||
|
default:
|
||||||
|
return nil, errors.New("must not happen")
|
||||||
|
}
|
||||||
|
|
||||||
|
wasStack = isStackLine
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use up stack
|
||||||
|
if stack != "" {
|
||||||
|
blocks = append(blocks, stack)
|
||||||
|
}
|
||||||
|
return blocks, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func testFormatCompleteCompare(t *testing.T, n int, arg interface{}, format string, want []string, detectStackBoundaries bool) {
|
||||||
|
gotStr := fmt.Sprintf(format, arg)
|
||||||
|
|
||||||
|
got, err := parseBlocks(gotStr, detectStackBoundaries)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(got) != len(want) {
|
||||||
|
t.Fatalf("test %d: fmt.Sprintf(%s, err) -> wrong number of blocks: got(%d) want(%d)\n got: %s\nwant: %s\ngotStr: %q",
|
||||||
|
n+1, format, len(got), len(want), prettyBlocks(got), prettyBlocks(want), gotStr)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range got {
|
||||||
|
if strings.ContainsAny(want[i], "\n") {
|
||||||
|
// Match as stack
|
||||||
|
match, err := regexp.MatchString(want[i], got[i])
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if !match {
|
||||||
|
t.Fatalf("test %d: block %d: fmt.Sprintf(%q, err):\ngot:\n%q\nwant:\n%q\nall-got:\n%s\nall-want:\n%s\n",
|
||||||
|
n+1, i+1, format, got[i], want[i], prettyBlocks(got), prettyBlocks(want))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Match as message
|
||||||
|
if got[i] != want[i] {
|
||||||
|
t.Fatalf("test %d: fmt.Sprintf(%s, err) at block %d got != want:\n got: %q\nwant: %q", n+1, format, i+1, got[i], want[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type wrapper struct {
|
||||||
|
wrap func(err error) error
|
||||||
|
want []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func prettyBlocks(blocks []string) string {
|
||||||
|
var out []string
|
||||||
|
|
||||||
|
for _, b := range blocks {
|
||||||
|
out = append(out, fmt.Sprintf("%v", b))
|
||||||
|
}
|
||||||
|
|
||||||
|
return " " + strings.Join(out, "\n ")
|
||||||
|
}
|
||||||
|
|
||||||
|
func testGenericRecursive(t *testing.T, beforeErr error, beforeWant []string, list []wrapper, maxDepth int) {
|
||||||
|
if len(beforeWant) == 0 {
|
||||||
|
panic("beforeWant must not be empty")
|
||||||
|
}
|
||||||
|
for _, w := range list {
|
||||||
|
if len(w.want) == 0 {
|
||||||
|
panic("want must not be empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
err := w.wrap(beforeErr)
|
||||||
|
|
||||||
|
// Copy required cause append(beforeWant, ..) modified beforeWant subtly.
|
||||||
|
beforeCopy := make([]string, len(beforeWant))
|
||||||
|
copy(beforeCopy, beforeWant)
|
||||||
|
|
||||||
|
beforeWant := beforeCopy
|
||||||
|
last := len(beforeWant) - 1
|
||||||
|
var want []string
|
||||||
|
|
||||||
|
// Merge two stacks behind each other.
|
||||||
|
if strings.ContainsAny(beforeWant[last], "\n") && strings.ContainsAny(w.want[0], "\n") {
|
||||||
|
want = append(beforeWant[:last], append([]string{beforeWant[last] + "((?s).*)" + w.want[0]}, w.want[1:]...)...)
|
||||||
|
} else {
|
||||||
|
want = append(beforeWant, w.want...)
|
||||||
|
}
|
||||||
|
|
||||||
|
testFormatCompleteCompare(t, maxDepth, err, "%+v", want, false)
|
||||||
|
if maxDepth > 0 {
|
||||||
|
testGenericRecursive(t, err, want, list, maxDepth-1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
147
vendor/github.com/pkg/errors/stack.go
generated
vendored
Normal file
147
vendor/github.com/pkg/errors/stack.go
generated
vendored
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
package errors
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"path"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Frame represents a program counter inside a stack frame.
|
||||||
|
type Frame uintptr
|
||||||
|
|
||||||
|
// pc returns the program counter for this frame;
|
||||||
|
// multiple frames may have the same PC value.
|
||||||
|
func (f Frame) pc() uintptr { return uintptr(f) - 1 }
|
||||||
|
|
||||||
|
// file returns the full path to the file that contains the
|
||||||
|
// function for this Frame's pc.
|
||||||
|
func (f Frame) file() string {
|
||||||
|
fn := runtime.FuncForPC(f.pc())
|
||||||
|
if fn == nil {
|
||||||
|
return "unknown"
|
||||||
|
}
|
||||||
|
file, _ := fn.FileLine(f.pc())
|
||||||
|
return file
|
||||||
|
}
|
||||||
|
|
||||||
|
// line returns the line number of source code of the
|
||||||
|
// function for this Frame's pc.
|
||||||
|
func (f Frame) line() int {
|
||||||
|
fn := runtime.FuncForPC(f.pc())
|
||||||
|
if fn == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
_, line := fn.FileLine(f.pc())
|
||||||
|
return line
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format formats the frame according to the fmt.Formatter interface.
|
||||||
|
//
|
||||||
|
// %s source file
|
||||||
|
// %d source line
|
||||||
|
// %n function name
|
||||||
|
// %v equivalent to %s:%d
|
||||||
|
//
|
||||||
|
// Format accepts flags that alter the printing of some verbs, as follows:
|
||||||
|
//
|
||||||
|
// %+s function name and path of source file relative to the compile time
|
||||||
|
// GOPATH separated by \n\t (<funcname>\n\t<path>)
|
||||||
|
// %+v equivalent to %+s:%d
|
||||||
|
func (f Frame) Format(s fmt.State, verb rune) {
|
||||||
|
switch verb {
|
||||||
|
case 's':
|
||||||
|
switch {
|
||||||
|
case s.Flag('+'):
|
||||||
|
pc := f.pc()
|
||||||
|
fn := runtime.FuncForPC(pc)
|
||||||
|
if fn == nil {
|
||||||
|
io.WriteString(s, "unknown")
|
||||||
|
} else {
|
||||||
|
file, _ := fn.FileLine(pc)
|
||||||
|
fmt.Fprintf(s, "%s\n\t%s", fn.Name(), file)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
io.WriteString(s, path.Base(f.file()))
|
||||||
|
}
|
||||||
|
case 'd':
|
||||||
|
fmt.Fprintf(s, "%d", f.line())
|
||||||
|
case 'n':
|
||||||
|
name := runtime.FuncForPC(f.pc()).Name()
|
||||||
|
io.WriteString(s, funcname(name))
|
||||||
|
case 'v':
|
||||||
|
f.Format(s, 's')
|
||||||
|
io.WriteString(s, ":")
|
||||||
|
f.Format(s, 'd')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// StackTrace is stack of Frames from innermost (newest) to outermost (oldest).
|
||||||
|
type StackTrace []Frame
|
||||||
|
|
||||||
|
// Format formats the stack of Frames according to the fmt.Formatter interface.
|
||||||
|
//
|
||||||
|
// %s lists source files for each Frame in the stack
|
||||||
|
// %v lists the source file and line number for each Frame in the stack
|
||||||
|
//
|
||||||
|
// Format accepts flags that alter the printing of some verbs, as follows:
|
||||||
|
//
|
||||||
|
// %+v Prints filename, function, and line number for each Frame in the stack.
|
||||||
|
func (st StackTrace) Format(s fmt.State, verb rune) {
|
||||||
|
switch verb {
|
||||||
|
case 'v':
|
||||||
|
switch {
|
||||||
|
case s.Flag('+'):
|
||||||
|
for _, f := range st {
|
||||||
|
fmt.Fprintf(s, "\n%+v", f)
|
||||||
|
}
|
||||||
|
case s.Flag('#'):
|
||||||
|
fmt.Fprintf(s, "%#v", []Frame(st))
|
||||||
|
default:
|
||||||
|
fmt.Fprintf(s, "%v", []Frame(st))
|
||||||
|
}
|
||||||
|
case 's':
|
||||||
|
fmt.Fprintf(s, "%s", []Frame(st))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// stack represents a stack of program counters.
|
||||||
|
type stack []uintptr
|
||||||
|
|
||||||
|
func (s *stack) Format(st fmt.State, verb rune) {
|
||||||
|
switch verb {
|
||||||
|
case 'v':
|
||||||
|
switch {
|
||||||
|
case st.Flag('+'):
|
||||||
|
for _, pc := range *s {
|
||||||
|
f := Frame(pc)
|
||||||
|
fmt.Fprintf(st, "\n%+v", f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *stack) StackTrace() StackTrace {
|
||||||
|
f := make([]Frame, len(*s))
|
||||||
|
for i := 0; i < len(f); i++ {
|
||||||
|
f[i] = Frame((*s)[i])
|
||||||
|
}
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
func callers() *stack {
|
||||||
|
const depth = 32
|
||||||
|
var pcs [depth]uintptr
|
||||||
|
n := runtime.Callers(3, pcs[:])
|
||||||
|
var st stack = pcs[0:n]
|
||||||
|
return &st
|
||||||
|
}
|
||||||
|
|
||||||
|
// funcname removes the path prefix component of a function's name reported by func.Name().
|
||||||
|
func funcname(name string) string {
|
||||||
|
i := strings.LastIndex(name, "/")
|
||||||
|
name = name[i+1:]
|
||||||
|
i = strings.Index(name, ".")
|
||||||
|
return name[i+1:]
|
||||||
|
}
|
274
vendor/github.com/pkg/errors/stack_test.go
generated
vendored
Normal file
274
vendor/github.com/pkg/errors/stack_test.go
generated
vendored
Normal file
@ -0,0 +1,274 @@
|
|||||||
|
package errors
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"runtime"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
var initpc, _, _, _ = runtime.Caller(0)
|
||||||
|
|
||||||
|
func TestFrameLine(t *testing.T) {
|
||||||
|
var tests = []struct {
|
||||||
|
Frame
|
||||||
|
want int
|
||||||
|
}{{
|
||||||
|
Frame(initpc),
|
||||||
|
9,
|
||||||
|
}, {
|
||||||
|
func() Frame {
|
||||||
|
var pc, _, _, _ = runtime.Caller(0)
|
||||||
|
return Frame(pc)
|
||||||
|
}(),
|
||||||
|
20,
|
||||||
|
}, {
|
||||||
|
func() Frame {
|
||||||
|
var pc, _, _, _ = runtime.Caller(1)
|
||||||
|
return Frame(pc)
|
||||||
|
}(),
|
||||||
|
28,
|
||||||
|
}, {
|
||||||
|
Frame(0), // invalid PC
|
||||||
|
0,
|
||||||
|
}}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
got := tt.Frame.line()
|
||||||
|
want := tt.want
|
||||||
|
if want != got {
|
||||||
|
t.Errorf("Frame(%v): want: %v, got: %v", uintptr(tt.Frame), want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type X struct{}
|
||||||
|
|
||||||
|
func (x X) val() Frame {
|
||||||
|
var pc, _, _, _ = runtime.Caller(0)
|
||||||
|
return Frame(pc)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *X) ptr() Frame {
|
||||||
|
var pc, _, _, _ = runtime.Caller(0)
|
||||||
|
return Frame(pc)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFrameFormat(t *testing.T) {
|
||||||
|
var tests = []struct {
|
||||||
|
Frame
|
||||||
|
format string
|
||||||
|
want string
|
||||||
|
}{{
|
||||||
|
Frame(initpc),
|
||||||
|
"%s",
|
||||||
|
"stack_test.go",
|
||||||
|
}, {
|
||||||
|
Frame(initpc),
|
||||||
|
"%+s",
|
||||||
|
"github.com/pkg/errors.init\n" +
|
||||||
|
"\t.+/github.com/pkg/errors/stack_test.go",
|
||||||
|
}, {
|
||||||
|
Frame(0),
|
||||||
|
"%s",
|
||||||
|
"unknown",
|
||||||
|
}, {
|
||||||
|
Frame(0),
|
||||||
|
"%+s",
|
||||||
|
"unknown",
|
||||||
|
}, {
|
||||||
|
Frame(initpc),
|
||||||
|
"%d",
|
||||||
|
"9",
|
||||||
|
}, {
|
||||||
|
Frame(0),
|
||||||
|
"%d",
|
||||||
|
"0",
|
||||||
|
}, {
|
||||||
|
Frame(initpc),
|
||||||
|
"%n",
|
||||||
|
"init",
|
||||||
|
}, {
|
||||||
|
func() Frame {
|
||||||
|
var x X
|
||||||
|
return x.ptr()
|
||||||
|
}(),
|
||||||
|
"%n",
|
||||||
|
`\(\*X\).ptr`,
|
||||||
|
}, {
|
||||||
|
func() Frame {
|
||||||
|
var x X
|
||||||
|
return x.val()
|
||||||
|
}(),
|
||||||
|
"%n",
|
||||||
|
"X.val",
|
||||||
|
}, {
|
||||||
|
Frame(0),
|
||||||
|
"%n",
|
||||||
|
"",
|
||||||
|
}, {
|
||||||
|
Frame(initpc),
|
||||||
|
"%v",
|
||||||
|
"stack_test.go:9",
|
||||||
|
}, {
|
||||||
|
Frame(initpc),
|
||||||
|
"%+v",
|
||||||
|
"github.com/pkg/errors.init\n" +
|
||||||
|
"\t.+/github.com/pkg/errors/stack_test.go:9",
|
||||||
|
}, {
|
||||||
|
Frame(0),
|
||||||
|
"%v",
|
||||||
|
"unknown:0",
|
||||||
|
}}
|
||||||
|
|
||||||
|
for i, tt := range tests {
|
||||||
|
testFormatRegexp(t, i, tt.Frame, tt.format, tt.want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFuncname(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name, want string
|
||||||
|
}{
|
||||||
|
{"", ""},
|
||||||
|
{"runtime.main", "main"},
|
||||||
|
{"github.com/pkg/errors.funcname", "funcname"},
|
||||||
|
{"funcname", "funcname"},
|
||||||
|
{"io.copyBuffer", "copyBuffer"},
|
||||||
|
{"main.(*R).Write", "(*R).Write"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
got := funcname(tt.name)
|
||||||
|
want := tt.want
|
||||||
|
if got != want {
|
||||||
|
t.Errorf("funcname(%q): want: %q, got %q", tt.name, want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStackTrace(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
err error
|
||||||
|
want []string
|
||||||
|
}{{
|
||||||
|
New("ooh"), []string{
|
||||||
|
"github.com/pkg/errors.TestStackTrace\n" +
|
||||||
|
"\t.+/github.com/pkg/errors/stack_test.go:154",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
Wrap(New("ooh"), "ahh"), []string{
|
||||||
|
"github.com/pkg/errors.TestStackTrace\n" +
|
||||||
|
"\t.+/github.com/pkg/errors/stack_test.go:159", // this is the stack of Wrap, not New
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
Cause(Wrap(New("ooh"), "ahh")), []string{
|
||||||
|
"github.com/pkg/errors.TestStackTrace\n" +
|
||||||
|
"\t.+/github.com/pkg/errors/stack_test.go:164", // this is the stack of New
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
func() error { return New("ooh") }(), []string{
|
||||||
|
`github.com/pkg/errors.(func·009|TestStackTrace.func1)` +
|
||||||
|
"\n\t.+/github.com/pkg/errors/stack_test.go:169", // this is the stack of New
|
||||||
|
"github.com/pkg/errors.TestStackTrace\n" +
|
||||||
|
"\t.+/github.com/pkg/errors/stack_test.go:169", // this is the stack of New's caller
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
Cause(func() error {
|
||||||
|
return func() error {
|
||||||
|
return Errorf("hello %s", fmt.Sprintf("world"))
|
||||||
|
}()
|
||||||
|
}()), []string{
|
||||||
|
`github.com/pkg/errors.(func·010|TestStackTrace.func2.1)` +
|
||||||
|
"\n\t.+/github.com/pkg/errors/stack_test.go:178", // this is the stack of Errorf
|
||||||
|
`github.com/pkg/errors.(func·011|TestStackTrace.func2)` +
|
||||||
|
"\n\t.+/github.com/pkg/errors/stack_test.go:179", // this is the stack of Errorf's caller
|
||||||
|
"github.com/pkg/errors.TestStackTrace\n" +
|
||||||
|
"\t.+/github.com/pkg/errors/stack_test.go:180", // this is the stack of Errorf's caller's caller
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
for i, tt := range tests {
|
||||||
|
x, ok := tt.err.(interface {
|
||||||
|
StackTrace() StackTrace
|
||||||
|
})
|
||||||
|
if !ok {
|
||||||
|
t.Errorf("expected %#v to implement StackTrace() StackTrace", tt.err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
st := x.StackTrace()
|
||||||
|
for j, want := range tt.want {
|
||||||
|
testFormatRegexp(t, i, st[j], "%+v", want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func stackTrace() StackTrace {
|
||||||
|
const depth = 8
|
||||||
|
var pcs [depth]uintptr
|
||||||
|
n := runtime.Callers(1, pcs[:])
|
||||||
|
var st stack = pcs[0:n]
|
||||||
|
return st.StackTrace()
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStackTraceFormat(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
StackTrace
|
||||||
|
format string
|
||||||
|
want string
|
||||||
|
}{{
|
||||||
|
nil,
|
||||||
|
"%s",
|
||||||
|
`\[\]`,
|
||||||
|
}, {
|
||||||
|
nil,
|
||||||
|
"%v",
|
||||||
|
`\[\]`,
|
||||||
|
}, {
|
||||||
|
nil,
|
||||||
|
"%+v",
|
||||||
|
"",
|
||||||
|
}, {
|
||||||
|
nil,
|
||||||
|
"%#v",
|
||||||
|
`\[\]errors.Frame\(nil\)`,
|
||||||
|
}, {
|
||||||
|
make(StackTrace, 0),
|
||||||
|
"%s",
|
||||||
|
`\[\]`,
|
||||||
|
}, {
|
||||||
|
make(StackTrace, 0),
|
||||||
|
"%v",
|
||||||
|
`\[\]`,
|
||||||
|
}, {
|
||||||
|
make(StackTrace, 0),
|
||||||
|
"%+v",
|
||||||
|
"",
|
||||||
|
}, {
|
||||||
|
make(StackTrace, 0),
|
||||||
|
"%#v",
|
||||||
|
`\[\]errors.Frame{}`,
|
||||||
|
}, {
|
||||||
|
stackTrace()[:2],
|
||||||
|
"%s",
|
||||||
|
`\[stack_test.go stack_test.go\]`,
|
||||||
|
}, {
|
||||||
|
stackTrace()[:2],
|
||||||
|
"%v",
|
||||||
|
`\[stack_test.go:207 stack_test.go:254\]`,
|
||||||
|
}, {
|
||||||
|
stackTrace()[:2],
|
||||||
|
"%+v",
|
||||||
|
"\n" +
|
||||||
|
"github.com/pkg/errors.stackTrace\n" +
|
||||||
|
"\t.+/github.com/pkg/errors/stack_test.go:207\n" +
|
||||||
|
"github.com/pkg/errors.TestStackTraceFormat\n" +
|
||||||
|
"\t.+/github.com/pkg/errors/stack_test.go:258",
|
||||||
|
}, {
|
||||||
|
stackTrace()[:2],
|
||||||
|
"%#v",
|
||||||
|
`\[\]errors.Frame{stack_test.go:207, stack_test.go:266}`,
|
||||||
|
}}
|
||||||
|
|
||||||
|
for i, tt := range tests {
|
||||||
|
testFormatRegexp(t, i, tt.StackTrace, tt.format, tt.want)
|
||||||
|
}
|
||||||
|
}
|
11
vendor/github.com/pressly/goose/.gitignore
generated
vendored
Normal file
11
vendor/github.com/pressly/goose/.gitignore
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
.DS_Store
|
||||||
|
cmd/goose/goose*
|
||||||
|
*.swp
|
||||||
|
*.test
|
||||||
|
|
||||||
|
# Files output by tests
|
||||||
|
bin
|
||||||
|
go.db
|
||||||
|
sql.db
|
||||||
|
|
||||||
|
|
11
vendor/github.com/pressly/goose/.travis.yml
generated
vendored
Normal file
11
vendor/github.com/pressly/goose/.travis.yml
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
sudo: false
|
||||||
|
language: go
|
||||||
|
go:
|
||||||
|
- 1.8
|
||||||
|
|
||||||
|
install:
|
||||||
|
- go get github.com/golang/dep/cmd/dep
|
||||||
|
- dep ensure
|
||||||
|
|
||||||
|
script:
|
||||||
|
- go test
|
11
vendor/github.com/pressly/goose/Gopkg.toml
generated
vendored
Normal file
11
vendor/github.com/pressly/goose/Gopkg.toml
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
[[constraint]]
|
||||||
|
name = "github.com/go-sql-driver/mysql"
|
||||||
|
version = "^1.3.0"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
branch = "master"
|
||||||
|
name = "github.com/lib/pq"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
name = "github.com/mattn/go-sqlite3"
|
||||||
|
version = "^1.2.0"
|
21
vendor/github.com/pressly/goose/LICENSE
generated
vendored
Normal file
21
vendor/github.com/pressly/goose/LICENSE
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
Original work Copyright (c) 2012 Liam Staskawicz
|
||||||
|
Modified work Copyright (c) 2016 Vojtech Vitek
|
||||||
|
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
|
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
9
vendor/github.com/pressly/goose/Makefile
generated
vendored
Normal file
9
vendor/github.com/pressly/goose/Makefile
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
.PHONY: dist
|
||||||
|
dist:
|
||||||
|
@mkdir -p ./bin
|
||||||
|
@rm -f ./bin/*
|
||||||
|
GOOS=darwin GOARCH=amd64 go build -o ./bin/goose-darwin64 ./cmd/goose
|
||||||
|
GOOS=linux GOARCH=amd64 go build -o ./bin/goose-linux64 ./cmd/goose
|
||||||
|
GOOS=linux GOARCH=386 go build -o ./bin/goose-linux386 ./cmd/goose
|
||||||
|
GOOS=windows GOARCH=amd64 go build -o ./bin/goose-windows64.exe ./cmd/goose
|
||||||
|
GOOS=windows GOARCH=386 go build -o ./bin/goose-windows386.exe ./cmd/goose
|
256
vendor/github.com/pressly/goose/README.md
generated
vendored
Normal file
256
vendor/github.com/pressly/goose/README.md
generated
vendored
Normal file
@ -0,0 +1,256 @@
|
|||||||
|
# goose
|
||||||
|
|
||||||
|
Goose is a database migration tool. Manage your database schema by creating incremental SQL changes or Go functions.
|
||||||
|
|
||||||
|
[![GoDoc Widget]][GoDoc] [![Travis Widget]][Travis]
|
||||||
|
|
||||||
|
### Goals of this fork
|
||||||
|
|
||||||
|
`github.com/pressly/goose` is a fork of `bitbucket.org/liamstask/goose` with the following changes:
|
||||||
|
- No config files
|
||||||
|
- [Default goose binary](./cmd/goose/main.go) can migrate SQL files only
|
||||||
|
- Go migrations:
|
||||||
|
- We don't `go build` Go migrations functions on-the-fly
|
||||||
|
from within the goose binary
|
||||||
|
- Instead, we let you
|
||||||
|
[create your own custom goose binary](examples/go-migrations),
|
||||||
|
register your Go migration functions explicitly and run complex
|
||||||
|
migrations with your own `*sql.DB` connection
|
||||||
|
- Go migration functions let you run your code within
|
||||||
|
an SQL transaction, if you use the `*sql.Tx` argument
|
||||||
|
- The goose pkg is decoupled from the binary:
|
||||||
|
- goose pkg doesn't register any SQL drivers anymore,
|
||||||
|
thus no driver `panic()` conflict within your codebase!
|
||||||
|
- goose pkg doesn't have any vendor dependencies anymore
|
||||||
|
- We use timestamped migrations by default but recommend a hybrid approach of using timestamps in the development process and sequential versions in production.
|
||||||
|
|
||||||
|
# Install
|
||||||
|
|
||||||
|
$ go get -u github.com/pressly/goose/cmd/goose
|
||||||
|
|
||||||
|
This will install the `goose` binary to your `$GOPATH/bin` directory.
|
||||||
|
|
||||||
|
For a lite version of the binary without DB connection dependent commands, use the exclusive build tags:
|
||||||
|
|
||||||
|
$ go build -tags='no_mysql no_sqlite no_psql' -i -o goose ./cmd/goose
|
||||||
|
|
||||||
|
|
||||||
|
# Usage
|
||||||
|
|
||||||
|
```
|
||||||
|
Usage: goose [OPTIONS] DRIVER DBSTRING COMMAND
|
||||||
|
|
||||||
|
Drivers:
|
||||||
|
postgres
|
||||||
|
mysql
|
||||||
|
sqlite3
|
||||||
|
redshift
|
||||||
|
|
||||||
|
Commands:
|
||||||
|
up Migrate the DB to the most recent version available
|
||||||
|
up-to VERSION Migrate the DB to a specific VERSION
|
||||||
|
down Roll back the version by 1
|
||||||
|
down-to VERSION Roll back to a specific VERSION
|
||||||
|
redo Re-run the latest migration
|
||||||
|
status Dump the migration status for the current DB
|
||||||
|
version Print the current version of the database
|
||||||
|
create NAME [sql|go] Creates new migration file with the current timestamp
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-dir string
|
||||||
|
directory with migration files (default ".")
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
goose sqlite3 ./foo.db status
|
||||||
|
goose sqlite3 ./foo.db create init sql
|
||||||
|
goose sqlite3 ./foo.db create add_some_column sql
|
||||||
|
goose sqlite3 ./foo.db create fetch_user_data go
|
||||||
|
goose sqlite3 ./foo.db up
|
||||||
|
|
||||||
|
goose postgres "user=postgres dbname=postgres sslmode=disable" status
|
||||||
|
goose mysql "user:password@/dbname?parseTime=true" status
|
||||||
|
goose redshift "postgres://user:password@qwerty.us-east-1.redshift.amazonaws.com:5439/db" status
|
||||||
|
goose tidb "user:password@/dbname?parseTime=true" status
|
||||||
|
```
|
||||||
|
## create
|
||||||
|
|
||||||
|
Create a new SQL migration.
|
||||||
|
|
||||||
|
$ goose create add_some_column sql
|
||||||
|
$ Created new file: 20170506082420_add_some_column.sql
|
||||||
|
|
||||||
|
Edit the newly created file to define the behavior of your migration.
|
||||||
|
|
||||||
|
You can also create a Go migration, if you then invoke it with [your own goose binary](#go-migrations):
|
||||||
|
|
||||||
|
$ goose create fetch_user_data go
|
||||||
|
$ Created new file: 20170506082421_fetch_user_data.go
|
||||||
|
|
||||||
|
## up
|
||||||
|
|
||||||
|
Apply all available migrations.
|
||||||
|
|
||||||
|
$ goose up
|
||||||
|
$ OK 001_basics.sql
|
||||||
|
$ OK 002_next.sql
|
||||||
|
$ OK 003_and_again.go
|
||||||
|
|
||||||
|
## up-to
|
||||||
|
|
||||||
|
Migrate up to a specific version.
|
||||||
|
|
||||||
|
$ goose up-to 20170506082420
|
||||||
|
$ OK 20170506082420_create_table.sql
|
||||||
|
|
||||||
|
## down
|
||||||
|
|
||||||
|
Roll back a single migration from the current version.
|
||||||
|
|
||||||
|
$ goose down
|
||||||
|
$ OK 003_and_again.go
|
||||||
|
|
||||||
|
## down-to
|
||||||
|
|
||||||
|
Roll back migrations to a specific version.
|
||||||
|
|
||||||
|
$ goose down-to 20170506082527
|
||||||
|
$ OK 20170506082527_alter_column.sql
|
||||||
|
|
||||||
|
## redo
|
||||||
|
|
||||||
|
Roll back the most recently applied migration, then run it again.
|
||||||
|
|
||||||
|
$ goose redo
|
||||||
|
$ OK 003_and_again.go
|
||||||
|
$ OK 003_and_again.go
|
||||||
|
|
||||||
|
## status
|
||||||
|
|
||||||
|
Print the status of all migrations:
|
||||||
|
|
||||||
|
$ goose status
|
||||||
|
$ Applied At Migration
|
||||||
|
$ =======================================
|
||||||
|
$ Sun Jan 6 11:25:03 2013 -- 001_basics.sql
|
||||||
|
$ Sun Jan 6 11:25:03 2013 -- 002_next.sql
|
||||||
|
$ Pending -- 003_and_again.go
|
||||||
|
|
||||||
|
Note: for MySQL [parseTime flag](https://github.com/go-sql-driver/mysql#parsetime) must be enabled.
|
||||||
|
|
||||||
|
## version
|
||||||
|
|
||||||
|
Print the current version of the database:
|
||||||
|
|
||||||
|
$ goose version
|
||||||
|
$ goose: version 002
|
||||||
|
|
||||||
|
# Migrations
|
||||||
|
|
||||||
|
goose supports migrations written in SQL or in Go.
|
||||||
|
|
||||||
|
## SQL Migrations
|
||||||
|
|
||||||
|
A sample SQL migration looks like:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- +goose Up
|
||||||
|
CREATE TABLE post (
|
||||||
|
id int NOT NULL,
|
||||||
|
title text,
|
||||||
|
body text,
|
||||||
|
PRIMARY KEY(id)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- +goose Down
|
||||||
|
DROP TABLE post;
|
||||||
|
```
|
||||||
|
|
||||||
|
Notice the annotations in the comments. Any statements following `-- +goose Up` will be executed as part of a forward migration, and any statements following `-- +goose Down` will be executed as part of a rollback.
|
||||||
|
|
||||||
|
By default, all migrations are run within a transaction. Some statements like `CREATE DATABASE`, however, cannot be run within a transaction. You may optionally add `-- +goose NO TRANSACTION` to the top of your migration
|
||||||
|
file in order to skip transactions within that specific migration file. Both Up and Down migrations within this file will be run without transactions.
|
||||||
|
|
||||||
|
By default, SQL statements are delimited by semicolons - in fact, query statements must end with a semicolon to be properly recognized by goose.
|
||||||
|
|
||||||
|
More complex statements (PL/pgSQL) that have semicolons within them must be annotated with `-- +goose StatementBegin` and `-- +goose StatementEnd` to be properly recognized. For example:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- +goose Up
|
||||||
|
-- +goose StatementBegin
|
||||||
|
CREATE OR REPLACE FUNCTION histories_partition_creation( DATE, DATE )
|
||||||
|
returns void AS $$
|
||||||
|
DECLARE
|
||||||
|
create_query text;
|
||||||
|
BEGIN
|
||||||
|
FOR create_query IN SELECT
|
||||||
|
'CREATE TABLE IF NOT EXISTS histories_'
|
||||||
|
|| TO_CHAR( d, 'YYYY_MM' )
|
||||||
|
|| ' ( CHECK( created_at >= timestamp '''
|
||||||
|
|| TO_CHAR( d, 'YYYY-MM-DD 00:00:00' )
|
||||||
|
|| ''' AND created_at < timestamp '''
|
||||||
|
|| TO_CHAR( d + INTERVAL '1 month', 'YYYY-MM-DD 00:00:00' )
|
||||||
|
|| ''' ) ) inherits ( histories );'
|
||||||
|
FROM generate_series( $1, $2, '1 month' ) AS d
|
||||||
|
LOOP
|
||||||
|
EXECUTE create_query;
|
||||||
|
END LOOP; -- LOOP END
|
||||||
|
END; -- FUNCTION END
|
||||||
|
$$
|
||||||
|
language plpgsql;
|
||||||
|
-- +goose StatementEnd
|
||||||
|
```
|
||||||
|
|
||||||
|
## Go Migrations
|
||||||
|
|
||||||
|
1. Create your own goose binary, see [example](./examples/go-migrations)
|
||||||
|
2. Import `github.com/pressly/goose`
|
||||||
|
3. Register your migration functions
|
||||||
|
4. Run goose command, ie. `goose.Up(db *sql.DB, dir string)`
|
||||||
|
|
||||||
|
A [sample Go migration 00002_users_add_email.go file](./example/migrations-go/00002_rename_root.go) looks like:
|
||||||
|
|
||||||
|
```go
|
||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
|
||||||
|
"github.com/pressly/goose"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
goose.AddMigration(Up, Down)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Up(tx *sql.Tx) error {
|
||||||
|
_, err := tx.Exec("UPDATE users SET username='admin' WHERE username='root';")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Down(tx *sql.Tx) error {
|
||||||
|
_, err := tx.Exec("UPDATE users SET username='root' WHERE username='admin';")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# Hybrid Versioning
|
||||||
|
Please, read the [versioning problem](https://github.com/pressly/goose/issues/63#issuecomment-428681694) first.
|
||||||
|
|
||||||
|
We strongly recommend adopting a hybrid versioning approach, using both timestamps and sequential numbers. Migrations created during the development process are timestamped and sequential versions are ran on production. We believe this method will prevent the problem of conflicting versions when writing software in a team environment.
|
||||||
|
|
||||||
|
To help you adopt this approach, `create` will use the current timestamp as the migration version. When you're ready to deploy your migrations in a production environment, we also provide a helpful `fix` command to convert your migrations into sequential order, while preserving the timestamp ordering. We recommend running `fix` in the CI pipeline, and only when the migrations are ready for production.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Licensed under [MIT License](./LICENSE)
|
||||||
|
|
||||||
|
[GoDoc]: https://godoc.org/github.com/pressly/goose
|
||||||
|
[GoDoc Widget]: https://godoc.org/github.com/pressly/goose?status.svg
|
||||||
|
[Travis]: https://travis-ci.org/pressly/goose
|
||||||
|
[Travis Widget]: https://travis-ci.org/pressly/goose.svg?branch=master
|
8
vendor/github.com/pressly/goose/cmd/goose/driver_mysql.go
generated
vendored
Normal file
8
vendor/github.com/pressly/goose/cmd/goose/driver_mysql.go
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
// +build !no_mysql
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "github.com/go-sql-driver/mysql"
|
||||||
|
_ "github.com/ziutek/mymysql/godrv"
|
||||||
|
)
|
7
vendor/github.com/pressly/goose/cmd/goose/driver_psql.go
generated
vendored
Normal file
7
vendor/github.com/pressly/goose/cmd/goose/driver_psql.go
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
// +build !no_pq
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "github.com/lib/pq"
|
||||||
|
)
|
7
vendor/github.com/pressly/goose/cmd/goose/driver_sqlite.go
generated
vendored
Normal file
7
vendor/github.com/pressly/goose/cmd/goose/driver_sqlite.go
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
// +build !no_sqlite
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "github.com/mattn/go-sqlite3"
|
||||||
|
)
|
134
vendor/github.com/pressly/goose/cmd/goose/main.go
generated
vendored
Normal file
134
vendor/github.com/pressly/goose/cmd/goose/main.go
generated
vendored
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/pressly/goose"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
flags = flag.NewFlagSet("goose", flag.ExitOnError)
|
||||||
|
dir = flags.String("dir", ".", "directory with migration files")
|
||||||
|
verbose = flags.Bool("v", false, "enable verbose mode")
|
||||||
|
help = flags.Bool("h", false, "print help")
|
||||||
|
version = flags.Bool("version", false, "print version")
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
flags.Usage = usage
|
||||||
|
flags.Parse(os.Args[1:])
|
||||||
|
|
||||||
|
if *version {
|
||||||
|
fmt.Println(goose.VERSION)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if *verbose {
|
||||||
|
goose.SetVerbose(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
args := flags.Args()
|
||||||
|
if len(args) == 0 || *help {
|
||||||
|
flags.Usage()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch args[0] {
|
||||||
|
case "create":
|
||||||
|
if err := goose.Run("create", nil, *dir, args[1:]...); err != nil {
|
||||||
|
log.Fatalf("goose run: %v", err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
case "fix":
|
||||||
|
if err := goose.Run("fix", nil, *dir); err != nil {
|
||||||
|
log.Fatalf("goose run: %v", err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(args) < 3 {
|
||||||
|
flags.Usage()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
driver, dbstring, command := args[0], args[1], args[2]
|
||||||
|
|
||||||
|
if err := goose.SetDialect(driver); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch driver {
|
||||||
|
case "redshift":
|
||||||
|
driver = "postgres"
|
||||||
|
case "tidb":
|
||||||
|
driver = "mysql"
|
||||||
|
}
|
||||||
|
|
||||||
|
switch dbstring {
|
||||||
|
case "":
|
||||||
|
log.Fatalf("-dbstring=%q not supported\n", dbstring)
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
db, err := sql.Open(driver, dbstring)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("-dbstring=%q: %v\n", dbstring, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
arguments := []string{}
|
||||||
|
if len(args) > 3 {
|
||||||
|
arguments = append(arguments, args[3:]...)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := goose.Run(command, db, *dir, arguments...); err != nil {
|
||||||
|
log.Fatalf("goose run: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func usage() {
|
||||||
|
fmt.Println(usagePrefix)
|
||||||
|
flags.PrintDefaults()
|
||||||
|
fmt.Println(usageCommands)
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
usagePrefix = `Usage: goose [OPTIONS] DRIVER DBSTRING COMMAND
|
||||||
|
|
||||||
|
Drivers:
|
||||||
|
postgres
|
||||||
|
mysql
|
||||||
|
sqlite3
|
||||||
|
redshift
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
goose sqlite3 ./foo.db status
|
||||||
|
goose sqlite3 ./foo.db create init sql
|
||||||
|
goose sqlite3 ./foo.db create add_some_column sql
|
||||||
|
goose sqlite3 ./foo.db create fetch_user_data go
|
||||||
|
goose sqlite3 ./foo.db up
|
||||||
|
|
||||||
|
goose postgres "user=postgres dbname=postgres sslmode=disable" status
|
||||||
|
goose mysql "user:password@/dbname?parseTime=true" status
|
||||||
|
goose redshift "postgres://user:password@qwerty.us-east-1.redshift.amazonaws.com:5439/db" status
|
||||||
|
goose tidb "user:password@/dbname?parseTime=true" status
|
||||||
|
|
||||||
|
Options:
|
||||||
|
`
|
||||||
|
|
||||||
|
usageCommands = `
|
||||||
|
Commands:
|
||||||
|
up Migrate the DB to the most recent version available
|
||||||
|
up-to VERSION Migrate the DB to a specific VERSION
|
||||||
|
down Roll back the version by 1
|
||||||
|
down-to VERSION Roll back to a specific VERSION
|
||||||
|
redo Re-run the latest migration
|
||||||
|
reset Roll back all migrations
|
||||||
|
status Dump the migration status for the current DB
|
||||||
|
version Print the current version of the database
|
||||||
|
create NAME [sql|go] Creates new migration file with the current timestamp
|
||||||
|
fix Apply sequential ordering to migrations
|
||||||
|
`
|
||||||
|
)
|
88
vendor/github.com/pressly/goose/create.go
generated
vendored
Normal file
88
vendor/github.com/pressly/goose/create.go
generated
vendored
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
package goose
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"text/template"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Create writes a new blank migration file.
|
||||||
|
func CreateWithTemplate(db *sql.DB, dir string, migrationTemplate *template.Template, name, migrationType string) error {
|
||||||
|
version := time.Now().Format(timestampFormat)
|
||||||
|
filename := fmt.Sprintf("%v_%v.%v", version, name, migrationType)
|
||||||
|
|
||||||
|
fpath := filepath.Join(dir, filename)
|
||||||
|
|
||||||
|
tmpl := sqlMigrationTemplate
|
||||||
|
if migrationType == "go" {
|
||||||
|
tmpl = goSQLMigrationTemplate
|
||||||
|
}
|
||||||
|
|
||||||
|
if migrationTemplate != nil {
|
||||||
|
tmpl = migrationTemplate
|
||||||
|
}
|
||||||
|
|
||||||
|
path, err := writeTemplateToFile(fpath, tmpl, version)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Created new file: %s\n", path)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create writes a new blank migration file.
|
||||||
|
func Create(db *sql.DB, dir, name, migrationType string) error {
|
||||||
|
return CreateWithTemplate(db, dir, nil, name, migrationType)
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeTemplateToFile(path string, t *template.Template, version string) (string, error) {
|
||||||
|
if _, err := os.Stat(path); !os.IsNotExist(err) {
|
||||||
|
return "", fmt.Errorf("failed to create file: %v already exists", path)
|
||||||
|
}
|
||||||
|
|
||||||
|
f, err := os.Create(path)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
err = t.Execute(f, version)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return f.Name(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var sqlMigrationTemplate = template.Must(template.New("goose.sql-migration").Parse(`-- +goose Up
|
||||||
|
-- SQL in this section is executed when the migration is applied.
|
||||||
|
|
||||||
|
-- +goose Down
|
||||||
|
-- SQL in this section is executed when the migration is rolled back.
|
||||||
|
`))
|
||||||
|
|
||||||
|
var goSQLMigrationTemplate = template.Must(template.New("goose.go-migration").Parse(`package migration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"github.com/pressly/goose"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
goose.AddMigration(Up{{.}}, Down{{.}})
|
||||||
|
}
|
||||||
|
|
||||||
|
func Up{{.}}(tx *sql.Tx) error {
|
||||||
|
// This code is executed when the migration is applied.
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Down{{.}}(tx *sql.Tx) error {
|
||||||
|
// This code is executed when the migration is rolled back.
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
`))
|
211
vendor/github.com/pressly/goose/dialect.go
generated
vendored
Normal file
211
vendor/github.com/pressly/goose/dialect.go
generated
vendored
Normal file
@ -0,0 +1,211 @@
|
|||||||
|
package goose
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SQLDialect abstracts the details of specific SQL dialects
|
||||||
|
// for goose's few SQL specific statements
|
||||||
|
type SQLDialect interface {
|
||||||
|
createVersionTableSQL() string // sql string to create the db version table
|
||||||
|
insertVersionSQL() string // sql string to insert the initial version table row
|
||||||
|
deleteVersionSQL() string // sql string to delete version
|
||||||
|
dbVersionQuery(db *sql.DB) (*sql.Rows, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
var dialect SQLDialect = &PostgresDialect{}
|
||||||
|
|
||||||
|
// GetDialect gets the SQLDialect
|
||||||
|
func GetDialect() SQLDialect {
|
||||||
|
return dialect
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetDialect sets the SQLDialect
|
||||||
|
func SetDialect(d string) error {
|
||||||
|
switch d {
|
||||||
|
case "postgres":
|
||||||
|
dialect = &PostgresDialect{}
|
||||||
|
case "mysql":
|
||||||
|
dialect = &MySQLDialect{}
|
||||||
|
case "sqlite3":
|
||||||
|
dialect = &Sqlite3Dialect{}
|
||||||
|
case "redshift":
|
||||||
|
dialect = &RedshiftDialect{}
|
||||||
|
case "tidb":
|
||||||
|
dialect = &TiDBDialect{}
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("%q: unknown dialect", d)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////
|
||||||
|
// Postgres
|
||||||
|
////////////////////////////
|
||||||
|
|
||||||
|
// PostgresDialect struct.
|
||||||
|
type PostgresDialect struct{}
|
||||||
|
|
||||||
|
func (pg PostgresDialect) createVersionTableSQL() string {
|
||||||
|
return fmt.Sprintf(`CREATE TABLE %s (
|
||||||
|
id serial NOT NULL,
|
||||||
|
version_id bigint NOT NULL,
|
||||||
|
is_applied boolean NOT NULL,
|
||||||
|
tstamp timestamp NULL default now(),
|
||||||
|
PRIMARY KEY(id)
|
||||||
|
);`, TableName())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pg PostgresDialect) insertVersionSQL() string {
|
||||||
|
return fmt.Sprintf("INSERT INTO %s (version_id, is_applied) VALUES ($1, $2);", TableName())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pg PostgresDialect) dbVersionQuery(db *sql.DB) (*sql.Rows, error) {
|
||||||
|
rows, err := db.Query(fmt.Sprintf("SELECT version_id, is_applied from %s ORDER BY id DESC", TableName()))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return rows, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pg PostgresDialect) deleteVersionSQL() string {
|
||||||
|
return fmt.Sprintf("DELETE FROM %s WHERE version_id=$1;", TableName())
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////
|
||||||
|
// MySQL
|
||||||
|
////////////////////////////
|
||||||
|
|
||||||
|
// MySQLDialect struct.
|
||||||
|
type MySQLDialect struct{}
|
||||||
|
|
||||||
|
func (m MySQLDialect) createVersionTableSQL() string {
|
||||||
|
return fmt.Sprintf(`CREATE TABLE %s (
|
||||||
|
id serial NOT NULL,
|
||||||
|
version_id bigint NOT NULL,
|
||||||
|
is_applied boolean NOT NULL,
|
||||||
|
tstamp timestamp NULL default now(),
|
||||||
|
PRIMARY KEY(id)
|
||||||
|
);`, TableName())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m MySQLDialect) insertVersionSQL() string {
|
||||||
|
return fmt.Sprintf("INSERT INTO %s (version_id, is_applied) VALUES (?, ?);", TableName())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m MySQLDialect) dbVersionQuery(db *sql.DB) (*sql.Rows, error) {
|
||||||
|
rows, err := db.Query(fmt.Sprintf("SELECT version_id, is_applied from %s ORDER BY id DESC", TableName()))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return rows, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m MySQLDialect) deleteVersionSQL() string {
|
||||||
|
return fmt.Sprintf("DELETE FROM %s WHERE version_id=?;", TableName())
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////
|
||||||
|
// sqlite3
|
||||||
|
////////////////////////////
|
||||||
|
|
||||||
|
// Sqlite3Dialect struct.
|
||||||
|
type Sqlite3Dialect struct{}
|
||||||
|
|
||||||
|
func (m Sqlite3Dialect) createVersionTableSQL() string {
|
||||||
|
return fmt.Sprintf(`CREATE TABLE %s (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
version_id INTEGER NOT NULL,
|
||||||
|
is_applied INTEGER NOT NULL,
|
||||||
|
tstamp TIMESTAMP DEFAULT (datetime('now'))
|
||||||
|
);`, TableName())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m Sqlite3Dialect) insertVersionSQL() string {
|
||||||
|
return fmt.Sprintf("INSERT INTO %s (version_id, is_applied) VALUES (?, ?);", TableName())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m Sqlite3Dialect) dbVersionQuery(db *sql.DB) (*sql.Rows, error) {
|
||||||
|
rows, err := db.Query(fmt.Sprintf("SELECT version_id, is_applied from %s ORDER BY id DESC", TableName()))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return rows, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m Sqlite3Dialect) deleteVersionSQL() string {
|
||||||
|
return fmt.Sprintf("DELETE FROM %s WHERE version_id=?;", TableName())
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////
|
||||||
|
// Redshift
|
||||||
|
////////////////////////////
|
||||||
|
|
||||||
|
// RedshiftDialect struct.
|
||||||
|
type RedshiftDialect struct{}
|
||||||
|
|
||||||
|
func (rs RedshiftDialect) createVersionTableSQL() string {
|
||||||
|
return fmt.Sprintf(`CREATE TABLE %s (
|
||||||
|
id integer NOT NULL identity(1, 1),
|
||||||
|
version_id bigint NOT NULL,
|
||||||
|
is_applied boolean NOT NULL,
|
||||||
|
tstamp timestamp NULL default sysdate,
|
||||||
|
PRIMARY KEY(id)
|
||||||
|
);`, TableName())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rs RedshiftDialect) insertVersionSQL() string {
|
||||||
|
return fmt.Sprintf("INSERT INTO %s (version_id, is_applied) VALUES ($1, $2);", TableName())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rs RedshiftDialect) dbVersionQuery(db *sql.DB) (*sql.Rows, error) {
|
||||||
|
rows, err := db.Query(fmt.Sprintf("SELECT version_id, is_applied from %s ORDER BY id DESC", TableName()))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return rows, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rs RedshiftDialect) deleteVersionSQL() string {
|
||||||
|
return fmt.Sprintf("DELETE FROM %s WHERE version_id=?;", TableName())
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////
|
||||||
|
// TiDB
|
||||||
|
////////////////////////////
|
||||||
|
|
||||||
|
// TiDBDialect struct.
|
||||||
|
type TiDBDialect struct{}
|
||||||
|
|
||||||
|
func (m TiDBDialect) createVersionTableSQL() string {
|
||||||
|
return fmt.Sprintf(`CREATE TABLE %s (
|
||||||
|
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE,
|
||||||
|
version_id bigint NOT NULL,
|
||||||
|
is_applied boolean NOT NULL,
|
||||||
|
tstamp timestamp NULL default now(),
|
||||||
|
PRIMARY KEY(id)
|
||||||
|
);`, TableName())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m TiDBDialect) insertVersionSQL() string {
|
||||||
|
return fmt.Sprintf("INSERT INTO %s (version_id, is_applied) VALUES (?, ?);", TableName())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m TiDBDialect) dbVersionQuery(db *sql.DB) (*sql.Rows, error) {
|
||||||
|
rows, err := db.Query(fmt.Sprintf("SELECT version_id, is_applied from %s ORDER BY id DESC", TableName()))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return rows, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m TiDBDialect) deleteVersionSQL() string {
|
||||||
|
return fmt.Sprintf("DELETE FROM %s WHERE version_id=?;", TableName())
|
||||||
|
}
|
56
vendor/github.com/pressly/goose/down.go
generated
vendored
Normal file
56
vendor/github.com/pressly/goose/down.go
generated
vendored
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
package goose
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Down rolls back a single migration from the current version.
|
||||||
|
func Down(db *sql.DB, dir string) error {
|
||||||
|
currentVersion, err := GetDBVersion(db)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
migrations, err := CollectMigrations(dir, minVersion, maxVersion)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
current, err := migrations.Current(currentVersion)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("no migration %v", currentVersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
return current.Down(db)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DownTo rolls back migrations to a specific version.
|
||||||
|
func DownTo(db *sql.DB, dir string, version int64) error {
|
||||||
|
migrations, err := CollectMigrations(dir, minVersion, maxVersion)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
currentVersion, err := GetDBVersion(db)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
current, err := migrations.Current(currentVersion)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("goose: no migrations to run. current version: %d\n", currentVersion)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if current.Version <= version {
|
||||||
|
log.Printf("goose: no migrations to run. current version: %d\n", currentVersion)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = current.Down(db); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
2
vendor/github.com/pressly/goose/examples/README.md
generated
vendored
Normal file
2
vendor/github.com/pressly/goose/examples/README.md
generated
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
# 1. [SQL migrations](sql-migrations)
|
||||||
|
# 2. [Go migrations](go-migrations)
|
14
vendor/github.com/pressly/goose/examples/go-migrations/00001_create_users_table.sql
generated
vendored
Normal file
14
vendor/github.com/pressly/goose/examples/go-migrations/00001_create_users_table.sql
generated
vendored
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
-- +goose Up
|
||||||
|
CREATE TABLE users (
|
||||||
|
id int NOT NULL PRIMARY KEY,
|
||||||
|
username text,
|
||||||
|
name text,
|
||||||
|
surname text
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO users VALUES
|
||||||
|
(0, 'root', '', ''),
|
||||||
|
(1, 'vojtechvitek', 'Vojtech', 'Vitek');
|
||||||
|
|
||||||
|
-- +goose Down
|
||||||
|
DROP TABLE users;
|
27
vendor/github.com/pressly/goose/examples/go-migrations/00002_rename_root.go
generated
vendored
Normal file
27
vendor/github.com/pressly/goose/examples/go-migrations/00002_rename_root.go
generated
vendored
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
|
||||||
|
"github.com/pressly/goose"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
goose.AddMigration(Up00002, Down00002)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Up00002(tx *sql.Tx) error {
|
||||||
|
_, err := tx.Exec("UPDATE users SET username='admin' WHERE username='root';")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Down00002(tx *sql.Tx) error {
|
||||||
|
_, err := tx.Exec("UPDATE users SET username='root' WHERE username='admin';")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
41
vendor/github.com/pressly/goose/examples/go-migrations/README.md
generated
vendored
Normal file
41
vendor/github.com/pressly/goose/examples/go-migrations/README.md
generated
vendored
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
# SQL + Go migrations
|
||||||
|
|
||||||
|
## This example: Custom goose binary with built-in Go migrations
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ go build -o goose *.go
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
$ ./goose sqlite3 ./foo.db status
|
||||||
|
Applied At Migration
|
||||||
|
=======================================
|
||||||
|
Pending -- 00001_create_users_table.sql
|
||||||
|
Pending -- 00002_rename_root.go
|
||||||
|
|
||||||
|
$ ./goose sqlite3 ./foo.db up
|
||||||
|
OK 00001_create_users_table.sql
|
||||||
|
OK 00002_rename_root.go
|
||||||
|
goose: no migrations to run. current version: 2
|
||||||
|
|
||||||
|
$
|
||||||
|
Applied At Migration
|
||||||
|
=======================================
|
||||||
|
Mon Jun 19 21:56:00 2017 -- 00001_create_users_table.sql
|
||||||
|
Mon Jun 19 21:56:00 2017 -- 00002_rename_root.go
|
||||||
|
```
|
||||||
|
|
||||||
|
## Best practice: Split migrations into a standalone package
|
||||||
|
|
||||||
|
1. Move [main.go](main.go) into your `cmd/` directory
|
||||||
|
|
||||||
|
2. Rename package name in all `*_.go` migration files from `main` to `migrations`.
|
||||||
|
|
||||||
|
3. Import this `migrations` package from your custom [cmd/main.go](main.go) file:
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
// Invoke init() functions within migrations pkg.
|
||||||
|
_ "github.com/pressly/goose/example/migrations-go"
|
||||||
|
)
|
||||||
|
```
|
BIN
vendor/github.com/pressly/goose/examples/go-migrations/foo.db
generated
vendored
Normal file
BIN
vendor/github.com/pressly/goose/examples/go-migrations/foo.db
generated
vendored
Normal file
Binary file not shown.
BIN
vendor/github.com/pressly/goose/examples/go-migrations/goose
generated
vendored
Executable file
BIN
vendor/github.com/pressly/goose/examples/go-migrations/goose
generated
vendored
Executable file
Binary file not shown.
133
vendor/github.com/pressly/goose/examples/go-migrations/main.go
generated
vendored
Normal file
133
vendor/github.com/pressly/goose/examples/go-migrations/main.go
generated
vendored
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"flag"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/pressly/goose"
|
||||||
|
|
||||||
|
// Init DB drivers.
|
||||||
|
_ "github.com/go-sql-driver/mysql"
|
||||||
|
_ "github.com/lib/pq"
|
||||||
|
_ "github.com/mattn/go-sqlite3"
|
||||||
|
_ "github.com/ziutek/mymysql/godrv"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
flags = flag.NewFlagSet("goose", flag.ExitOnError)
|
||||||
|
dir = flags.String("dir", ".", "directory with migration files")
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
flags.Usage = usage
|
||||||
|
flags.Parse(os.Args[1:])
|
||||||
|
|
||||||
|
args := flags.Args()
|
||||||
|
if len(args) == 0 || args[0] == "-h" || args[0] == "--help" {
|
||||||
|
flags.Usage()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch args[0] {
|
||||||
|
case "create":
|
||||||
|
if err := goose.Run("create", nil, *dir, args[1:]...); err != nil {
|
||||||
|
log.Fatalf("goose run: %v", err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
case "fix":
|
||||||
|
if err := goose.Run("fix", nil, *dir); err != nil {
|
||||||
|
log.Fatalf("goose run: %v", err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(args) < 3 {
|
||||||
|
flags.Usage()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if args[0] == "-h" || args[0] == "--help" {
|
||||||
|
flags.Usage()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
driver, dbstring, command := args[0], args[1], args[2]
|
||||||
|
|
||||||
|
switch driver {
|
||||||
|
case "postgres", "mysql", "sqlite3", "redshift":
|
||||||
|
if err := goose.SetDialect(driver); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
log.Fatalf("%q driver not supported\n", driver)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch dbstring {
|
||||||
|
case "":
|
||||||
|
log.Fatalf("-dbstring=%q not supported\n", dbstring)
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
if driver == "redshift" {
|
||||||
|
driver = "postgres"
|
||||||
|
}
|
||||||
|
|
||||||
|
db, err := sql.Open(driver, dbstring)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("-dbstring=%q: %v\n", dbstring, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
arguments := []string{}
|
||||||
|
if len(args) > 3 {
|
||||||
|
arguments = append(arguments, args[3:]...)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := goose.Run(command, db, *dir, arguments...); err != nil {
|
||||||
|
log.Fatalf("goose run: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func usage() {
|
||||||
|
log.Print(usagePrefix)
|
||||||
|
flags.PrintDefaults()
|
||||||
|
log.Print(usageCommands)
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
usagePrefix = `Usage: goose [OPTIONS] DRIVER DBSTRING COMMAND
|
||||||
|
|
||||||
|
Drivers:
|
||||||
|
postgres
|
||||||
|
mysql
|
||||||
|
sqlite3
|
||||||
|
redshift
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
goose sqlite3 ./foo.db status
|
||||||
|
goose sqlite3 ./foo.db create init sql
|
||||||
|
goose sqlite3 ./foo.db create add_some_column sql
|
||||||
|
goose sqlite3 ./foo.db create fetch_user_data go
|
||||||
|
goose sqlite3 ./foo.db up
|
||||||
|
|
||||||
|
goose postgres "user=postgres dbname=postgres sslmode=disable" status
|
||||||
|
goose mysql "user:password@/dbname?parseTime=true" status
|
||||||
|
goose redshift "postgres://user:password@qwerty.us-east-1.redshift.amazonaws.com:5439/db" status
|
||||||
|
|
||||||
|
Options:
|
||||||
|
`
|
||||||
|
|
||||||
|
usageCommands = `
|
||||||
|
Commands:
|
||||||
|
up Migrate the DB to the most recent version available
|
||||||
|
up-to VERSION Migrate the DB to a specific VERSION
|
||||||
|
down Roll back the version by 1
|
||||||
|
down-to VERSION Roll back to a specific VERSION
|
||||||
|
redo Re-run the latest migration
|
||||||
|
status Dump the migration status for the current DB
|
||||||
|
version Print the current version of the database
|
||||||
|
create NAME [sql|go] Creates new migration file with the current timestamp
|
||||||
|
fix Apply sequential ordering to migrations
|
||||||
|
`
|
||||||
|
)
|
14
vendor/github.com/pressly/goose/examples/sql-migrations/00001_create_users_table.sql
generated
vendored
Normal file
14
vendor/github.com/pressly/goose/examples/sql-migrations/00001_create_users_table.sql
generated
vendored
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
-- +goose Up
|
||||||
|
CREATE TABLE users (
|
||||||
|
id int NOT NULL PRIMARY KEY,
|
||||||
|
username text,
|
||||||
|
name text,
|
||||||
|
surname text
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO users VALUES
|
||||||
|
(0, 'root', '', ''),
|
||||||
|
(1, 'vojtechvitek', 'Vojtech', 'Vitek');
|
||||||
|
|
||||||
|
-- +goose Down
|
||||||
|
DROP TABLE users;
|
9
vendor/github.com/pressly/goose/examples/sql-migrations/00002_rename_root.sql
generated
vendored
Normal file
9
vendor/github.com/pressly/goose/examples/sql-migrations/00002_rename_root.sql
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
-- +goose Up
|
||||||
|
-- +goose StatementBegin
|
||||||
|
UPDATE users SET username='admin' WHERE username='root';
|
||||||
|
-- +goose StatementEnd
|
||||||
|
|
||||||
|
-- +goose Down
|
||||||
|
-- +goose StatementBegin
|
||||||
|
UPDATE users SET username='root' WHERE username='admin';
|
||||||
|
-- +goose StatementEnd
|
11
vendor/github.com/pressly/goose/examples/sql-migrations/00003_no_transaction.sql
generated
vendored
Normal file
11
vendor/github.com/pressly/goose/examples/sql-migrations/00003_no_transaction.sql
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
-- +goose NO TRANSACTION
|
||||||
|
-- +goose Up
|
||||||
|
CREATE TABLE post (
|
||||||
|
id int NOT NULL,
|
||||||
|
title text,
|
||||||
|
body text,
|
||||||
|
PRIMARY KEY(id)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- +goose Down
|
||||||
|
DROP TABLE post;
|
26
vendor/github.com/pressly/goose/examples/sql-migrations/README.md
generated
vendored
Normal file
26
vendor/github.com/pressly/goose/examples/sql-migrations/README.md
generated
vendored
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
# SQL migrations only
|
||||||
|
|
||||||
|
See [this example](../go-migrations) for Go migrations.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ go get -u github.com/pressly/goose/cmd/goose
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ goose sqlite3 ./foo.db status
|
||||||
|
Applied At Migration
|
||||||
|
=======================================
|
||||||
|
Pending -- 00001_create_users_table.sql
|
||||||
|
Pending -- 00002_rename_root.sql
|
||||||
|
|
||||||
|
$ goose sqlite3 ./foo.db up
|
||||||
|
OK 00001_create_users_table.sql
|
||||||
|
OK 00002_rename_root.sql
|
||||||
|
goose: no migrations to run. current version: 2
|
||||||
|
|
||||||
|
$ goose sqlite3 ./foo.db status
|
||||||
|
Applied At Migration
|
||||||
|
=======================================
|
||||||
|
Mon Jun 19 21:56:00 2017 -- 00001_create_users_table.sql
|
||||||
|
Mon Jun 19 21:56:00 2017 -- 00002_rename_root.sql
|
||||||
|
```
|
46
vendor/github.com/pressly/goose/fix.go
generated
vendored
Normal file
46
vendor/github.com/pressly/goose/fix.go
generated
vendored
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
package goose
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Fix(dir string) error {
|
||||||
|
migrations, err := CollectMigrations(dir, minVersion, maxVersion)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// split into timestamped and versioned migrations
|
||||||
|
tsMigrations, err := migrations.timestamped()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
vMigrations, err := migrations.versioned()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Initial version.
|
||||||
|
version := int64(1)
|
||||||
|
if last, err := vMigrations.Last(); err == nil {
|
||||||
|
version = last.Version + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// fix filenames by replacing timestamps with sequential versions
|
||||||
|
for _, tsm := range tsMigrations {
|
||||||
|
oldPath := tsm.Source
|
||||||
|
newPath := strings.Replace(oldPath, fmt.Sprintf("%d", tsm.Version), fmt.Sprintf("%05v", version), 1)
|
||||||
|
|
||||||
|
if err := os.Rename(oldPath, newPath); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("RENAMED %s => %s", filepath.Base(oldPath), filepath.Base(newPath))
|
||||||
|
version++
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
81
vendor/github.com/pressly/goose/fix_test.go
generated
vendored
Normal file
81
vendor/github.com/pressly/goose/fix_test.go
generated
vendored
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
package goose
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFix(t *testing.T) {
|
||||||
|
dir, err := ioutil.TempDir("", "tmptest")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer os.RemoveAll(dir) // clean up
|
||||||
|
defer os.Remove("goose") // clean up
|
||||||
|
|
||||||
|
commands := []string{
|
||||||
|
"go build -i -o ./bin/goose ./cmd/goose",
|
||||||
|
fmt.Sprintf("./bin/goose -dir=%s create create_table", dir),
|
||||||
|
fmt.Sprintf("./bin/goose -dir=%s create add_users", dir),
|
||||||
|
fmt.Sprintf("./bin/goose -dir=%s create add_indices", dir),
|
||||||
|
fmt.Sprintf("./bin/goose -dir=%s create update_users", dir),
|
||||||
|
fmt.Sprintf("./bin/goose -dir=%s fix", dir),
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, cmd := range commands {
|
||||||
|
args := strings.Split(cmd, " ")
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
out, err := exec.Command(args[0], args[1:]...).CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("%s:\n%v\n\n%s", err, cmd, out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
files, err := ioutil.ReadDir(dir)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// check that the files are in order
|
||||||
|
for i, f := range files {
|
||||||
|
expected := fmt.Sprintf("%05v", i+1)
|
||||||
|
if !strings.HasPrefix(f.Name(), expected) {
|
||||||
|
t.Errorf("failed to find %s prefix in %s", expected, f.Name())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// add more migrations and then fix it
|
||||||
|
commands = []string{
|
||||||
|
fmt.Sprintf("./bin/goose -dir=%s create remove_column", dir),
|
||||||
|
fmt.Sprintf("./bin/goose -dir=%s create create_books_table", dir),
|
||||||
|
fmt.Sprintf("./bin/goose -dir=%s fix", dir),
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, cmd := range commands {
|
||||||
|
args := strings.Split(cmd, " ")
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
out, err := exec.Command(args[0], args[1:]...).CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("%s:\n%v\n\n%s", err, cmd, out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
files, err = ioutil.ReadDir(dir)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// check that the files still in order
|
||||||
|
for i, f := range files {
|
||||||
|
expected := fmt.Sprintf("%05v", i+1)
|
||||||
|
if !strings.HasPrefix(f.Name(), expected) {
|
||||||
|
t.Errorf("failed to find %s prefix in %s", expected, f.Name())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
100
vendor/github.com/pressly/goose/goose.go
generated
vendored
Normal file
100
vendor/github.com/pressly/goose/goose.go
generated
vendored
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
package goose
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
const VERSION = "v2.6.0"
|
||||||
|
|
||||||
|
var (
|
||||||
|
duplicateCheckOnce sync.Once
|
||||||
|
minVersion = int64(0)
|
||||||
|
maxVersion = int64((1 << 63) - 1)
|
||||||
|
timestampFormat = "20060102150405"
|
||||||
|
verbose = false
|
||||||
|
)
|
||||||
|
|
||||||
|
// SetVerbose set the goose verbosity mode
|
||||||
|
func SetVerbose(v bool) {
|
||||||
|
verbose = v
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run runs a goose command.
|
||||||
|
func Run(command string, db *sql.DB, dir string, args ...string) error {
|
||||||
|
switch command {
|
||||||
|
case "up":
|
||||||
|
if err := Up(db, dir); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case "up-by-one":
|
||||||
|
if err := UpByOne(db, dir); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case "up-to":
|
||||||
|
if len(args) == 0 {
|
||||||
|
return fmt.Errorf("up-to must be of form: goose [OPTIONS] DRIVER DBSTRING up-to VERSION")
|
||||||
|
}
|
||||||
|
|
||||||
|
version, err := strconv.ParseInt(args[0], 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("version must be a number (got '%s')", args[0])
|
||||||
|
}
|
||||||
|
if err := UpTo(db, dir, version); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case "create":
|
||||||
|
if len(args) == 0 {
|
||||||
|
return fmt.Errorf("create must be of form: goose [OPTIONS] DRIVER DBSTRING create NAME [go|sql]")
|
||||||
|
}
|
||||||
|
|
||||||
|
migrationType := "go"
|
||||||
|
if len(args) == 2 {
|
||||||
|
migrationType = args[1]
|
||||||
|
}
|
||||||
|
if err := Create(db, dir, args[0], migrationType); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case "down":
|
||||||
|
if err := Down(db, dir); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case "down-to":
|
||||||
|
if len(args) == 0 {
|
||||||
|
return fmt.Errorf("down-to must be of form: goose [OPTIONS] DRIVER DBSTRING down-to VERSION")
|
||||||
|
}
|
||||||
|
|
||||||
|
version, err := strconv.ParseInt(args[0], 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("version must be a number (got '%s')", args[0])
|
||||||
|
}
|
||||||
|
if err := DownTo(db, dir, version); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case "fix":
|
||||||
|
if err := Fix(dir); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case "redo":
|
||||||
|
if err := Redo(db, dir); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case "reset":
|
||||||
|
if err := Reset(db, dir); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case "status":
|
||||||
|
if err := Status(db, dir); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case "version":
|
||||||
|
if err := Version(db, dir); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("%q: no such command", command)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
84
vendor/github.com/pressly/goose/goose_test.go
generated
vendored
Normal file
84
vendor/github.com/pressly/goose/goose_test.go
generated
vendored
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
package goose
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestDefaultBinary(t *testing.T) {
|
||||||
|
commands := []string{
|
||||||
|
"go build -i -o ./bin/goose ./cmd/goose",
|
||||||
|
"./bin/goose -dir=examples/sql-migrations sqlite3 sql.db up",
|
||||||
|
"./bin/goose -dir=examples/sql-migrations sqlite3 sql.db version",
|
||||||
|
"./bin/goose -dir=examples/sql-migrations sqlite3 sql.db down",
|
||||||
|
"./bin/goose -dir=examples/sql-migrations sqlite3 sql.db status",
|
||||||
|
"./bin/goose",
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, cmd := range commands {
|
||||||
|
args := strings.Split(cmd, " ")
|
||||||
|
command := args[0]
|
||||||
|
var params []string
|
||||||
|
if len(args) > 1 {
|
||||||
|
params = args[1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
out, err := exec.Command(command, params...).CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("%s:\n%v\n\n%s", err, cmd, out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLiteBinary(t *testing.T) {
|
||||||
|
dir, err := ioutil.TempDir("", "tmptest")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer os.RemoveAll(dir) // clean up
|
||||||
|
defer os.Remove("./bin/goose") // clean up
|
||||||
|
|
||||||
|
commands := []string{
|
||||||
|
fmt.Sprintf("./bin/goose -dir=%s create user_indices sql", dir),
|
||||||
|
fmt.Sprintf("./bin/goose -dir=%s fix", dir),
|
||||||
|
}
|
||||||
|
|
||||||
|
// this has to be done outside of the loop
|
||||||
|
// since go only supports space separated tags list.
|
||||||
|
cmd := "go build -tags='no_mysql no_sqlite no_psql' -i -o ./bin/goose ./cmd/goose"
|
||||||
|
out, err := exec.Command("go", "build", "-tags='no_mysql no_sqlite no_psql'", "-i", "-o", "./bin/goose", "./cmd/goose").CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("%s:\n%v\n\n%s", err, cmd, out)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, cmd := range commands {
|
||||||
|
args := strings.Split(cmd, " ")
|
||||||
|
out, err := exec.Command(args[0], args[1:]...).CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("%s:\n%v\n\n%s", err, cmd, out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCustomBinary(t *testing.T) {
|
||||||
|
commands := []string{
|
||||||
|
"go build -i -o ./bin/custom-goose ./examples/go-migrations",
|
||||||
|
"./bin/custom-goose -dir=examples/go-migrations sqlite3 go.db up",
|
||||||
|
"./bin/custom-goose -dir=examples/go-migrations sqlite3 go.db version",
|
||||||
|
"./bin/custom-goose -dir=examples/go-migrations sqlite3 go.db down",
|
||||||
|
"./bin/custom-goose -dir=examples/go-migrations sqlite3 go.db status",
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, cmd := range commands {
|
||||||
|
args := strings.Split(cmd, " ")
|
||||||
|
out, err := exec.Command(args[0], args[1:]...).CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("%s:\n%v\n\n%s", err, cmd, out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
30
vendor/github.com/pressly/goose/log.go
generated
vendored
Normal file
30
vendor/github.com/pressly/goose/log.go
generated
vendored
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
package goose
|
||||||
|
|
||||||
|
import (
|
||||||
|
std "log"
|
||||||
|
)
|
||||||
|
|
||||||
|
var log Logger = &stdLogger{}
|
||||||
|
|
||||||
|
// Logger is standart logger interface
|
||||||
|
type Logger interface {
|
||||||
|
Fatal(v ...interface{})
|
||||||
|
Fatalf(format string, v ...interface{})
|
||||||
|
Print(v ...interface{})
|
||||||
|
Println(v ...interface{})
|
||||||
|
Printf(format string, v ...interface{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLogger sets the logger for package output
|
||||||
|
func SetLogger(l Logger) {
|
||||||
|
log = l
|
||||||
|
}
|
||||||
|
|
||||||
|
// stdLogger is a default logger that outputs to a stdlib's log.std logger.
|
||||||
|
type stdLogger struct{}
|
||||||
|
|
||||||
|
func (*stdLogger) Fatal(v ...interface{}) { std.Fatal(v...) }
|
||||||
|
func (*stdLogger) Fatalf(format string, v ...interface{}) { std.Fatalf(format, v...) }
|
||||||
|
func (*stdLogger) Print(v ...interface{}) { std.Print(v...) }
|
||||||
|
func (*stdLogger) Println(v ...interface{}) { std.Println(v...) }
|
||||||
|
func (*stdLogger) Printf(format string, v ...interface{}) { std.Printf(format, v...) }
|
319
vendor/github.com/pressly/goose/migrate.go
generated
vendored
Normal file
319
vendor/github.com/pressly/goose/migrate.go
generated
vendored
Normal file
@ -0,0 +1,319 @@
|
|||||||
|
package goose
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
"sort"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// ErrNoCurrentVersion when a current migration version is not found.
|
||||||
|
ErrNoCurrentVersion = errors.New("no current version found")
|
||||||
|
// ErrNoNextVersion when the next migration version is not found.
|
||||||
|
ErrNoNextVersion = errors.New("no next version found")
|
||||||
|
// MaxVersion is the maximum allowed version.
|
||||||
|
MaxVersion int64 = 9223372036854775807 // max(int64)
|
||||||
|
|
||||||
|
registeredGoMigrations = map[int64]*Migration{}
|
||||||
|
)
|
||||||
|
|
||||||
|
// Migrations slice.
|
||||||
|
type Migrations []*Migration
|
||||||
|
|
||||||
|
// helpers so we can use pkg sort
|
||||||
|
func (ms Migrations) Len() int { return len(ms) }
|
||||||
|
func (ms Migrations) Swap(i, j int) { ms[i], ms[j] = ms[j], ms[i] }
|
||||||
|
func (ms Migrations) Less(i, j int) bool {
|
||||||
|
if ms[i].Version == ms[j].Version {
|
||||||
|
panic(fmt.Sprintf("goose: duplicate version %v detected:\n%v\n%v", ms[i].Version, ms[i].Source, ms[j].Source))
|
||||||
|
}
|
||||||
|
return ms[i].Version < ms[j].Version
|
||||||
|
}
|
||||||
|
|
||||||
|
// Current gets the current migration.
|
||||||
|
func (ms Migrations) Current(current int64) (*Migration, error) {
|
||||||
|
for i, migration := range ms {
|
||||||
|
if migration.Version == current {
|
||||||
|
return ms[i], nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, ErrNoCurrentVersion
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next gets the next migration.
|
||||||
|
func (ms Migrations) Next(current int64) (*Migration, error) {
|
||||||
|
for i, migration := range ms {
|
||||||
|
if migration.Version > current {
|
||||||
|
return ms[i], nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, ErrNoNextVersion
|
||||||
|
}
|
||||||
|
|
||||||
|
// Previous : Get the previous migration.
|
||||||
|
func (ms Migrations) Previous(current int64) (*Migration, error) {
|
||||||
|
for i := len(ms) - 1; i >= 0; i-- {
|
||||||
|
if ms[i].Version < current {
|
||||||
|
return ms[i], nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, ErrNoNextVersion
|
||||||
|
}
|
||||||
|
|
||||||
|
// Last gets the last migration.
|
||||||
|
func (ms Migrations) Last() (*Migration, error) {
|
||||||
|
if len(ms) == 0 {
|
||||||
|
return nil, ErrNoNextVersion
|
||||||
|
}
|
||||||
|
|
||||||
|
return ms[len(ms)-1], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Versioned gets versioned migrations.
|
||||||
|
func (ms Migrations) versioned() (Migrations, error) {
|
||||||
|
var migrations Migrations
|
||||||
|
|
||||||
|
// assume that the user will never have more than 19700101000000 migrations
|
||||||
|
for _, m := range ms {
|
||||||
|
// parse version as timestmap
|
||||||
|
versionTime, err := time.Parse(timestampFormat, fmt.Sprintf("%d", m.Version))
|
||||||
|
|
||||||
|
if versionTime.Before(time.Unix(0, 0)) || err != nil {
|
||||||
|
migrations = append(migrations, m)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return migrations, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Timestamped gets the timestamped migrations.
|
||||||
|
func (ms Migrations) timestamped() (Migrations, error) {
|
||||||
|
var migrations Migrations
|
||||||
|
|
||||||
|
// assume that the user will never have more than 19700101000000 migrations
|
||||||
|
for _, m := range ms {
|
||||||
|
// parse version as timestmap
|
||||||
|
versionTime, err := time.Parse(timestampFormat, fmt.Sprintf("%d", m.Version))
|
||||||
|
if err != nil {
|
||||||
|
// probably not a timestamp
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if versionTime.After(time.Unix(0, 0)) {
|
||||||
|
migrations = append(migrations, m)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return migrations, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms Migrations) String() string {
|
||||||
|
str := ""
|
||||||
|
for _, m := range ms {
|
||||||
|
str += fmt.Sprintln(m)
|
||||||
|
}
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddMigration adds a migration.
|
||||||
|
func AddMigration(up func(*sql.Tx) error, down func(*sql.Tx) error) {
|
||||||
|
_, filename, _, _ := runtime.Caller(1)
|
||||||
|
AddNamedMigration(filename, up, down)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddNamedMigration : Add a named migration.
|
||||||
|
func AddNamedMigration(filename string, up func(*sql.Tx) error, down func(*sql.Tx) error) {
|
||||||
|
v, _ := NumericComponent(filename)
|
||||||
|
migration := &Migration{Version: v, Next: -1, Previous: -1, Registered: true, UpFn: up, DownFn: down, Source: filename}
|
||||||
|
|
||||||
|
if existing, ok := registeredGoMigrations[v]; ok {
|
||||||
|
panic(fmt.Sprintf("failed to add migration %q: version conflicts with %q", filename, existing.Source))
|
||||||
|
}
|
||||||
|
|
||||||
|
registeredGoMigrations[v] = migration
|
||||||
|
}
|
||||||
|
|
||||||
|
// CollectMigrations returns all the valid looking migration scripts in the
|
||||||
|
// migrations folder and go func registry, and key them by version.
|
||||||
|
func CollectMigrations(dirpath string, current, target int64) (Migrations, error) {
|
||||||
|
if _, err := os.Stat(dirpath); os.IsNotExist(err) {
|
||||||
|
return nil, fmt.Errorf("%s directory does not exists", dirpath)
|
||||||
|
}
|
||||||
|
|
||||||
|
var migrations Migrations
|
||||||
|
|
||||||
|
// SQL migration files.
|
||||||
|
sqlMigrationFiles, err := filepath.Glob(dirpath + "/**.sql")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, file := range sqlMigrationFiles {
|
||||||
|
v, err := NumericComponent(file)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if versionFilter(v, current, target) {
|
||||||
|
migration := &Migration{Version: v, Next: -1, Previous: -1, Source: file}
|
||||||
|
migrations = append(migrations, migration)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Go migrations registered via goose.AddMigration().
|
||||||
|
for _, migration := range registeredGoMigrations {
|
||||||
|
v, err := NumericComponent(migration.Source)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if versionFilter(v, current, target) {
|
||||||
|
migrations = append(migrations, migration)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Go migration files
|
||||||
|
goMigrationFiles, err := filepath.Glob(dirpath + "/**.go")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, file := range goMigrationFiles {
|
||||||
|
v, err := NumericComponent(file)
|
||||||
|
if err != nil {
|
||||||
|
continue // Skip any files that don't have version prefix.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip migrations already existing migrations registered via goose.AddMigration().
|
||||||
|
if _, ok := registeredGoMigrations[v]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if versionFilter(v, current, target) {
|
||||||
|
migration := &Migration{Version: v, Next: -1, Previous: -1, Source: file, Registered: false}
|
||||||
|
migrations = append(migrations, migration)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
migrations = sortAndConnectMigrations(migrations)
|
||||||
|
|
||||||
|
return migrations, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func sortAndConnectMigrations(migrations Migrations) Migrations {
|
||||||
|
sort.Sort(migrations)
|
||||||
|
|
||||||
|
// now that we're sorted in the appropriate direction,
|
||||||
|
// populate next and previous for each migration
|
||||||
|
for i, m := range migrations {
|
||||||
|
prev := int64(-1)
|
||||||
|
if i > 0 {
|
||||||
|
prev = migrations[i-1].Version
|
||||||
|
migrations[i-1].Next = m.Version
|
||||||
|
}
|
||||||
|
migrations[i].Previous = prev
|
||||||
|
}
|
||||||
|
|
||||||
|
return migrations
|
||||||
|
}
|
||||||
|
|
||||||
|
func versionFilter(v, current, target int64) bool {
|
||||||
|
|
||||||
|
if target > current {
|
||||||
|
return v > current && v <= target
|
||||||
|
}
|
||||||
|
|
||||||
|
if target < current {
|
||||||
|
return v <= current && v > target
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnsureDBVersion retrieves the current version for this DB.
|
||||||
|
// Create and initialize the DB version table if it doesn't exist.
|
||||||
|
func EnsureDBVersion(db *sql.DB) (int64, error) {
|
||||||
|
rows, err := GetDialect().dbVersionQuery(db)
|
||||||
|
if err != nil {
|
||||||
|
return 0, createVersionTable(db)
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
// The most recent record for each migration specifies
|
||||||
|
// whether it has been applied or rolled back.
|
||||||
|
// The first version we find that has been applied is the current version.
|
||||||
|
|
||||||
|
toSkip := make([]int64, 0)
|
||||||
|
|
||||||
|
for rows.Next() {
|
||||||
|
var row MigrationRecord
|
||||||
|
if err = rows.Scan(&row.VersionID, &row.IsApplied); err != nil {
|
||||||
|
return 0, errors.Wrap(err, "failed to scan row")
|
||||||
|
}
|
||||||
|
|
||||||
|
// have we already marked this version to be skipped?
|
||||||
|
skip := false
|
||||||
|
for _, v := range toSkip {
|
||||||
|
if v == row.VersionID {
|
||||||
|
skip = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if skip {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// if version has been applied we're done
|
||||||
|
if row.IsApplied {
|
||||||
|
return row.VersionID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// latest version of migration has not been applied.
|
||||||
|
toSkip = append(toSkip, row.VersionID)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return 0, errors.Wrap(err, "failed to get next row")
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0, ErrNoNextVersion
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the db version table
|
||||||
|
// and insert the initial 0 value into it
|
||||||
|
func createVersionTable(db *sql.DB) error {
|
||||||
|
txn, err := db.Begin()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
d := GetDialect()
|
||||||
|
|
||||||
|
if _, err := txn.Exec(d.createVersionTableSQL()); err != nil {
|
||||||
|
txn.Rollback()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
version := 0
|
||||||
|
applied := true
|
||||||
|
if _, err := txn.Exec(d.insertVersionSQL(), version, applied); err != nil {
|
||||||
|
txn.Rollback()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return txn.Commit()
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetDBVersion is an alias for EnsureDBVersion, but returns -1 in error.
|
||||||
|
func GetDBVersion(db *sql.DB) (int64, error) {
|
||||||
|
version, err := EnsureDBVersion(db)
|
||||||
|
if err != nil {
|
||||||
|
return -1, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return version, nil
|
||||||
|
}
|
58
vendor/github.com/pressly/goose/migrate_test.go
generated
vendored
Normal file
58
vendor/github.com/pressly/goose/migrate_test.go
generated
vendored
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
package goose
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func newMigration(v int64, src string) *Migration {
|
||||||
|
return &Migration{Version: v, Previous: -1, Next: -1, Source: src}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMigrationSort(t *testing.T) {
|
||||||
|
|
||||||
|
ms := Migrations{}
|
||||||
|
|
||||||
|
// insert in any order
|
||||||
|
ms = append(ms, newMigration(20120000, "test"))
|
||||||
|
ms = append(ms, newMigration(20128000, "test"))
|
||||||
|
ms = append(ms, newMigration(20129000, "test"))
|
||||||
|
ms = append(ms, newMigration(20127000, "test"))
|
||||||
|
|
||||||
|
ms = sortAndConnectMigrations(ms)
|
||||||
|
|
||||||
|
sorted := []int64{20120000, 20127000, 20128000, 20129000}
|
||||||
|
|
||||||
|
validateMigrationSort(t, ms, sorted)
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateMigrationSort(t *testing.T, ms Migrations, sorted []int64) {
|
||||||
|
|
||||||
|
for i, m := range ms {
|
||||||
|
if sorted[i] != m.Version {
|
||||||
|
t.Error("incorrect sorted version")
|
||||||
|
}
|
||||||
|
|
||||||
|
var next, prev int64
|
||||||
|
|
||||||
|
if i == 0 {
|
||||||
|
prev = -1
|
||||||
|
next = ms[i+1].Version
|
||||||
|
} else if i == len(ms)-1 {
|
||||||
|
prev = ms[i-1].Version
|
||||||
|
next = -1
|
||||||
|
} else {
|
||||||
|
prev = ms[i-1].Version
|
||||||
|
next = ms[i+1].Version
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.Next != next {
|
||||||
|
t.Errorf("mismatched Next. v: %v, got %v, wanted %v\n", m, m.Next, next)
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.Previous != prev {
|
||||||
|
t.Errorf("mismatched Previous v: %v, got %v, wanted %v\n", m, m.Previous, prev)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Log(ms)
|
||||||
|
}
|
124
vendor/github.com/pressly/goose/migration.go
generated
vendored
Normal file
124
vendor/github.com/pressly/goose/migration.go
generated
vendored
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
package goose
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MigrationRecord struct.
|
||||||
|
type MigrationRecord struct {
|
||||||
|
VersionID int64
|
||||||
|
TStamp time.Time
|
||||||
|
IsApplied bool // was this a result of up() or down()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Migration struct.
|
||||||
|
type Migration struct {
|
||||||
|
Version int64
|
||||||
|
Next int64 // next version, or -1 if none
|
||||||
|
Previous int64 // previous version, -1 if none
|
||||||
|
Source string // path to .sql script
|
||||||
|
Registered bool
|
||||||
|
UpFn func(*sql.Tx) error // Up go migration function
|
||||||
|
DownFn func(*sql.Tx) error // Down go migration function
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Migration) String() string {
|
||||||
|
return fmt.Sprintf(m.Source)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Up runs an up migration.
|
||||||
|
func (m *Migration) Up(db *sql.DB) error {
|
||||||
|
if err := m.run(db, true); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
log.Println("OK ", filepath.Base(m.Source))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Down runs a down migration.
|
||||||
|
func (m *Migration) Down(db *sql.DB) error {
|
||||||
|
if err := m.run(db, false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
log.Println("OK ", filepath.Base(m.Source))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Migration) run(db *sql.DB, direction bool) error {
|
||||||
|
switch filepath.Ext(m.Source) {
|
||||||
|
case ".sql":
|
||||||
|
if err := runSQLMigration(db, m.Source, m.Version, direction); err != nil {
|
||||||
|
return errors.Wrapf(err, "failed to run SQL migration %q", filepath.Base(m.Source))
|
||||||
|
}
|
||||||
|
|
||||||
|
case ".go":
|
||||||
|
if !m.Registered {
|
||||||
|
return errors.Errorf("failed to run Go migration %q: Go functions must be registered and built into a custom binary (see https://github.com/pressly/goose/tree/master/examples/go-migrations)", m.Source)
|
||||||
|
}
|
||||||
|
tx, err := db.Begin()
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "failed to begin transaction")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn := m.UpFn
|
||||||
|
if !direction {
|
||||||
|
fn = m.DownFn
|
||||||
|
}
|
||||||
|
if fn != nil {
|
||||||
|
if err := fn(tx); err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
return errors.Wrapf(err, "failed to run Go migration %q", filepath.Base(m.Source))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if direction {
|
||||||
|
if _, err := tx.Exec(GetDialect().insertVersionSQL(), m.Version, direction); err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
return errors.Wrap(err, "failed to execute transaction")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if _, err := tx.Exec(GetDialect().deleteVersionSQL(), m.Version); err != nil {
|
||||||
|
tx.Rollback()
|
||||||
|
return errors.Wrap(err, "failed to execute transaction")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := tx.Commit(); err != nil {
|
||||||
|
return errors.Wrap(err, "failed to commit transaction")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NumericComponent looks for migration scripts with names in the form:
|
||||||
|
// XXX_descriptivename.ext where XXX specifies the version number
|
||||||
|
// and ext specifies the type of migration
|
||||||
|
func NumericComponent(name string) (int64, error) {
|
||||||
|
base := filepath.Base(name)
|
||||||
|
|
||||||
|
if ext := filepath.Ext(base); ext != ".go" && ext != ".sql" {
|
||||||
|
return 0, errors.New("not a recognized migration file type")
|
||||||
|
}
|
||||||
|
|
||||||
|
idx := strings.Index(base, "_")
|
||||||
|
if idx < 0 {
|
||||||
|
return 0, errors.New("no separator found")
|
||||||
|
}
|
||||||
|
|
||||||
|
n, e := strconv.ParseInt(base[:idx], 10, 64)
|
||||||
|
if e == nil && n <= 0 {
|
||||||
|
return 0, errors.New("migration IDs must be greater than zero")
|
||||||
|
}
|
||||||
|
|
||||||
|
return n, e
|
||||||
|
}
|
240
vendor/github.com/pressly/goose/migration_sql.go
generated
vendored
Normal file
240
vendor/github.com/pressly/goose/migration_sql.go
generated
vendored
Normal file
@ -0,0 +1,240 @@
|
|||||||
|
package goose
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"bytes"
|
||||||
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
const sqlCmdPrefix = "-- +goose "
|
||||||
|
const scanBufSize = 4 * 1024 * 1024
|
||||||
|
|
||||||
|
var bufferPool = sync.Pool{
|
||||||
|
New: func() interface{} {
|
||||||
|
return make([]byte, scanBufSize)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checks the line to see if the line has a statement-ending semicolon
|
||||||
|
// or if the line contains a double-dash comment.
|
||||||
|
func endsWithSemicolon(line string) bool {
|
||||||
|
scanBuf := bufferPool.Get().([]byte)
|
||||||
|
defer bufferPool.Put(scanBuf)
|
||||||
|
|
||||||
|
prev := ""
|
||||||
|
scanner := bufio.NewScanner(strings.NewReader(line))
|
||||||
|
scanner.Buffer(scanBuf, scanBufSize)
|
||||||
|
scanner.Split(bufio.ScanWords)
|
||||||
|
|
||||||
|
for scanner.Scan() {
|
||||||
|
word := scanner.Text()
|
||||||
|
if strings.HasPrefix(word, "--") {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
prev = word
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.HasSuffix(prev, ";")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Split the given sql script into individual statements.
|
||||||
|
//
|
||||||
|
// The base case is to simply split on semicolons, as these
|
||||||
|
// naturally terminate a statement.
|
||||||
|
//
|
||||||
|
// However, more complex cases like pl/pgsql can have semicolons
|
||||||
|
// within a statement. For these cases, we provide the explicit annotations
|
||||||
|
// 'StatementBegin' and 'StatementEnd' to allow the script to
|
||||||
|
// tell us to ignore semicolons.
|
||||||
|
func getSQLStatements(r io.Reader, direction bool) ([]string, bool, error) {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
scanBuf := bufferPool.Get().([]byte)
|
||||||
|
defer bufferPool.Put(scanBuf)
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(r)
|
||||||
|
scanner.Buffer(scanBuf, scanBufSize)
|
||||||
|
|
||||||
|
// track the count of each section
|
||||||
|
// so we can diagnose scripts with no annotations
|
||||||
|
upSections := 0
|
||||||
|
downSections := 0
|
||||||
|
|
||||||
|
statementEnded := false
|
||||||
|
ignoreSemicolons := false
|
||||||
|
directionIsActive := false
|
||||||
|
tx := true
|
||||||
|
stmts := []string{}
|
||||||
|
|
||||||
|
for scanner.Scan() {
|
||||||
|
|
||||||
|
line := scanner.Text()
|
||||||
|
|
||||||
|
// handle any goose-specific commands
|
||||||
|
if strings.HasPrefix(line, sqlCmdPrefix) {
|
||||||
|
cmd := strings.TrimSpace(line[len(sqlCmdPrefix):])
|
||||||
|
switch cmd {
|
||||||
|
case "Up":
|
||||||
|
directionIsActive = (direction == true)
|
||||||
|
upSections++
|
||||||
|
break
|
||||||
|
|
||||||
|
case "Down":
|
||||||
|
directionIsActive = (direction == false)
|
||||||
|
downSections++
|
||||||
|
break
|
||||||
|
|
||||||
|
case "StatementBegin":
|
||||||
|
if directionIsActive {
|
||||||
|
ignoreSemicolons = true
|
||||||
|
}
|
||||||
|
break
|
||||||
|
|
||||||
|
case "StatementEnd":
|
||||||
|
if directionIsActive {
|
||||||
|
statementEnded = (ignoreSemicolons == true)
|
||||||
|
ignoreSemicolons = false
|
||||||
|
}
|
||||||
|
break
|
||||||
|
|
||||||
|
case "NO TRANSACTION":
|
||||||
|
tx = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !directionIsActive {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := buf.WriteString(line + "\n"); err != nil {
|
||||||
|
return nil, false, fmt.Errorf("io err: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrap up the two supported cases: 1) basic with semicolon; 2) psql statement
|
||||||
|
// Lines that end with semicolon that are in a statement block
|
||||||
|
// do not conclude statement.
|
||||||
|
if (!ignoreSemicolons && endsWithSemicolon(line)) || statementEnded {
|
||||||
|
statementEnded = false
|
||||||
|
stmts = append(stmts, buf.String())
|
||||||
|
buf.Reset()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := scanner.Err(); err != nil {
|
||||||
|
return nil, false, fmt.Errorf("scanning migration: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// diagnose likely migration script errors
|
||||||
|
if ignoreSemicolons {
|
||||||
|
return nil, false, fmt.Errorf("parsing migration: saw '-- +goose StatementBegin' with no matching '-- +goose StatementEnd'")
|
||||||
|
}
|
||||||
|
|
||||||
|
if bufferRemaining := strings.TrimSpace(buf.String()); len(bufferRemaining) > 0 {
|
||||||
|
return nil, false, fmt.Errorf("parsing migration: unexpected unfinished SQL query: %s. potential missing semicolon", bufferRemaining)
|
||||||
|
}
|
||||||
|
|
||||||
|
if upSections == 0 && downSections == 0 {
|
||||||
|
return nil, false, fmt.Errorf("parsing migration: no Up/Down annotations found, so no statements were executed. See https://bitbucket.org/liamstask/goose/overview for details")
|
||||||
|
}
|
||||||
|
|
||||||
|
return stmts, tx, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run a migration specified in raw SQL.
|
||||||
|
//
|
||||||
|
// Sections of the script can be annotated with a special comment,
|
||||||
|
// starting with "-- +goose" to specify whether the section should
|
||||||
|
// be applied during an Up or Down migration
|
||||||
|
//
|
||||||
|
// All statements following an Up or Down directive are grouped together
|
||||||
|
// until another direction directive is found.
|
||||||
|
func runSQLMigration(db *sql.DB, sqlFile string, v int64, direction bool) error {
|
||||||
|
f, err := os.Open(sqlFile)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "failed to open SQL migration file")
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
statements, useTx, err := getSQLStatements(f, direction)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if useTx {
|
||||||
|
// TRANSACTION.
|
||||||
|
|
||||||
|
printInfo("Begin transaction\n")
|
||||||
|
|
||||||
|
tx, err := db.Begin()
|
||||||
|
if err != nil {
|
||||||
|
errors.Wrap(err, "failed to begin transaction")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, query := range statements {
|
||||||
|
printInfo("Executing statement: %s\n", clearStatement(query))
|
||||||
|
if _, err = tx.Exec(query); err != nil {
|
||||||
|
printInfo("Rollback transaction\n")
|
||||||
|
tx.Rollback()
|
||||||
|
return errors.Wrapf(err, "failed to execute SQL query %q", clearStatement(query))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if direction {
|
||||||
|
if _, err := tx.Exec(GetDialect().insertVersionSQL(), v, direction); err != nil {
|
||||||
|
printInfo("Rollback transaction\n")
|
||||||
|
tx.Rollback()
|
||||||
|
return errors.Wrap(err, "failed to insert new goose version")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if _, err := tx.Exec(GetDialect().deleteVersionSQL(), v); err != nil {
|
||||||
|
printInfo("Rollback transaction\n")
|
||||||
|
tx.Rollback()
|
||||||
|
return errors.Wrap(err, "failed to delete goose version")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printInfo("Commit transaction\n")
|
||||||
|
if err := tx.Commit(); err != nil {
|
||||||
|
return errors.Wrap(err, "failed to commit transaction")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NO TRANSACTION.
|
||||||
|
for _, query := range statements {
|
||||||
|
printInfo("Executing statement: %s\n", clearStatement(query))
|
||||||
|
if _, err := db.Exec(query); err != nil {
|
||||||
|
return errors.Wrapf(err, "failed to execute SQL query %q", clearStatement(query))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if _, err := db.Exec(GetDialect().insertVersionSQL(), v, direction); err != nil {
|
||||||
|
return errors.Wrap(err, "failed to insert new goose version")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func printInfo(s string, args ...interface{}) {
|
||||||
|
if verbose {
|
||||||
|
log.Printf(s, args...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
matchSQLComments = regexp.MustCompile(`(?m)^--.*$[\r\n]*`)
|
||||||
|
matchEmptyLines = regexp.MustCompile(`(?m)^$[\r\n]*`)
|
||||||
|
)
|
||||||
|
|
||||||
|
func clearStatement(s string) string {
|
||||||
|
s = matchSQLComments.ReplaceAllString(s, ``)
|
||||||
|
return matchEmptyLines.ReplaceAllString(s, ``)
|
||||||
|
}
|
264
vendor/github.com/pressly/goose/migration_sql_test.go
generated
vendored
Normal file
264
vendor/github.com/pressly/goose/migration_sql_test.go
generated
vendored
Normal file
@ -0,0 +1,264 @@
|
|||||||
|
package goose
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSemicolons(t *testing.T) {
|
||||||
|
|
||||||
|
type testData struct {
|
||||||
|
line string
|
||||||
|
result bool
|
||||||
|
}
|
||||||
|
|
||||||
|
tests := []testData{
|
||||||
|
{
|
||||||
|
line: "END;",
|
||||||
|
result: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
line: "END; -- comment",
|
||||||
|
result: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
line: "END ; -- comment",
|
||||||
|
result: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
line: "END -- comment",
|
||||||
|
result: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
line: "END -- comment ;",
|
||||||
|
result: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
line: "END \" ; \" -- comment",
|
||||||
|
result: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
r := endsWithSemicolon(test.line)
|
||||||
|
if r != test.result {
|
||||||
|
t.Errorf("incorrect semicolon. got %v, want %v", r, test.result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSplitStatements(t *testing.T) {
|
||||||
|
|
||||||
|
type testData struct {
|
||||||
|
sql string
|
||||||
|
direction bool
|
||||||
|
count int
|
||||||
|
}
|
||||||
|
|
||||||
|
tests := []testData{
|
||||||
|
{
|
||||||
|
sql: functxt,
|
||||||
|
direction: true,
|
||||||
|
count: 2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sql: functxt,
|
||||||
|
direction: false,
|
||||||
|
count: 2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sql: multitxt,
|
||||||
|
direction: true,
|
||||||
|
count: 2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sql: multitxt,
|
||||||
|
direction: false,
|
||||||
|
count: 2,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
stmts, _, err := getSQLStatements(strings.NewReader(test.sql), test.direction)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
if len(stmts) != test.count {
|
||||||
|
t.Errorf("incorrect number of stmts. got %v, want %v", len(stmts), test.count)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUseTransactions(t *testing.T) {
|
||||||
|
type testData struct {
|
||||||
|
fileName string
|
||||||
|
useTransactions bool
|
||||||
|
}
|
||||||
|
|
||||||
|
tests := []testData{
|
||||||
|
{
|
||||||
|
fileName: "./examples/sql-migrations/00001_create_users_table.sql",
|
||||||
|
useTransactions: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fileName: "./examples/sql-migrations/00002_rename_root.sql",
|
||||||
|
useTransactions: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fileName: "./examples/sql-migrations/00003_no_transaction.sql",
|
||||||
|
useTransactions: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
f, err := os.Open(test.fileName)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
_, useTx, err := getSQLStatements(f, true)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
if useTx != test.useTransactions {
|
||||||
|
t.Errorf("Failed transaction check. got %v, want %v", useTx, test.useTransactions)
|
||||||
|
}
|
||||||
|
f.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParsingErrors(t *testing.T) {
|
||||||
|
type testData struct {
|
||||||
|
sql string
|
||||||
|
error bool
|
||||||
|
}
|
||||||
|
tests := []testData{
|
||||||
|
{
|
||||||
|
sql: statementBeginNoStatementEnd,
|
||||||
|
error: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sql: unfinishedSQL,
|
||||||
|
error: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sql: noUpDownAnnotations,
|
||||||
|
error: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
_, _, err := getSQLStatements(strings.NewReader(test.sql), true)
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("Failed transaction check. got %v, want %v", err, test.error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var functxt = `-- +goose Up
|
||||||
|
CREATE TABLE IF NOT EXISTS histories (
|
||||||
|
id BIGSERIAL PRIMARY KEY,
|
||||||
|
current_value varchar(2000) NOT NULL,
|
||||||
|
created_at timestamp with time zone NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
-- +goose StatementBegin
|
||||||
|
CREATE OR REPLACE FUNCTION histories_partition_creation( DATE, DATE )
|
||||||
|
returns void AS $$
|
||||||
|
DECLARE
|
||||||
|
create_query text;
|
||||||
|
BEGIN
|
||||||
|
FOR create_query IN SELECT
|
||||||
|
'CREATE TABLE IF NOT EXISTS histories_'
|
||||||
|
|| TO_CHAR( d, 'YYYY_MM' )
|
||||||
|
|| ' ( CHECK( created_at >= timestamp '''
|
||||||
|
|| TO_CHAR( d, 'YYYY-MM-DD 00:00:00' )
|
||||||
|
|| ''' AND created_at < timestamp '''
|
||||||
|
|| TO_CHAR( d + INTERVAL '1 month', 'YYYY-MM-DD 00:00:00' )
|
||||||
|
|| ''' ) ) inherits ( histories );'
|
||||||
|
FROM generate_series( $1, $2, '1 month' ) AS d
|
||||||
|
LOOP
|
||||||
|
EXECUTE create_query;
|
||||||
|
END LOOP; -- LOOP END
|
||||||
|
END; -- FUNCTION END
|
||||||
|
$$
|
||||||
|
language plpgsql;
|
||||||
|
-- +goose StatementEnd
|
||||||
|
|
||||||
|
-- +goose Down
|
||||||
|
drop function histories_partition_creation(DATE, DATE);
|
||||||
|
drop TABLE histories;
|
||||||
|
`
|
||||||
|
|
||||||
|
// test multiple up/down transitions in a single script
|
||||||
|
var multitxt = `-- +goose Up
|
||||||
|
CREATE TABLE post (
|
||||||
|
id int NOT NULL,
|
||||||
|
title text,
|
||||||
|
body text,
|
||||||
|
PRIMARY KEY(id)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- +goose Down
|
||||||
|
DROP TABLE post;
|
||||||
|
|
||||||
|
-- +goose Up
|
||||||
|
CREATE TABLE fancier_post (
|
||||||
|
id int NOT NULL,
|
||||||
|
title text,
|
||||||
|
body text,
|
||||||
|
created_on timestamp without time zone,
|
||||||
|
PRIMARY KEY(id)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- +goose Down
|
||||||
|
DROP TABLE fancier_post;
|
||||||
|
`
|
||||||
|
|
||||||
|
var statementBeginNoStatementEnd = `-- +goose Up
|
||||||
|
CREATE TABLE IF NOT EXISTS histories (
|
||||||
|
id BIGSERIAL PRIMARY KEY,
|
||||||
|
current_value varchar(2000) NOT NULL,
|
||||||
|
created_at timestamp with time zone NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
-- +goose StatementBegin
|
||||||
|
CREATE OR REPLACE FUNCTION histories_partition_creation( DATE, DATE )
|
||||||
|
returns void AS $$
|
||||||
|
DECLARE
|
||||||
|
create_query text;
|
||||||
|
BEGIN
|
||||||
|
FOR create_query IN SELECT
|
||||||
|
'CREATE TABLE IF NOT EXISTS histories_'
|
||||||
|
|| TO_CHAR( d, 'YYYY_MM' )
|
||||||
|
|| ' ( CHECK( created_at >= timestamp '''
|
||||||
|
|| TO_CHAR( d, 'YYYY-MM-DD 00:00:00' )
|
||||||
|
|| ''' AND created_at < timestamp '''
|
||||||
|
|| TO_CHAR( d + INTERVAL '1 month', 'YYYY-MM-DD 00:00:00' )
|
||||||
|
|| ''' ) ) inherits ( histories );'
|
||||||
|
FROM generate_series( $1, $2, '1 month' ) AS d
|
||||||
|
LOOP
|
||||||
|
EXECUTE create_query;
|
||||||
|
END LOOP; -- LOOP END
|
||||||
|
END; -- FUNCTION END
|
||||||
|
$$
|
||||||
|
language plpgsql;
|
||||||
|
|
||||||
|
-- +goose Down
|
||||||
|
drop function histories_partition_creation(DATE, DATE);
|
||||||
|
drop TABLE histories;
|
||||||
|
`
|
||||||
|
|
||||||
|
var unfinishedSQL = `
|
||||||
|
-- +goose Up
|
||||||
|
ALTER TABLE post
|
||||||
|
|
||||||
|
-- +goose Down
|
||||||
|
`
|
||||||
|
var noUpDownAnnotations = `
|
||||||
|
CREATE TABLE post (
|
||||||
|
id int NOT NULL,
|
||||||
|
title text,
|
||||||
|
body text,
|
||||||
|
PRIMARY KEY(id)
|
||||||
|
);
|
||||||
|
`
|
33
vendor/github.com/pressly/goose/redo.go
generated
vendored
Normal file
33
vendor/github.com/pressly/goose/redo.go
generated
vendored
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
package goose
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Redo rolls back the most recently applied migration, then runs it again.
|
||||||
|
func Redo(db *sql.DB, dir string) error {
|
||||||
|
currentVersion, err := GetDBVersion(db)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
migrations, err := CollectMigrations(dir, minVersion, maxVersion)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
current, err := migrations.Current(currentVersion)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := current.Down(db); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := current.Up(db); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
60
vendor/github.com/pressly/goose/reset.go
generated
vendored
Normal file
60
vendor/github.com/pressly/goose/reset.go
generated
vendored
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
package goose
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"sort"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Reset rolls back all migrations
|
||||||
|
func Reset(db *sql.DB, dir string) error {
|
||||||
|
migrations, err := CollectMigrations(dir, minVersion, maxVersion)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "failed to collect migrations")
|
||||||
|
}
|
||||||
|
statuses, err := dbMigrationsStatus(db)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "failed to get status of migrations")
|
||||||
|
}
|
||||||
|
sort.Sort(sort.Reverse(migrations))
|
||||||
|
|
||||||
|
for _, migration := range migrations {
|
||||||
|
if !statuses[migration.Version] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err = migration.Down(db); err != nil {
|
||||||
|
return errors.Wrap(err, "failed to db-down")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func dbMigrationsStatus(db *sql.DB) (map[int64]bool, error) {
|
||||||
|
rows, err := GetDialect().dbVersionQuery(db)
|
||||||
|
if err != nil {
|
||||||
|
return map[int64]bool{}, nil
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
// The most recent record for each migration specifies
|
||||||
|
// whether it has been applied or rolled back.
|
||||||
|
|
||||||
|
result := make(map[int64]bool)
|
||||||
|
|
||||||
|
for rows.Next() {
|
||||||
|
var row MigrationRecord
|
||||||
|
if err = rows.Scan(&row.VersionID, &row.IsApplied); err != nil {
|
||||||
|
return nil, errors.Wrap(err, "failed to scan row")
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := result[row.VersionID]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
result[row.VersionID] = row.IsApplied
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
54
vendor/github.com/pressly/goose/status.go
generated
vendored
Normal file
54
vendor/github.com/pressly/goose/status.go
generated
vendored
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
package goose
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
|
"path/filepath"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Status prints the status of all migrations.
|
||||||
|
func Status(db *sql.DB, dir string) error {
|
||||||
|
// collect all migrations
|
||||||
|
migrations, err := CollectMigrations(dir, minVersion, maxVersion)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "failed to collect migrations")
|
||||||
|
}
|
||||||
|
|
||||||
|
// must ensure that the version table exists if we're running on a pristine DB
|
||||||
|
if _, err := EnsureDBVersion(db); err != nil {
|
||||||
|
return errors.Wrap(err, "failed to ensure DB version")
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println(" Applied At Migration")
|
||||||
|
log.Println(" =======================================")
|
||||||
|
for _, migration := range migrations {
|
||||||
|
if err := printMigrationStatus(db, migration.Version, filepath.Base(migration.Source)); err != nil {
|
||||||
|
return errors.Wrap(err, "failed to print status")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func printMigrationStatus(db *sql.DB, version int64, script string) error {
|
||||||
|
q := fmt.Sprintf("SELECT tstamp, is_applied FROM %s WHERE version_id=%d ORDER BY tstamp DESC LIMIT 1", TableName(), version)
|
||||||
|
|
||||||
|
var row MigrationRecord
|
||||||
|
err := db.QueryRow(q).Scan(&row.TStamp, &row.IsApplied)
|
||||||
|
if err != nil && err != sql.ErrNoRows {
|
||||||
|
return errors.Wrap(err, "failed to query the latest migration")
|
||||||
|
}
|
||||||
|
|
||||||
|
var appliedAt string
|
||||||
|
if row.IsApplied {
|
||||||
|
appliedAt = row.TStamp.Format(time.ANSIC)
|
||||||
|
} else {
|
||||||
|
appliedAt = "Pending"
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf(" %-24s -- %v\n", appliedAt, script)
|
||||||
|
return nil
|
||||||
|
}
|
65
vendor/github.com/pressly/goose/up.go
generated
vendored
Normal file
65
vendor/github.com/pressly/goose/up.go
generated
vendored
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
package goose
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
)
|
||||||
|
|
||||||
|
// UpTo migrates up to a specific version.
|
||||||
|
func UpTo(db *sql.DB, dir string, version int64) error {
|
||||||
|
migrations, err := CollectMigrations(dir, minVersion, version)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
current, err := GetDBVersion(db)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
next, err := migrations.Next(current)
|
||||||
|
if err != nil {
|
||||||
|
if err == ErrNoNextVersion {
|
||||||
|
log.Printf("goose: no migrations to run. current version: %d\n", current)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = next.Up(db); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Up applies all available migrations.
|
||||||
|
func Up(db *sql.DB, dir string) error {
|
||||||
|
return UpTo(db, dir, maxVersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpByOne migrates up by a single version.
|
||||||
|
func UpByOne(db *sql.DB, dir string) error {
|
||||||
|
migrations, err := CollectMigrations(dir, minVersion, maxVersion)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
currentVersion, err := GetDBVersion(db)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
next, err := migrations.Next(currentVersion)
|
||||||
|
if err != nil {
|
||||||
|
if err == ErrNoNextVersion {
|
||||||
|
log.Printf("goose: no migrations to run. current version: %d\n", currentVersion)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = next.Up(db); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
28
vendor/github.com/pressly/goose/version.go
generated
vendored
Normal file
28
vendor/github.com/pressly/goose/version.go
generated
vendored
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package goose
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Version prints the current version of the database.
|
||||||
|
func Version(db *sql.DB, dir string) error {
|
||||||
|
current, err := GetDBVersion(db)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("goose: version %v\n", current)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var tableName = "goose_db_version"
|
||||||
|
|
||||||
|
// TableName returns goose db version table name
|
||||||
|
func TableName() string {
|
||||||
|
return tableName
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetTableName set goose db version table name
|
||||||
|
func SetTableName(n string) {
|
||||||
|
tableName = n
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user