DERO-HE STARGATE Testnet Release27

This commit is contained in:
Captain 2021-11-21 17:09:14 +00:00
parent ac9d12577c
commit 2ef26faa40
No known key found for this signature in database
GPG Key ID: 18CDB3ED5E85D2D4
25 changed files with 2683 additions and 16 deletions

View File

@ -123,9 +123,9 @@ func (chain *Blockchain) Get_Difficulty_At_Tips(tips []crypto.Hash) *big.Int {
step := new(big.Int) step := new(big.Int)
if globals.IsMainnet() { if globals.IsMainnet() {
MinimumDifficulty = new(big.Int).SetUint64(config.MAINNET_MINIMUM_DIFFICULTY) // this must be controllable parameter MinimumDifficulty = new(big.Int).SetUint64(config.Settings.MAINNET_MINIMUM_DIFFICULTY) // this must be controllable parameter
} else { } else {
MinimumDifficulty = new(big.Int).SetUint64(config.TESTNET_MINIMUM_DIFFICULTY) // this must be controllable parameter MinimumDifficulty = new(big.Int).SetUint64(config.Settings.TESTNET_MINIMUM_DIFFICULTY) // this must be controllable parameter
} }
GenesisDifficulty := new(big.Int).SetUint64(1) GenesisDifficulty := new(big.Int).SetUint64(1)

View File

@ -327,12 +327,12 @@ func (pool *Mempool) Mempool_Print() {
}) })
loggerpool.Info(fmt.Sprintf("Total TX in mempool = %d\n", len(klist))) loggerpool.Info(fmt.Sprintf("Total TX in mempool = %d\n", len(klist)))
loggerpool.Info(fmt.Sprintf("%20s %14s %7s %7s %6s %32s\n", "Added", "Size", "Height", "TXID")) loggerpool.Info(fmt.Sprintf("%20s %7s %6s %32s\n", "Added", "Size", "Height", "TXID"))
for i := range klist { for i := range klist {
k := klist[i] k := klist[i]
v := vlist[i] v := vlist[i]
loggerpool.Info(fmt.Sprintf("%20s %14s %7d %7d %6d %32s\n", time.Unix(int64(v.Added), 0).UTC().Format(time.RFC3339), loggerpool.Info(fmt.Sprintf("%20s %7d %6d %32s\n", time.Unix(int64(v.Added), 0).UTC().Format(time.RFC3339),
len(v.Tx.Serialize()), v.Height, k)) len(v.Tx.Serialize()), v.Height, k))
} }
} }

View File

@ -28,7 +28,7 @@ func Test_mempool(t *testing.T) {
// this tx is from internal testnet // this tx is from internal testnet
// tx_id 499002f3fb7fea8a71dac93dea65c0ff74be05b0858078a27a48d78b71eacf87 // tx_id 499002f3fb7fea8a71dac93dea65c0ff74be05b0858078a27a48d78b71eacf87
tx_hex := "010000030101000000000000000000000000000000000000000000000000000000000000000000002aa937d8879cebc74425f4fee7bcc81b424dd6f2130d0548a0c4afa7f9e40b1c41ee8f9487971ee3ecf35cef40d26b6382b49b6315370f96696cda3394a550c4bd5d301a3b91737c354573ffa0d9e921a523af274b2ccc5d7078efd5c489c8deba43a0205aafd9f89b80cd432825f2f0bcbfa61f82bc30c2a83a7976e6743aad48fbdb8c7799cbf3131d156d2ac7b780c80202000d136ae832342f1ecf99a935e1dcdc255c7f33297b204383e7539f31278fd097001e261e85c34489c313aaa05ce4abb3772d31e5d192321dc2cce7fe45b21f4d114244b8fbf5a6cc1f0119b69ed785e7c8739c306b4a35278159bbb6977a28ea71ea0ffc5a6398ec935e000b8b5806e6e7a0bd8b57e24edd21cfafa79a54bf7d3bc74643294b88920b3b900113dad7529adb51a5b634140f01c8389c57c92af984d16cf4400a463a448fd7e7007ed6b651c46aab06f6f9677d50ee78cf98a3e121b325a0cab4bf67910f9a92d0153222d7f87cedc63a5b773a5c5482479e554d56d906eaf5d5f9b1c37d9f52170029bd3c397bcb89dca495d7ee8cab0e5e4cd8b204dff933e8673cacece063830d010676be97476c5028c633ca3160a7367352750304ee2be99bf6311c198b1207a20006364d038c0d479f5264c085c8f210ea88f8a7f08535240c3541c641aadae496002449b5477c26ff74be1159c36d71d9dbca3ab2c2a0804590637fb79e0d89e5d801053afa58bcdbf17aa0ce544e3ca12e9b5c204aaea6a0b5698fef75669c1d91690114acfe9439eff58fe532aa243187adadf7118ba78f9772429b3041a07cb203df0125ffa09b619faa1b890d0a5323a4f162b4d0d1a6864f9a0261820bfc901dea4501098ad5f3c3bb0629de269f3e01633b4e0ee6a8f74e648aa40f57dd2496ed7230010f100ede75074bafc160fc1327545a44fd8d34627b136fed6de0bfa72df0e1330116108dc5545f42b9f5b8e302d1546930d9840c18fc92e425bacd0856e842f60f011b7f689aa43b95bbfd02ee20aab2cac2077c9639b9e4f84b8b221b37cdaf13a2010b979e41274c4338395dfc447c0d4a548caf414ee425aab1748475cca9faef4e012051ff90139adccfbf0459e3a5c0638dfb1654ee728cba59c6803ab1daaddda9011ef927e921f956134892499c7513bc2e077986295c050633a1566d449fd0954a00071f56b24c65aaa4549be3c859ac8ec75fe302d89e8755166da3f7d0d08ae285011983fdc2aa2a0611187b0b86119508e3f7642dfe7380f5bdbe6ad27f0dc4ccf201127e3c3923518fec22a4ead80845bbe6008d9b790bd50ec6ef83b087d0490995011982ad7c49288a3115c638a04e14a0c74a75008359b40aff422e9972e276929800237a7bfd1fe105865abbc36e926de565530da393da1ddc0b1005bb0c31504402002569e7e95e54711903c29f63cb8c6b58d47ea3299c455c8738b543d552e8dffe012ea47467abedda0d168d06bcf2f45ab8fa090b90d6e4662d4052df0488084403057542fc7603a7d717dd8267dc036330e3083d2a1562bf5b1ecfbce99804c05100000000000000000000000000000000000000000000000000000000000000000e377bd9c8a2b6faf14c766e51fc9415ed979d604e3d5dcc800b3c5a9c6bec1f239a65bdeb2028926a6fa13fdf2caf0a09ba17e1420b74bef294aa4c9731d2c71f46ae2c57612f525f14cf49e86be5a984aab4d8c25ec3818e19612ba07722d500082c5b600665b3a718fad7516b976749ac3692a6ccf60225c04d1da272a95780012c932f36c1cca1753377ad16b2dbecabb58a2efbf8e88a066d80efba20addf8208d52649fc24ba86ecd87da10efd8ab480c48cadf4ee205e60d10f6e1f1527dd01171915999416a85d08a06e4a8ed18797fcd62910e6624222e120bdd60a00db22fb4d9f0a7aee7570f72b99c673195c67b7dc5e53aa5a32ffc04b409aa79cb52faa6cb8374cd242bd90fd2da9a891fc18022112ecb943b8b0f6c69a4b2e33ad0b16abbd22b38f11f1e76bfd6c1950864753ef84ce0ba869b82f909fbe2751ef0e02b170d107ec7cf6c25d9fdbdd86f5e4790e532254f89ad6cd477bf30816e207ce092de3148c4fd818812abfcadc03a325991fb7dd48b5a54266137709715a11556344ae9bbb2afd1e7ea7fa417f1308d20fdef8dd2168f89101d0643ce62217ee68724101b6e8644ad0860940f95b1674a1befa7ec45235d2c93043087e9001211d72b9f744364770a276f99a183dc184f90ad09d034119f5e4754249046bb201156984d6a418664bda88f98075679d6bb8cc4c644ff727278931797db12a2c65012698726eabb2580faecafa12befe8855a7074da2b4f2d2cd74fd481e818f2287001d445415f6abc3b4a9ff7043906d8f83d5c61ad853b12a72c152a21b9627d8bf00004d5a3deaf642e40e1401ead28babb7ce0263afcc3b3f1e7876a31d6fbea5e90125bff3189cf6ab0e68caa851e60fc92483d3bc2a5ecd511594e7f80f565301c101247b8928fb1866a98b99add332a7e6065cf27ed8a7d48d7775727299308f0ab9002cb7663076e2883fe31b3397f6f5460491835f1a23c173f858fb93cbc312cf360117c5b8e4a25c2e3228b6f4d06525f96e818772292b095b7d344eb3f9f18735bd000889c0fcc3c2f25fe74c915b178db653b0d7725efdc6e2e80a2770738cc3bff9002a578a39364fa16dc82fd7f15872da799f2ddc6422491b9e5c6447ea87adb01a00187461816522889fc2bcb1dc1b0b5d2537df3ae2bb58cbef2b58cb678ba6b9f30121f1cf89f1e9840aace8469b06edf81e9930ddfb8aef4a2c3d46e8551cc40ab400" tx_hex := "01000003519b9e874a9dd7fcbfb7802268123dcf970c336891101a3a0705855b72b9eb08c80100000000000000000000000000000000000000000000000000000000000000000000f394d06566a81b024fd8624b4c8592f8b9344e58f227261eb08d821bd190b4ac9c7df0660038ddcf881602a14fe5ad8eebff83d3ce3541a1f232fe61acf71109e417160936863e8c0597c798b73ef08e76b8eeebcaf20260ba91fcdef5f626361f824dc6197b02c599d4511c624a933226d8fccc125611ec80d8ad5acea4baf2f1c77e4c5525d9859b40f43daaf3d4e4450203d80419dcb026b9adbd7d6912284ee9ce20f3721076947f16e1faefd9b8c35116f4cf0044ead0a12fda3f3bcf2ed91627b922c02c10d112df9e782d3750cda151f6ba2ebe6495065141f32800894566011198c4055458005a31d3e285037446ba14bac54420bcab87cbebeaccab1f158b011e90132b7310e6c866e348cab68d21bad1d9f811b4d667a1e40bdef1a19259d3000b972ae06da958658b12ca4a45c2c6ea50d305be86f7e979fc962c687eb012f401a2c4bf0beb6c713343b94d65ee6d937660480daf670ab5b0ed421a9103e8a25119c836dd799600e67e4ec66ef680833398a99b16956aed2ee5bd9e6c8e68009a01145636e5e448d6c8ab902db394aa9c5aeee92dd150e1150d5b8f6674f330c279010912df27232ae126525a130ed8a9b4dee62eb57ce1d8a42ae9bcef867b10ce94012f94aa78846fcdda504243f83f3122aee5dc38dd32fa2a90224b3a40b4cf79c301129028709e39591c55e6e477a36cc26dc2efd7183fb59f51635dbd114dfed9d5010d66f31b781fa181c2114600ee1f03d55439355265700fb9d35ac684a19db398001e12558cc17e59fb85fb825481dee6fef3612c043bb38ca4833183da5381364600077a99d4d2df2f06067359f178a40f98a3e0943309c5ce3ce5398b9909174254012aa49cfc78ebec51c00e7824db0d8d41ef43fbb0396824d2c31b7db64124cc61000a8b51bd6c94a502f7aea3e5001f00d76b165ad580e48f8aa72813da8240286e00055f3480aa7cdb68a20d4b1e567d42389b44cf4e345da9e5a5655a80418695bc012c8f1e1ef8af646b4fb08afaeb3febde17c4c0d04b30dfd22d96a32ced9c9439010c40484e1547d307ad56b79bb7450e4eaaed7ed79bd5392dffd7449043f8783a0015104264f8d80356176ca6fdf4777e4ebc8edcbab50f8b6c366ac75ebd6bb5c701078d55053d2d41f21f51d5e617f282ba9dfa2576f0231048dd73998ceaa699fd0105821b61addd6935c7d80e65c706f0f2aa2d73ad22c5548c9c8b92cd82689dc40115f576c413a37014b9ee5377b121c69ad6e0f00f2b4f6c99d1f68b00a5d923370119b29fe6e9cf35f1344e24d52ee1fdb6521de3176f3d2b2a2b9327ae6e6cfbb10017198369a6ff180253700361c40e7f378c8e7ead6e04f01dbf5b4c47e7e1e4ff001abaf84628764eccbc5d0f66dc0a99505bb0e598362c45312470526afad11caf00242c6a902c564b3b363eb4ae08f643f18571779428358bfbdaf9856b0ebf229f0100000000000000000000000000000000000000000000000000000000000000001b7a78b6f573d4ac5d3a8d7d10dafac0dbc92604474417b29d40448d9fbc821d0fe3f73da41b27752d5db0658fcc0bff7da21112417ac719e491fdd43c8e5d0b07bcca22c27367a276e6a4e0cfb1bfbc772842898356ad4723101d4ada5137f409bb3b290d7519da3af15feb09e183e2be809690099551f1cb984deb1295b7611dd0cfd9000482314a388512d278fc22b2f6e3fc6e95023b4bd228e22626b7440119fa2c6f45a33b008ef5b23a5522ebbf0bf5f26d8263613a7f9b5ad9a192357600107a023453f7f79f413756dfba0096ae5d13158bbbb147089a020e819ef6640728acf01c811b967d1a14d767ac20088c5ca1613aa5d94ebe7fe2840b6431d8d002137dae183071d12cd9fb14c4b4738ef750ff514ce26257d1245eaedfea625516bfcb075a33a8910dc4e40742bfaa70d95591711e9db33d0db0be06cc819817072c22a9c81f4369f68bb1ef71c7f7458671d647caef18b30cca91da4f1b201d082a03306b4a07d1f0e1a8cc8844038fc524201a6c3a346a971203fd45458d292987d44049eecdac25c5622465a8d683a43621612d2fb283724b17a7bfa3bad2266a6fb1cf669eef21c90e24e85d6ab48e8b237355e964407dde00d65fb442dd210ce0378349f533c0e8ab65293de5319e246a044ed22b1e6db28add1508dd6f0da22954eea8a431b211a8b54147e32fec6593f9fb731389f62f94d5047e0f3301216576c71a79629bc3879325280e216d59cf7e6ff2d6a0babe418f8f2ed603ce010e16785f8c855043221ed5a603d4ed4e8e90059669543738ceb2a04dc996079c01264e9beaf4bb82e1b8f47bb0c239167064001e306eeef2b5495ec42754806b65012357f738543b13594ff081a070dbc0575645ac5ce8e0f89d3afdeb3d49e9ddae012a17d5095b9cef08f6eee2ce733dbf2cfcdb8c23e39410ed973e68cf8505266d00280c52b45752dd12ba84499618898111a8f9b19f2b76c06917e57eef221f3387011cc3360b478d144118a82a3c4391814f34aac2fb0f2d043394304bed179689e501292ca5631820f5f465242b4cc517f06c153c176a43f77daca463b7e2d3e2d7ba001aa0b2c90c3172cd2556137d78748f47924432449210d8b2f5e27adb6210bc77012c92a12526a5b0b1ef60994eb4d08e9bb5a3ea330d417838a52ad8636d37fa9e00131153c9affeefd6b98ecb6a80f5e6ea97417376030325182c064e12dd353c32011f4e25c49eea09adaa46d56642e2ea0afced2d75036acd3839435863f1ec3bf1002e19fe8456a7236c8fb77a15f87164debaad865e85c3468152a5deaffde3da6a01"
var tx, dup_tx transaction.Transaction var tx, dup_tx transaction.Transaction

View File

@ -166,12 +166,15 @@ func (chain *Blockchain) Create_new_miner_block(miner_address rpc.Address) (cbl
} }
height := chain.Calculate_Height_At_Tips(bl.Tips) // we are 1 higher than previous highest tip height := chain.Calculate_Height_At_Tips(bl.Tips) // we are 1 higher than previous highest tip
history := map[crypto.Hash]bool{} history := map[crypto.Hash]bool{}
var history_array []crypto.Hash var history_array []crypto.Hash
for i := range bl.Tips { for i := range bl.Tips {
history_array = append(history_array, chain.get_ordered_past(bl.Tips[i], 26)...) h := height - 20
if h < 0 {
h = 0
}
history_array = append(history_array, chain.get_ordered_past(bl.Tips[i], h)...)
} }
for _, h := range history_array { for _, h := range history_array {
history[h] = true history[h] = true

View File

@ -17,6 +17,7 @@
package config package config
import "github.com/satori/go.uuid" import "github.com/satori/go.uuid"
import "github.com/caarlos0/env/v6"
import "github.com/deroproject/derohe/cryptography/crypto" import "github.com/deroproject/derohe/cryptography/crypto"
// all global configuration variables are picked from here // all global configuration variables are picked from here
@ -52,12 +53,20 @@ const MAX_RINGSIZE = 128 // <= 128, ringsize will be accepted
// Minimum FEE calculation constants are here // Minimum FEE calculation constants are here
const FEE_PER_KB = uint64(100) // .00100 dero per kb const FEE_PER_KB = uint64(100) // .00100 dero per kb
const MAINNET_BOOTSTRAP_DIFFICULTY = uint64(80000000) // atlantis mainnet botstrapped at 80 MH/s
const MAINNET_MINIMUM_DIFFICULTY = uint64(800000000) // 80 MH/s
// testnet bootstraps at 1 MH type SettingsStruct struct {
const TESTNET_BOOTSTRAP_DIFFICULTY = uint64(10000) // testnet bootstrap at 50KH/s MAINNET_BOOTSTRAP_DIFFICULTY uint64 `env:"MAINNET_BOOTSTRAP_DIFFICULTY" envDefault:"80000000"`
const TESTNET_MINIMUM_DIFFICULTY = uint64(10000) // 10KH/s MAINNET_MINIMUM_DIFFICULTY uint64 `env:"MAINNET_MINIMUM_DIFFICULTY" envDefault:"80000000"`
TESTNET_BOOTSTRAP_DIFFICULTY uint64 `env:"TESTNET_BOOTSTRAP_DIFFICULTY" envDefault:"10000"`
TESTNET_MINIMUM_DIFFICULTY uint64 `env:"TESTNET_MINIMUM_DIFFICULTY" envDefault:"10000"`
}
var Settings SettingsStruct
var _ = env.Parse(&Settings)
// this single parameter controls lots of various parameters // this single parameter controls lots of various parameters
// within the consensus, it should never go below 7 // within the consensus, it should never go below 7

View File

@ -20,4 +20,4 @@ import "github.com/blang/semver/v4"
// right now it has to be manually changed // right now it has to be manually changed
// do we need to include git commitsha?? // do we need to include git commitsha??
var Version = semver.MustParse("3.4.80-1.DEROHE.STARGATE+20112021") var Version = semver.MustParse("3.4.82-1.DEROHE.STARGATE+20112021")

View File

@ -146,13 +146,13 @@ func Connection_Pending_Clear() {
if time.Now().Sub(v.update_received).Round(time.Second).Seconds() > 20 { if time.Now().Sub(v.update_received).Round(time.Second).Seconds() > 20 {
v.exit() v.exit()
Connection_Delete(v) Connection_Delete(v)
v.logger.Info("Purging connection due since idle") v.logger.V(1).Info("Purging connection due since idle")
} }
if IsAddressInBanList(Address(v)) { if IsAddressInBanList(Address(v)) {
v.exit() v.exit()
Connection_Delete(v) Connection_Delete(v)
v.logger.Info("Purging connection due to ban list") v.logger.V(1).Info("Purging connection due to ban list")
} }
return true return true
}) })

View File

@ -112,7 +112,7 @@ func Test_TX_Valid(t *testing.T) {
}{ }{
{ {
name: "4 ring test", name: "4 ring test",
txhex: "010000030101000000000000000000000000000000000000000000000000000000000000000000002aa937d8879cebc74425f4fee7bcc81b424dd6f2130d0548a0c4afa7f9e40b1c41ee8f9487971ee3ecf35cef40d26b6382b49b6315370f96696cda3394a550c4bd5d301a3b91737c354573ffa0d9e921a523af274b2ccc5d7078efd5c489c8deba43a0205aafd9f89b80cd432825f2f0bcbfa61f82bc30c2a83a7976e6743aad48fbdb8c7799cbf3131d156d2ac7b780c80202000d136ae832342f1ecf99a935e1dcdc255c7f33297b204383e7539f31278fd097001e261e85c34489c313aaa05ce4abb3772d31e5d192321dc2cce7fe45b21f4d114244b8fbf5a6cc1f0119b69ed785e7c8739c306b4a35278159bbb6977a28ea71ea0ffc5a6398ec935e000b8b5806e6e7a0bd8b57e24edd21cfafa79a54bf7d3bc74643294b88920b3b900113dad7529adb51a5b634140f01c8389c57c92af984d16cf4400a463a448fd7e7007ed6b651c46aab06f6f9677d50ee78cf98a3e121b325a0cab4bf67910f9a92d0153222d7f87cedc63a5b773a5c5482479e554d56d906eaf5d5f9b1c37d9f52170029bd3c397bcb89dca495d7ee8cab0e5e4cd8b204dff933e8673cacece063830d010676be97476c5028c633ca3160a7367352750304ee2be99bf6311c198b1207a20006364d038c0d479f5264c085c8f210ea88f8a7f08535240c3541c641aadae496002449b5477c26ff74be1159c36d71d9dbca3ab2c2a0804590637fb79e0d89e5d801053afa58bcdbf17aa0ce544e3ca12e9b5c204aaea6a0b5698fef75669c1d91690114acfe9439eff58fe532aa243187adadf7118ba78f9772429b3041a07cb203df0125ffa09b619faa1b890d0a5323a4f162b4d0d1a6864f9a0261820bfc901dea4501098ad5f3c3bb0629de269f3e01633b4e0ee6a8f74e648aa40f57dd2496ed7230010f100ede75074bafc160fc1327545a44fd8d34627b136fed6de0bfa72df0e1330116108dc5545f42b9f5b8e302d1546930d9840c18fc92e425bacd0856e842f60f011b7f689aa43b95bbfd02ee20aab2cac2077c9639b9e4f84b8b221b37cdaf13a2010b979e41274c4338395dfc447c0d4a548caf414ee425aab1748475cca9faef4e012051ff90139adccfbf0459e3a5c0638dfb1654ee728cba59c6803ab1daaddda9011ef927e921f956134892499c7513bc2e077986295c050633a1566d449fd0954a00071f56b24c65aaa4549be3c859ac8ec75fe302d89e8755166da3f7d0d08ae285011983fdc2aa2a0611187b0b86119508e3f7642dfe7380f5bdbe6ad27f0dc4ccf201127e3c3923518fec22a4ead80845bbe6008d9b790bd50ec6ef83b087d0490995011982ad7c49288a3115c638a04e14a0c74a75008359b40aff422e9972e276929800237a7bfd1fe105865abbc36e926de565530da393da1ddc0b1005bb0c31504402002569e7e95e54711903c29f63cb8c6b58d47ea3299c455c8738b543d552e8dffe012ea47467abedda0d168d06bcf2f45ab8fa090b90d6e4662d4052df0488084403057542fc7603a7d717dd8267dc036330e3083d2a1562bf5b1ecfbce99804c05100000000000000000000000000000000000000000000000000000000000000000e377bd9c8a2b6faf14c766e51fc9415ed979d604e3d5dcc800b3c5a9c6bec1f239a65bdeb2028926a6fa13fdf2caf0a09ba17e1420b74bef294aa4c9731d2c71f46ae2c57612f525f14cf49e86be5a984aab4d8c25ec3818e19612ba07722d500082c5b600665b3a718fad7516b976749ac3692a6ccf60225c04d1da272a95780012c932f36c1cca1753377ad16b2dbecabb58a2efbf8e88a066d80efba20addf8208d52649fc24ba86ecd87da10efd8ab480c48cadf4ee205e60d10f6e1f1527dd01171915999416a85d08a06e4a8ed18797fcd62910e6624222e120bdd60a00db22fb4d9f0a7aee7570f72b99c673195c67b7dc5e53aa5a32ffc04b409aa79cb52faa6cb8374cd242bd90fd2da9a891fc18022112ecb943b8b0f6c69a4b2e33ad0b16abbd22b38f11f1e76bfd6c1950864753ef84ce0ba869b82f909fbe2751ef0e02b170d107ec7cf6c25d9fdbdd86f5e4790e532254f89ad6cd477bf30816e207ce092de3148c4fd818812abfcadc03a325991fb7dd48b5a54266137709715a11556344ae9bbb2afd1e7ea7fa417f1308d20fdef8dd2168f89101d0643ce62217ee68724101b6e8644ad0860940f95b1674a1befa7ec45235d2c93043087e9001211d72b9f744364770a276f99a183dc184f90ad09d034119f5e4754249046bb201156984d6a418664bda88f98075679d6bb8cc4c644ff727278931797db12a2c65012698726eabb2580faecafa12befe8855a7074da2b4f2d2cd74fd481e818f2287001d445415f6abc3b4a9ff7043906d8f83d5c61ad853b12a72c152a21b9627d8bf00004d5a3deaf642e40e1401ead28babb7ce0263afcc3b3f1e7876a31d6fbea5e90125bff3189cf6ab0e68caa851e60fc92483d3bc2a5ecd511594e7f80f565301c101247b8928fb1866a98b99add332a7e6065cf27ed8a7d48d7775727299308f0ab9002cb7663076e2883fe31b3397f6f5460491835f1a23c173f858fb93cbc312cf360117c5b8e4a25c2e3228b6f4d06525f96e818772292b095b7d344eb3f9f18735bd000889c0fcc3c2f25fe74c915b178db653b0d7725efdc6e2e80a2770738cc3bff9002a578a39364fa16dc82fd7f15872da799f2ddc6422491b9e5c6447ea87adb01a00187461816522889fc2bcb1dc1b0b5d2537df3ae2bb58cbef2b58cb678ba6b9f30121f1cf89f1e9840aace8469b06edf81e9930ddfb8aef4a2c3d46e8551cc40ab400", txhex: "01000003519b9e874a9dd7fcbfb7802268123dcf970c336891101a3a0705855b72b9eb08c80100000000000000000000000000000000000000000000000000000000000000000000f394d06566a81b024fd8624b4c8592f8b9344e58f227261eb08d821bd190b4ac9c7df0660038ddcf881602a14fe5ad8eebff83d3ce3541a1f232fe61acf71109e417160936863e8c0597c798b73ef08e76b8eeebcaf20260ba91fcdef5f626361f824dc6197b02c599d4511c624a933226d8fccc125611ec80d8ad5acea4baf2f1c77e4c5525d9859b40f43daaf3d4e4450203d80419dcb026b9adbd7d6912284ee9ce20f3721076947f16e1faefd9b8c35116f4cf0044ead0a12fda3f3bcf2ed91627b922c02c10d112df9e782d3750cda151f6ba2ebe6495065141f32800894566011198c4055458005a31d3e285037446ba14bac54420bcab87cbebeaccab1f158b011e90132b7310e6c866e348cab68d21bad1d9f811b4d667a1e40bdef1a19259d3000b972ae06da958658b12ca4a45c2c6ea50d305be86f7e979fc962c687eb012f401a2c4bf0beb6c713343b94d65ee6d937660480daf670ab5b0ed421a9103e8a25119c836dd799600e67e4ec66ef680833398a99b16956aed2ee5bd9e6c8e68009a01145636e5e448d6c8ab902db394aa9c5aeee92dd150e1150d5b8f6674f330c279010912df27232ae126525a130ed8a9b4dee62eb57ce1d8a42ae9bcef867b10ce94012f94aa78846fcdda504243f83f3122aee5dc38dd32fa2a90224b3a40b4cf79c301129028709e39591c55e6e477a36cc26dc2efd7183fb59f51635dbd114dfed9d5010d66f31b781fa181c2114600ee1f03d55439355265700fb9d35ac684a19db398001e12558cc17e59fb85fb825481dee6fef3612c043bb38ca4833183da5381364600077a99d4d2df2f06067359f178a40f98a3e0943309c5ce3ce5398b9909174254012aa49cfc78ebec51c00e7824db0d8d41ef43fbb0396824d2c31b7db64124cc61000a8b51bd6c94a502f7aea3e5001f00d76b165ad580e48f8aa72813da8240286e00055f3480aa7cdb68a20d4b1e567d42389b44cf4e345da9e5a5655a80418695bc012c8f1e1ef8af646b4fb08afaeb3febde17c4c0d04b30dfd22d96a32ced9c9439010c40484e1547d307ad56b79bb7450e4eaaed7ed79bd5392dffd7449043f8783a0015104264f8d80356176ca6fdf4777e4ebc8edcbab50f8b6c366ac75ebd6bb5c701078d55053d2d41f21f51d5e617f282ba9dfa2576f0231048dd73998ceaa699fd0105821b61addd6935c7d80e65c706f0f2aa2d73ad22c5548c9c8b92cd82689dc40115f576c413a37014b9ee5377b121c69ad6e0f00f2b4f6c99d1f68b00a5d923370119b29fe6e9cf35f1344e24d52ee1fdb6521de3176f3d2b2a2b9327ae6e6cfbb10017198369a6ff180253700361c40e7f378c8e7ead6e04f01dbf5b4c47e7e1e4ff001abaf84628764eccbc5d0f66dc0a99505bb0e598362c45312470526afad11caf00242c6a902c564b3b363eb4ae08f643f18571779428358bfbdaf9856b0ebf229f0100000000000000000000000000000000000000000000000000000000000000001b7a78b6f573d4ac5d3a8d7d10dafac0dbc92604474417b29d40448d9fbc821d0fe3f73da41b27752d5db0658fcc0bff7da21112417ac719e491fdd43c8e5d0b07bcca22c27367a276e6a4e0cfb1bfbc772842898356ad4723101d4ada5137f409bb3b290d7519da3af15feb09e183e2be809690099551f1cb984deb1295b7611dd0cfd9000482314a388512d278fc22b2f6e3fc6e95023b4bd228e22626b7440119fa2c6f45a33b008ef5b23a5522ebbf0bf5f26d8263613a7f9b5ad9a192357600107a023453f7f79f413756dfba0096ae5d13158bbbb147089a020e819ef6640728acf01c811b967d1a14d767ac20088c5ca1613aa5d94ebe7fe2840b6431d8d002137dae183071d12cd9fb14c4b4738ef750ff514ce26257d1245eaedfea625516bfcb075a33a8910dc4e40742bfaa70d95591711e9db33d0db0be06cc819817072c22a9c81f4369f68bb1ef71c7f7458671d647caef18b30cca91da4f1b201d082a03306b4a07d1f0e1a8cc8844038fc524201a6c3a346a971203fd45458d292987d44049eecdac25c5622465a8d683a43621612d2fb283724b17a7bfa3bad2266a6fb1cf669eef21c90e24e85d6ab48e8b237355e964407dde00d65fb442dd210ce0378349f533c0e8ab65293de5319e246a044ed22b1e6db28add1508dd6f0da22954eea8a431b211a8b54147e32fec6593f9fb731389f62f94d5047e0f3301216576c71a79629bc3879325280e216d59cf7e6ff2d6a0babe418f8f2ed603ce010e16785f8c855043221ed5a603d4ed4e8e90059669543738ceb2a04dc996079c01264e9beaf4bb82e1b8f47bb0c239167064001e306eeef2b5495ec42754806b65012357f738543b13594ff081a070dbc0575645ac5ce8e0f89d3afdeb3d49e9ddae012a17d5095b9cef08f6eee2ce733dbf2cfcdb8c23e39410ed973e68cf8505266d00280c52b45752dd12ba84499618898111a8f9b19f2b76c06917e57eef221f3387011cc3360b478d144118a82a3c4391814f34aac2fb0f2d043394304bed179689e501292ca5631820f5f465242b4cc517f06c153c176a43f77daca463b7e2d3e2d7ba001aa0b2c90c3172cd2556137d78748f47924432449210d8b2f5e27adb6210bc77012c92a12526a5b0b1ef60994eb4d08e9bb5a3ea330d417838a52ad8636d37fa9e00131153c9affeefd6b98ecb6a80f5e6ea97417376030325182c064e12dd353c32011f4e25c49eea09adaa46d56642e2ea0afced2d75036acd3839435863f1ec3bf1002e19fe8456a7236c8fb77a15f87164debaad865e85c3468152a5deaffde3da6a01",
}, },
} }

View File

@ -0,0 +1 @@
github: [caarlos0]

View File

@ -0,0 +1,18 @@
version: 2
updates:
- package-ecosystem: "gomod"
directory: "/"
schedule:
interval: "daily"
time: "08:00"
labels:
- "dependencies"
- "automerge"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"
time: "08:00"
labels:
- "dependencies"
- "automerge"

View File

@ -0,0 +1,61 @@
name: build
on:
push:
branches:
- 'master'
tags:
- 'v*'
pull_request:
jobs:
build:
strategy:
matrix:
go-version: [~1.17]
os: [ ubuntu-latest, macos-latest, windows-latest ]
runs-on: ${{ matrix.os }}
steps:
-
name: Checkout
uses: actions/checkout@v2
with:
fetch-depth: 0
-
name: Set up Go
uses: actions/setup-go@v2
with:
go-version: ${{ matrix.go-version }}
-
name: Cache Go modules
uses: actions/cache@v2
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
-
name: CI
run: make setup ci
-
name: Upload coverage
uses: codecov/codecov-action@v2
if: matrix.os == 'ubuntu-latest'
with:
token: ${{ secrets.CODECOV_TOKEN }}
file: ./coverage.txt
-
name: Run GoReleaser
uses: goreleaser/goreleaser-action@v2
if: success() && startsWith(github.ref, 'refs/tags/') && matrix.os == 'ubuntu-latest'
with:
version: latest
distribution: goreleaser-pro
args: release --rm-dist
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }}
TWITTER_CONSUMER_KEY: ${{ secrets.TWITTER_CONSUMER_KEY }}
TWITTER_CONSUMER_SECRET: ${{ secrets.TWITTER_CONSUMER_SECRET }}
TWITTER_ACCESS_TOKEN: ${{ secrets.TWITTER_ACCESS_TOKEN }}
TWITTER_ACCESS_TOKEN_SECRET: ${{ secrets.TWITTER_ACCESS_TOKEN_SECRET }}

View File

@ -0,0 +1,22 @@
name: golangci-lint
on:
push:
tags:
- v*
branches:
- master
- main
pull_request:
jobs:
golangci:
name: lint
runs-on: ubuntu-latest
steps:
- uses: actions/setup-go@v2
with:
go-version: ~1.16
- uses: actions/checkout@v2
- name: golangci-lint
uses: golangci/golangci-lint-action@v2
with:
skip-go-installation: true

4
vendor/github.com/caarlos0/env/v6/.gitignore generated vendored Normal file
View File

@ -0,0 +1,4 @@
coverage.txt
bin
card.png
dist

8
vendor/github.com/caarlos0/env/v6/.golangci.yml generated vendored Normal file
View File

@ -0,0 +1,8 @@
linters:
enable:
- thelper
- gofumpt
- tparallel
- unconvert
- unparam
- wastedassign

3
vendor/github.com/caarlos0/env/v6/.goreleaser.yml generated vendored Normal file
View File

@ -0,0 +1,3 @@
includes:
- from_url:
url: https://raw.githubusercontent.com/caarlos0/.goreleaserfiles/main/lib.yml

21
vendor/github.com/caarlos0/env/v6/LICENSE.md generated vendored Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2015-2019 Carlos Alexandro Becker
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.

37
vendor/github.com/caarlos0/env/v6/Makefile generated vendored Normal file
View File

@ -0,0 +1,37 @@
SOURCE_FILES?=./...
TEST_PATTERN?=.
export GO111MODULE := on
setup:
go mod tidy
.PHONY: setup
build:
go build
.PHONY: build
test:
go test -v -failfast -race -coverpkg=./... -covermode=atomic -coverprofile=coverage.txt $(SOURCE_FILES) -run $(TEST_PATTERN) -timeout=2m
.PHONY: test
cover: test
go tool cover -html=coverage.txt
.PHONY: cover
fmt:
find . -name '*.go' -not -wholename './vendor/*' | while read -r file; do gofmt -w -s "$$file"; goimports -w "$$file"; done
.PHONY: fmt
lint:
./bin/golangci-lint run ./...
.PHONY: lint
ci: build test
.PHONY: ci
card:
wget -O card.png -c "https://og.caarlos0.dev/**env**: parse envs to structs.png?theme=light&md=1&fontSize=100px&images=https://github.com/caarlos0.png"
.PHONY: card
.DEFAULT_GOAL := ci

459
vendor/github.com/caarlos0/env/v6/README.md generated vendored Normal file
View File

@ -0,0 +1,459 @@
# env
[![Build Status](https://img.shields.io/github/workflow/status/caarlos0/env/build?style=for-the-badge)](https://github.com/caarlos0/env/actions?workflow=build)
[![Coverage Status](https://img.shields.io/codecov/c/gh/caarlos0/env.svg?logo=codecov&style=for-the-badge)](https://codecov.io/gh/caarlos0/env)
[![](http://img.shields.io/badge/godoc-reference-5272B4.svg?style=for-the-badge)](https://pkg.go.dev/github.com/caarlos0/env/v6)
Simple lib to parse envs to structs in Go.
## Example
Get the module with:
```sh
go get github.com/caarlos0/env/v6
```
The usage looks like this:
```go
package main
import (
"fmt"
"time"
"github.com/caarlos0/env/v6"
)
type config struct {
Home string `env:"HOME"`
Port int `env:"PORT" envDefault:"3000"`
Password string `env:"PASSWORD,unset"`
IsProduction bool `env:"PRODUCTION"`
Hosts []string `env:"HOSTS" envSeparator:":"`
Duration time.Duration `env:"DURATION"`
TempFolder string `env:"TEMP_FOLDER" envDefault:"${HOME}/tmp" envExpand:"true"`
}
func main() {
cfg := config{}
if err := env.Parse(&cfg); err != nil {
fmt.Printf("%+v\n", err)
}
fmt.Printf("%+v\n", cfg)
}
```
You can run it like this:
```sh
$ PRODUCTION=true HOSTS="host1:host2:host3" DURATION=1s go run main.go
{Home:/your/home Port:3000 IsProduction:true Hosts:[host1 host2 host3] Duration:1s}
```
⚠️⚠️⚠️ **Attention:** _unexported fields_ will be **ignored**.
## Supported types and defaults
Out of the box all built-in types are supported, plus a few others that
are commonly used.
Complete list:
- `string`
- `bool`
- `int`
- `int8`
- `int16`
- `int32`
- `int64`
- `uint`
- `uint8`
- `uint16`
- `uint32`
- `uint64`
- `float32`
- `float64`
- `string`
- `time.Duration`
- `encoding.TextUnmarshaler`
- `url.URL`
Pointers, slices and slices of pointers of those types are also supported.
You can also use/define a [custom parser func](#custom-parser-funcs) for any
other type you want.
If you set the `envDefault` tag for something, this value will be used in the
case of absence of it in the environment.
By default, slice types will split the environment value on `,`; you can change
this behavior by setting the `envSeparator` tag.
If you set the `envExpand` tag, environment variables (either in `${var}` or
`$var` format) in the string will be replaced according with the actual value
of the variable.
## Custom Parser Funcs
If you have a type that is not supported out of the box by the lib, you are able
to use (or define) and pass custom parsers (and their associated `reflect.Type`)
to the `env.ParseWithFuncs()` function.
In addition to accepting a struct pointer (same as `Parse()`), this function
also accepts a `map[reflect.Type]env.ParserFunc`.
`env` also ships with some pre-built custom parser funcs for common types. You
can check them out [here](parsers/).
If you add a custom parser for, say `Foo`, it will also be used to parse
`*Foo` and `[]Foo` types.
This directory contains pre-built, custom parsers that can be used with `env.ParseWithFuncs`
to facilitate the parsing of envs that are not basic types.
Check the example in the [go doc](http://godoc.org/github.com/caarlos0/env)
for more info.
### A note about `TextUnmarshaler` and `time.Time`
Env supports by default anything that implements the `TextUnmarshaler` interface.
That includes things like `time.Time` for example.
The upside is that depending on the format you need, you don't need to change anything.
The downside is that if you do need time in another format, you'll need to create your own type.
Its fairly straightforward:
```go
type MyTime time.Time
func (t *MyTime) UnmarshalText(text []byte) error {
tt, err := time.Parse("2006-01-02", string(text))
*t = MyTime(tt)
return err
}
type Config struct {
SomeTime MyTime `env:"SOME_TIME"`
}
```
And then you can parse `Config` with `env.Parse`.
## Required fields
The `env` tag option `required` (e.g., `env:"tagKey,required"`) can be added to ensure that some environment variable is set.
In the example above, an error is returned if the `config` struct is changed to:
```go
type config struct {
SecretKey string `env:"SECRET_KEY,required"`
}
```
## Not Empty fields
While `required` demands the environment variable to be check, it doesn't check its value.
If you want to make sure the environment is set and not empty, you need to use the `notEmpty` tag option instead (`env:"SOME_ENV,notEmpty"`).
Example:
```go
type config struct {
SecretKey string `env:"SECRET_KEY,notEmpty"`
}
```
## Unset environment variable after reading it
The `env` tag option `unset` (e.g., `env:"tagKey,unset"`) can be added
to ensure that some environment variable is unset after reading it.
Example:
```go
type config struct {
SecretKey string `env:"SECRET_KEY,unset"`
}
```
## From file
The `env` tag option `file` (e.g., `env:"tagKey,file"`) can be added
to in order to indicate that the value of the variable shall be loaded from a file. The path of that file is given
by the environment variable associated with it
Example below
```go
package main
import (
"fmt"
"time"
"github.com/caarlos0/env/v6"
)
type config struct {
Secret string `env:"SECRET,file"`
Password string `env:"PASSWORD,file" envDefault:"/tmp/password"`
Certificate string `env:"CERTIFICATE,file" envDefault:"${CERTIFICATE_FILE}" envExpand:"true"`
}
func main() {
cfg := config{}
if err := env.Parse(&cfg); err != nil {
fmt.Printf("%+v\n", err)
}
fmt.Printf("%+v\n", cfg)
}
```
```sh
$ echo qwerty > /tmp/secret
$ echo dvorak > /tmp/password
$ echo coleman > /tmp/certificate
$ SECRET=/tmp/secret \
CERTIFICATE_FILE=/tmp/certificate \
go run main.go
{Secret:qwerty Password:dvorak Certificate:coleman}
```
## Options
### Environment
By setting the `Options.Environment` map you can tell `Parse` to add those `keys` and `values`
as env vars before parsing is done. These envs are stored in the map and never actually set by `os.Setenv`.
This option effectively makes `env` ignore the OS environment variables: only the ones provided in the option are used.
This can make your testing scenarios a bit more clean and easy to handle.
```go
package main
import (
"fmt"
"log"
"github.com/caarlos0/env/v6"
)
type Config struct {
Password string `env:"PASSWORD"`
}
func main() {
cfg := &Config{}
opts := &env.Options{Environment: map[string]string{
"PASSWORD": "MY_PASSWORD",
}}
// Load env vars.
if err := env.Parse(cfg, opts); err != nil {
log.Fatal(err)
}
// Print the loaded data.
fmt.Printf("%+v\n", cfg.envData)
}
```
### Changing default tag name
You can change what tag name to use for setting the env vars by setting the `Options.TagName`
variable.
For example
```go
package main
import (
"fmt"
"log"
"github.com/caarlos0/env/v6"
)
type Config struct {
Password string `json:"PASSWORD"`
}
func main() {
cfg := &Config{}
opts := &env.Options{TagName: "json"}
// Load env vars.
if err := env.Parse(cfg, opts); err != nil {
log.Fatal(err)
}
// Print the loaded data.
fmt.Printf("%+v\n", cfg.envData)
}
```
### Prefixes
You can prefix sub-structs env tags, as well as a whole `env.Parse` call.
Here's an example flexing it a bit:
```go
package main
import (
"fmt"
"log"
"github.com/caarlos0/env/v6"
)
type Config struct {
Home string `env:"HOME"`
}
type ComplexConfig struct {
Foo Config `envPrefix:"FOO_"`
Clean Config
Bar Config `envPrefix:"BAR_"`
Blah string `env:"BLAH"`
}
func main() {
cfg := ComplexConfig{}
if err := Parse(&cfg, Options{
Prefix: "T_",
Environment: map[string]string{
"T_FOO_HOME": "/foo",
"T_BAR_HOME": "/bar",
"T_BLAH": "blahhh",
"T_HOME": "/clean",
},
}); err != nil {
log.Fatal(err)
}
// Load env vars.
if err := env.Parse(cfg, opts); err != nil {
log.Fatal(err)
}
// Print the loaded data.
fmt.Printf("%+v\n", cfg.envData)
}
```
### On set hooks
You might want to listen to value sets and, for example, log something or do some other kind of logic.
You can do this by passing a `OnSet` option:
```go
package main
import (
"fmt"
"log"
"github.com/caarlos0/env/v6"
)
type Config struct {
Username string `env:"USERNAME" envDefault:"admin"`
Password string `env:"PASSWORD"`
}
func main() {
cfg := &Config{}
opts := &env.Options{
OnSet: func(tag string, value interface{}, isDefault bool) {
fmt.Printf("Set %s to %v (default? %v)\n", tag, value, isDefault)
},
}
// Load env vars.
if err := env.Parse(cfg, opts); err != nil {
log.Fatal(err)
}
// Print the loaded data.
fmt.Printf("%+v\n", cfg.envData)
}
```
## Making all fields to required
You can make all fields that don't have a default value be required by setting the `RequiredIfNoDef: true` in the `Options`.
For example
```go
package main
import (
"fmt"
"log"
"github.com/caarlos0/env/v6"
)
type Config struct {
Username string `env:"USERNAME" envDefault:"admin"`
Password string `env:"PASSWORD"`
}
func main() {
cfg := &Config{}
opts := &env.Options{RequiredIfNoDef: true}
// Load env vars.
if err := env.Parse(cfg, opts); err != nil {
log.Fatal(err)
}
// Print the loaded data.
fmt.Printf("%+v\n", cfg.envData)
}
```
## Defaults from code
You may define default value also in code, by initialising the config data before it's filled by `env.Parse`.
Default values defined as struct tags will overwrite existing values during Parse.
```go
package main
import (
"fmt"
"log"
"github.com/caarlos0/env/v6"
)
type Config struct {
Username string `env:"USERNAME" envDefault:"admin"`
Password string `env:"PASSWORD"`
}
func main() {
var cfg = Config{
Username: "test",
Password: "123456",
}
if err := env.Parse(&cfg); err != nil {
fmt.Println("failed:", err)
}
fmt.Printf("%+v", cfg) // {Username:admin Password:123456}
}
```
## Stargazers over time
[![Stargazers over time](https://starchart.cc/caarlos0/env.svg)](https://starchart.cc/caarlos0/env)

477
vendor/github.com/caarlos0/env/v6/env.go generated vendored Normal file
View File

@ -0,0 +1,477 @@
package env
import (
"encoding"
"errors"
"fmt"
"net/url"
"os"
"reflect"
"strconv"
"strings"
"time"
)
// nolint: gochecknoglobals
var (
// ErrNotAStructPtr is returned if you pass something that is not a pointer to a
// Struct to Parse.
ErrNotAStructPtr = errors.New("env: expected a pointer to a Struct")
defaultBuiltInParsers = map[reflect.Kind]ParserFunc{
reflect.Bool: func(v string) (interface{}, error) {
return strconv.ParseBool(v)
},
reflect.String: func(v string) (interface{}, error) {
return v, nil
},
reflect.Int: func(v string) (interface{}, error) {
i, err := strconv.ParseInt(v, 10, 32)
return int(i), err
},
reflect.Int16: func(v string) (interface{}, error) {
i, err := strconv.ParseInt(v, 10, 16)
return int16(i), err
},
reflect.Int32: func(v string) (interface{}, error) {
i, err := strconv.ParseInt(v, 10, 32)
return int32(i), err
},
reflect.Int64: func(v string) (interface{}, error) {
return strconv.ParseInt(v, 10, 64)
},
reflect.Int8: func(v string) (interface{}, error) {
i, err := strconv.ParseInt(v, 10, 8)
return int8(i), err
},
reflect.Uint: func(v string) (interface{}, error) {
i, err := strconv.ParseUint(v, 10, 32)
return uint(i), err
},
reflect.Uint16: func(v string) (interface{}, error) {
i, err := strconv.ParseUint(v, 10, 16)
return uint16(i), err
},
reflect.Uint32: func(v string) (interface{}, error) {
i, err := strconv.ParseUint(v, 10, 32)
return uint32(i), err
},
reflect.Uint64: func(v string) (interface{}, error) {
i, err := strconv.ParseUint(v, 10, 64)
return i, err
},
reflect.Uint8: func(v string) (interface{}, error) {
i, err := strconv.ParseUint(v, 10, 8)
return uint8(i), err
},
reflect.Float64: func(v string) (interface{}, error) {
return strconv.ParseFloat(v, 64)
},
reflect.Float32: func(v string) (interface{}, error) {
f, err := strconv.ParseFloat(v, 32)
return float32(f), err
},
}
defaultTypeParsers = map[reflect.Type]ParserFunc{
reflect.TypeOf(url.URL{}): func(v string) (interface{}, error) {
u, err := url.Parse(v)
if err != nil {
return nil, fmt.Errorf("unable to parse URL: %v", err)
}
return *u, nil
},
reflect.TypeOf(time.Nanosecond): func(v string) (interface{}, error) {
s, err := time.ParseDuration(v)
if err != nil {
return nil, fmt.Errorf("unable to parse duration: %v", err)
}
return s, err
},
}
)
// ParserFunc defines the signature of a function that can be used within `CustomParsers`.
type ParserFunc func(v string) (interface{}, error)
// OnSetFn is a hook that can be run when a value is set.
type OnSetFn func(tag string, value interface{}, isDefault bool)
// Options for the parser.
type Options struct {
// Environment keys and values that will be accessible for the service.
Environment map[string]string
// TagName specifies another tagname to use rather than the default env.
TagName string
// RequiredIfNoDef automatically sets all env as required if they do not declare 'envDefault'
RequiredIfNoDef bool
// OnSet allows to run a function when a value is set
OnSet OnSetFn
// Prefix define a prefix for each key
Prefix string
// Sets to true if we have already configured once.
configured bool
}
// configure will do the basic configurations and defaults.
func configure(opts []Options) []Options {
// If we have already configured the first item
// of options will have been configured set to true.
if len(opts) > 0 && opts[0].configured {
return opts
}
// Created options with defaults.
opt := Options{
TagName: "env",
Environment: toMap(os.Environ()),
configured: true,
}
// Loop over all opts structs and set
// to opt if value is not default/empty.
for _, item := range opts {
if item.Environment != nil {
opt.Environment = item.Environment
}
if item.TagName != "" {
opt.TagName = item.TagName
}
if item.OnSet != nil {
opt.OnSet = item.OnSet
}
if item.Prefix != "" {
opt.Prefix = item.Prefix
}
opt.RequiredIfNoDef = item.RequiredIfNoDef
}
return []Options{opt}
}
func getOnSetFn(opts []Options) OnSetFn {
return opts[0].OnSet
}
// getTagName returns the tag name.
func getTagName(opts []Options) string {
return opts[0].TagName
}
// getEnvironment returns the environment map.
func getEnvironment(opts []Options) map[string]string {
return opts[0].Environment
}
// Parse parses a struct containing `env` tags and loads its values from
// environment variables.
func Parse(v interface{}, opts ...Options) error {
return ParseWithFuncs(v, map[reflect.Type]ParserFunc{}, opts...)
}
// ParseWithFuncs is the same as `Parse` except it also allows the user to pass
// in custom parsers.
func ParseWithFuncs(v interface{}, funcMap map[reflect.Type]ParserFunc, opts ...Options) error {
opts = configure(opts)
ptrRef := reflect.ValueOf(v)
if ptrRef.Kind() != reflect.Ptr {
return ErrNotAStructPtr
}
ref := ptrRef.Elem()
if ref.Kind() != reflect.Struct {
return ErrNotAStructPtr
}
parsers := defaultTypeParsers
for k, v := range funcMap {
parsers[k] = v
}
return doParse(ref, parsers, opts)
}
func doParse(ref reflect.Value, funcMap map[reflect.Type]ParserFunc, opts []Options) error {
refType := ref.Type()
for i := 0; i < refType.NumField(); i++ {
refField := ref.Field(i)
if !refField.CanSet() {
continue
}
if reflect.Ptr == refField.Kind() && !refField.IsNil() {
err := ParseWithFuncs(refField.Interface(), funcMap, opts...)
if err != nil {
return err
}
continue
}
if reflect.Struct == refField.Kind() && refField.CanAddr() && refField.Type().Name() == "" {
err := Parse(refField.Addr().Interface(), opts...)
if err != nil {
return err
}
continue
}
refTypeField := refType.Field(i)
value, err := get(refTypeField, opts)
if err != nil {
return err
}
if value == "" {
if reflect.Struct == refField.Kind() {
subOpts := make([]Options, len(opts))
copy(subOpts, opts)
if prefix := refType.Field(i).Tag.Get("envPrefix"); prefix != "" {
subOpts[0].Prefix += prefix
}
if err := doParse(refField, funcMap, subOpts); err != nil {
return err
}
}
continue
}
if err := set(refField, refTypeField, value, funcMap); err != nil {
return err
}
}
return nil
}
func get(field reflect.StructField, opts []Options) (val string, err error) {
var exists bool
var isDefault bool
var loadFile bool
var unset bool
var notEmpty bool
required := opts[0].RequiredIfNoDef
prefix := opts[0].Prefix
key, tags := parseKeyForOption(field.Tag.Get(getTagName(opts)))
key = prefix + key
for _, tag := range tags {
switch tag {
case "":
continue
case "file":
loadFile = true
case "required":
required = true
case "unset":
unset = true
case "notEmpty":
notEmpty = true
default:
return "", fmt.Errorf("env: tag option %q not supported", tag)
}
}
expand := strings.EqualFold(field.Tag.Get("envExpand"), "true")
defaultValue, defExists := field.Tag.Lookup("envDefault")
val, exists, isDefault = getOr(key, defaultValue, defExists, getEnvironment(opts))
if expand {
val = os.ExpandEnv(val)
}
if unset {
defer os.Unsetenv(key)
}
if required && !exists && len(key) > 0 {
return "", fmt.Errorf(`env: required environment variable %q is not set`, key)
}
if notEmpty && val == "" {
return "", fmt.Errorf("env: environment variable %q should not be empty", key)
}
if loadFile && val != "" {
filename := val
val, err = getFromFile(filename)
if err != nil {
return "", fmt.Errorf(`env: could not load content of file "%s" from variable %s: %v`, filename, key, err)
}
}
if onSetFn := getOnSetFn(opts); onSetFn != nil {
onSetFn(key, val, isDefault)
}
return val, err
}
// split the env tag's key into the expected key and desired option, if any.
func parseKeyForOption(key string) (string, []string) {
opts := strings.Split(key, ",")
return opts[0], opts[1:]
}
func getFromFile(filename string) (value string, err error) {
b, err := os.ReadFile(filename)
return string(b), err
}
func getOr(key, defaultValue string, defExists bool, envs map[string]string) (string, bool, bool) {
value, exists := envs[key]
switch {
case (!exists || key == "") && defExists:
return defaultValue, true, true
case !exists:
return "", false, false
}
return value, true, false
}
func set(field reflect.Value, sf reflect.StructField, value string, funcMap map[reflect.Type]ParserFunc) error {
if tm := asTextUnmarshaler(field); tm != nil {
if err := tm.UnmarshalText([]byte(value)); err != nil {
return newParseError(sf, err)
}
return nil
}
typee := sf.Type
fieldee := field
if typee.Kind() == reflect.Ptr {
typee = typee.Elem()
fieldee = field.Elem()
}
parserFunc, ok := funcMap[typee]
if ok {
val, err := parserFunc(value)
if err != nil {
return newParseError(sf, err)
}
fieldee.Set(reflect.ValueOf(val))
return nil
}
parserFunc, ok = defaultBuiltInParsers[typee.Kind()]
if ok {
val, err := parserFunc(value)
if err != nil {
return newParseError(sf, err)
}
fieldee.Set(reflect.ValueOf(val).Convert(typee))
return nil
}
if field.Kind() == reflect.Slice {
return handleSlice(field, value, sf, funcMap)
}
return newNoParserError(sf)
}
func handleSlice(field reflect.Value, value string, sf reflect.StructField, funcMap map[reflect.Type]ParserFunc) error {
separator := sf.Tag.Get("envSeparator")
if separator == "" {
separator = ","
}
parts := strings.Split(value, separator)
typee := sf.Type.Elem()
if typee.Kind() == reflect.Ptr {
typee = typee.Elem()
}
if _, ok := reflect.New(typee).Interface().(encoding.TextUnmarshaler); ok {
return parseTextUnmarshalers(field, parts, sf)
}
parserFunc, ok := funcMap[typee]
if !ok {
parserFunc, ok = defaultBuiltInParsers[typee.Kind()]
if !ok {
return newNoParserError(sf)
}
}
result := reflect.MakeSlice(sf.Type, 0, len(parts))
for _, part := range parts {
r, err := parserFunc(part)
if err != nil {
return newParseError(sf, err)
}
v := reflect.ValueOf(r).Convert(typee)
if sf.Type.Elem().Kind() == reflect.Ptr {
v = reflect.New(typee)
v.Elem().Set(reflect.ValueOf(r).Convert(typee))
}
result = reflect.Append(result, v)
}
field.Set(result)
return nil
}
func asTextUnmarshaler(field reflect.Value) encoding.TextUnmarshaler {
if reflect.Ptr == field.Kind() {
if field.IsNil() {
field.Set(reflect.New(field.Type().Elem()))
}
} else if field.CanAddr() {
field = field.Addr()
}
tm, ok := field.Interface().(encoding.TextUnmarshaler)
if !ok {
return nil
}
return tm
}
func parseTextUnmarshalers(field reflect.Value, data []string, sf reflect.StructField) error {
s := len(data)
elemType := field.Type().Elem()
slice := reflect.MakeSlice(reflect.SliceOf(elemType), s, s)
for i, v := range data {
sv := slice.Index(i)
kind := sv.Kind()
if kind == reflect.Ptr {
sv = reflect.New(elemType.Elem())
} else {
sv = sv.Addr()
}
tm := sv.Interface().(encoding.TextUnmarshaler)
if err := tm.UnmarshalText([]byte(v)); err != nil {
return newParseError(sf, err)
}
if kind == reflect.Ptr {
slice.Index(i).Set(sv)
}
}
field.Set(slice)
return nil
}
func newParseError(sf reflect.StructField, err error) error {
if err == nil {
return nil
}
return parseError{
sf: sf,
err: err,
}
}
type parseError struct {
sf reflect.StructField
err error
}
func (e parseError) Error() string {
return fmt.Sprintf(`env: parse error on field "%s" of type "%s": %v`, e.sf.Name, e.sf.Type, e.err)
}
func newNoParserError(sf reflect.StructField) error {
return fmt.Errorf(`env: no parser found for field "%s" of type "%s"`, sf.Name, sf.Type)
}

1477
vendor/github.com/caarlos0/env/v6/env_test.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

15
vendor/github.com/caarlos0/env/v6/env_unix.go generated vendored Normal file
View File

@ -0,0 +1,15 @@
//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
// +build darwin dragonfly freebsd linux netbsd openbsd solaris
package env
import "strings"
func toMap(env []string) map[string]string {
r := map[string]string{}
for _, e := range env {
p := strings.SplitN(e, "=", 2)
r[p[0]] = p[1]
}
return r
}

25
vendor/github.com/caarlos0/env/v6/env_windows.go generated vendored Normal file
View File

@ -0,0 +1,25 @@
package env
import "strings"
func toMap(env []string) map[string]string {
r := map[string]string{}
for _, e := range env {
p := strings.SplitN(e, "=", 2)
// On Windows, environment variables can start with '='. If so, Split at next character.
// See env_windows.go in the Go source: https://github.com/golang/go/blob/master/src/syscall/env_windows.go#L58
prefixEqualSign := false
if len(e) > 0 && e[0] == '=' {
e = e[1:]
prefixEqualSign = true
}
p = strings.SplitN(e, "=", 2)
if prefixEqualSign {
p[0] = "=" + p[0]
}
r[p[0]] = p[1]
}
return r
}

20
vendor/github.com/caarlos0/env/v6/env_windows_test.go generated vendored Normal file
View File

@ -0,0 +1,20 @@
package env
import (
"testing"
"github.com/matryer/is"
)
// On Windows, environment variables can start with '='. This test verifies this behavior without relying on a Windows environment.
// See env_windows.go in the Go source: https://github.com/golang/go/blob/master/src/syscall/env_windows.go#L58
func TestToMapWindows(t *testing.T) {
is := is.New(t)
envVars := []string{"=::=::\\", "=C:=C:\\test", "VAR=REGULARVAR"}
result := toMap(envVars)
is.Equal(map[string]string{
"=::": "::\\",
"=C:": "C:\\test",
"VAR": "REGULARVAR",
}, result)
}

5
vendor/github.com/caarlos0/env/v6/go.mod generated vendored Normal file
View File

@ -0,0 +1,5 @@
module github.com/caarlos0/env/v6
require github.com/matryer/is v1.4.0
go 1.17

2
vendor/github.com/caarlos0/env/v6/go.sum generated vendored Normal file
View File

@ -0,0 +1,2 @@
github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE=
github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=