diff --git a/.github/workflows/common.yaml b/.github/workflows/common.yaml
index f33bc748db..6dc04165b5 100644
--- a/.github/workflows/common.yaml
+++ b/.github/workflows/common.yaml
@@ -136,17 +136,11 @@ jobs:
yml: ./codecov.yml
fail_ci_if_error: true
func-tests-badger:
- runs-on: self-hosted
+ runs-on: ubuntu-latest
name: func-tests-badger
env:
- GOPATH: ${{github.workspace}}/go
+ GOPATH: /home/runner/work/insolar/insolar/go
steps:
- - name: cleanup
- run: |
- docker rm -f $(docker ps -aq) || sleep 1
- docker rmi -f $(docker images -aq) || sleep 1
- docker volume rm -f $(docker volume ls -q) || sleep 1
- sudo rm -rf $GITHUB_WORKSPACE/*
- name: checkout code
uses: actions/checkout@master
with:
@@ -176,17 +170,11 @@ jobs:
name: logs-badger
path: logs-badger.tar.gz
func-tests-pgsql:
- runs-on: self-hosted
+ runs-on: ubuntu-latest
name: func-tests-pgsql
env:
- GOPATH: ${{github.workspace}}/go
+ GOPATH: /home/runner/work/insolar/insolar/go
steps:
- - name: cleanup
- run: |
- docker rm -f $(docker ps -aq) || sleep 1
- docker rmi -f $(docker images -aq) || sleep 1
- docker volume rm -f $(docker volume ls -q) || sleep 1
- sudo rm -rf $GITHUB_WORKSPACE/*
- name: checkout code
uses: actions/checkout@master
with:
diff --git a/Makefile b/Makefile
index acfbb64f38..8ef4962ef6 100644
--- a/Makefile
+++ b/Makefile
@@ -171,8 +171,6 @@ test_unit: ## run all unit tests
.PHONY: functest
functest: ## run functest FUNCTEST_COUNT times
CGO_ENABLED=1 $(GOTEST) -test.v $(TEST_ARGS) -tags "functest bloattest" ./application/functest -count=$(FUNCTEST_COUNT)
- sleep 10 # workaround for a "bind: address already in use" problem
- CGO_ENABLED=1 $(GOTEST) -test.v $(TEST_ARGS) -tags "functest bloattest" ./applicationbase/functest -count=$(FUNCTEST_COUNT)
.PNONY: functest_race
functest_race: ## run functest 10 times with -race flag
diff --git a/README.md b/README.md
index 3303eb2833..2d90b850cc 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-[](http://insolar.io/?utm_source=Github)
+[](http://insolar.io/?utm_source=Github)
Insolar platform is the most secure, scalable, and comprehensive business-ready blockchain toolkit in the world. Insolar’s goal is to give businesses access to features and services that enable them to launch new decentralized applications quickly and easily. Whether a minimum viable product or full-scale production software, Insolar builds and integrates applications for your enterprise's existing systems.
@@ -12,9 +12,7 @@ Insolar platform is the most secure, scalable, and comprehensive business-ready
To learn what distinguishes Insolar from other blockchain projects, go through the [list of our features](https://insolar.io/platform?utm_source=Github).
-To get a grip on how Insolar works, take a look at its [architecture overview](https://docs.insolar.io/en/latest/architecture.html#architecture).
-
-To join the Insolar network, download the [latest release](https://github.com/insolar/insolar/releases) and follow the [integration instructions](https://docs.insolar.io/en/latest/integration.html).
+To get a grip on how Insolar works, take a look at the [big picture](https://docs.insolar.io/en/latest/basics.html) and explore the [architecture](https://docs.insolar.io/en/latest/architecture.html).
To test Insolar locally, install it and deploy as described below.
@@ -85,14 +83,14 @@ If you have any additional questions, join our [developers chat](https://t.me/In
Our social media:
-[](https://facebook.com/insolario)
-[](https://twitter.com/insolario)
-[](https://medium.com/insolar)
-[](https://youtube.com/insolar)
-[](https://www.reddit.com/r/insolar/)
-[](https://www.linkedin.com/company/insolario/)
-[](https://instagram.com/insolario)
-[](https://t.me/InsolarAnnouncements)
+[](https://facebook.com/insolario)
+[](https://twitter.com/insolario)
+[](https://medium.com/insolar)
+[](https://youtube.com/insolar)
+[](https://www.reddit.com/r/insolar/)
+[](https://www.linkedin.com/company/insolario/)
+[](https://instagram.com/insolario)
+[](https://t.me/InsolarAnnouncements)
# License
diff --git a/application/cmd/insolar/create_default_configs.go b/application/cmd/insolar/create_default_configs.go
index 240a5a829e..56e59264ef 100644
--- a/application/cmd/insolar/create_default_configs.go
+++ b/application/cmd/insolar/create_default_configs.go
@@ -48,7 +48,7 @@ func writeBootstrapConfig(outputDir string) {
}
func writeNodeConfig(outputDir string) {
- cfg := configuration.NewConfiguration()
+ cfg := configuration.NewGenericConfiguration()
raw, err := yaml.Marshal(cfg)
if err != nil {
panic(err)
diff --git a/cmd/insolard/genesis.go b/cmd/insolard/genesis.go
index b254e889dc..7c8cb2ad4f 100644
--- a/cmd/insolard/genesis.go
+++ b/cmd/insolard/genesis.go
@@ -11,17 +11,17 @@ import (
"io/ioutil"
"time"
+ "github.com/pkg/errors"
+
"github.com/insolar/insolar/application"
"github.com/insolar/insolar/application/appfoundation"
"github.com/insolar/insolar/application/genesisrefs"
"github.com/insolar/insolar/application/genesisrefs/contracts"
"github.com/insolar/insolar/applicationbase/genesis"
- "github.com/insolar/insolar/configuration"
"github.com/insolar/insolar/insolar"
"github.com/insolar/insolar/log"
"github.com/insolar/insolar/logicrunner/builtin/foundation"
"github.com/insolar/insolar/pulse"
- "github.com/pkg/errors"
)
const (
@@ -43,18 +43,7 @@ const (
FoundationVestingStep = 0
)
-func initStates(configPath, genesisConfigPath string) ([]genesis.ContractState, error) {
- cfgHolder := configuration.NewHolder()
- var err error
- if len(configPath) != 0 {
- err = cfgHolder.LoadFromFile(configPath)
- } else {
- err = cfgHolder.Load()
- }
- if err != nil {
- log.Fatalf("failed to load configuration: %v", err.Error())
- }
-
+func initStates(genesisConfigPath string) ([]genesis.ContractState, error) {
b, err := ioutil.ReadFile(genesisConfigPath)
if err != nil {
log.Fatalf("failed to load genesis configuration from file: %v", genesisConfigPath)
diff --git a/cmd/insolard/main.go b/cmd/insolard/main.go
index 222d0b8107..9a56befe3b 100644
--- a/cmd/insolard/main.go
+++ b/cmd/insolard/main.go
@@ -10,55 +10,138 @@ import (
"io/ioutil"
"path/filepath"
- "github.com/insolar/insolar/application"
- appbuiltin "github.com/insolar/insolar/application/builtin"
- "github.com/insolar/insolar/applicationbase/genesis"
- "github.com/insolar/insolar/logicrunner/builtin"
"github.com/pkg/errors"
"github.com/spf13/cobra"
jww "github.com/spf13/jwalterweatherman"
+ "github.com/insolar/insolar/application"
+ appbuiltin "github.com/insolar/insolar/application/builtin"
+ "github.com/insolar/insolar/applicationbase/genesis"
"github.com/insolar/insolar/certificate"
"github.com/insolar/insolar/configuration"
"github.com/insolar/insolar/insolar"
"github.com/insolar/insolar/log"
+ "github.com/insolar/insolar/logicrunner/builtin"
"github.com/insolar/insolar/server"
- "github.com/insolar/insolar/version"
)
func main() {
var (
configPath string
genesisConfigPath string
+ heavyDB string
genesisOnly bool
)
+ var cmdHeavy = &cobra.Command{
+ Use: "heavy --config=path --heavy-genesis=path",
+ Short: "starts heavy node",
+ Run: func(cmd *cobra.Command, args []string) {
+ runHeavyNode(configPath, genesisConfigPath, heavyDB, genesisOnly)
+ },
+ }
+ cmdHeavy.Flags().StringVarP(&genesisConfigPath, "heavy-genesis", "", "", "path to genesis config for heavy node")
+ if err := cmdHeavy.MarkFlagRequired("heavy-genesis"); err != nil {
+ log.Fatal("MarkFlagRequired failed:", err)
+ }
+ cmdHeavy.Flags().StringVarP(&heavyDB, "database", "", "", "sets database type for heavy node, available badger/postgres")
+ if err := cmdHeavy.MarkFlagRequired("database"); err != nil {
+ log.Fatal("MarkFlagRequired failed:", err)
+ }
+ cmdHeavy.Flags().BoolVarP(&genesisOnly, "genesis-only", "", false, "run only genesis and then terminate")
+
+ var cmdLight = &cobra.Command{
+ Use: "light --config=path",
+ Short: "starts light node",
+ Run: func(cmd *cobra.Command, args []string) {
+ runLightNode(configPath)
+ },
+ }
+
+ var cmdVirtual = &cobra.Command{
+ Use: "virtual --config=path",
+ Short: "starts virtual node",
+ Run: func(cmd *cobra.Command, args []string) {
+ runVirtualNode(configPath)
+ },
+ }
+
var rootCmd = &cobra.Command{
Use: "insolard",
- Run: func(_ *cobra.Command, _ []string) {
- runInsolardServer(configPath, genesisConfigPath, genesisOnly)
- },
}
- rootCmd.Flags().StringVarP(&configPath, "config", "c", "", "path to config file")
- rootCmd.Flags().StringVarP(&genesisConfigPath, "heavy-genesis", "", "", "path to genesis config for heavy node")
- rootCmd.Flags().BoolVarP(&genesisOnly, "genesis-only", "", false, "run only genesis and then terminate")
- rootCmd.AddCommand(version.GetCommand("insolard"))
+ rootCmd.PersistentFlags().StringVarP(&configPath, "config", "c", "", "path to config file")
+ if err := rootCmd.MarkPersistentFlagRequired("config"); err != nil {
+ log.Fatal("MarkFlagRequired failed:", err)
+ }
+ rootCmd.AddCommand(cmdHeavy, cmdLight, cmdVirtual)
err := rootCmd.Execute()
if err != nil {
log.Fatal("insolard execution failed:", err)
}
}
-// psAgentLauncher is a stub for gops agent launcher (available with 'debug' build tag)
-var psAgentLauncher = func() error { return nil }
+func runHeavyNode(configPath string, genesisConfigPath string, db string, genesisOnly bool) {
+ var holder configuration.ConfigHolder
+ var err error
+
+ switch db {
+ case configuration.DbTypeBadger:
+ holder, err = readHeavyBadgerConfig(configPath)
+ case configuration.DbTypePg:
+ holder, err = readHeavyPgConfig(configPath)
+ default:
+ log.Fatal("db type is not supported")
+ }
+ if err != nil {
+ log.Fatal(errors.Wrap(err, "failed to load configuration"))
+ }
+
+ role, err := readRole(holder)
+ if err != nil {
+ log.Fatal(errors.Wrap(err, "readRole failed"))
+ }
+ if role != insolar.StaticRoleHeavyMaterial {
+ log.Fatal(errors.Wrap(err, "role in cert is not heavy"))
+ }
+
+ if err := psAgentLauncher(); err != nil {
+ log.Warnf("Failed to launch gops agent: %s", err)
+ }
+
+ apiOptions, err := initAPIOptions()
+ if err != nil {
+ log.Fatal(errors.Wrap(err, "failed to get API info response"))
+ }
+
+ states, _ := initStates(genesisConfigPath)
+ s := server.NewHeavyServer(
+ holder,
+ genesisConfigPath,
+ genesis.Options{
+ States: states,
+ ParentDomain: application.GenesisNameRootDomain,
+ },
+ genesisOnly,
+ apiOptions,
+ )
+ s.Serve()
+}
-func runInsolardServer(configPath string, genesisConfigPath string, genesisOnly bool) {
+func runVirtualNode(configPath string) {
jww.SetStdoutThreshold(jww.LevelDebug)
- role, err := readRole(configPath)
+ holder, err := readVirtualConfig(configPath)
+ if err != nil {
+ log.Fatal(errors.Wrap(err, "failed to load configuration"))
+ }
+
+ role, err := readRole(holder)
if err != nil {
log.Fatal(errors.Wrap(err, "readRole failed"))
}
+ if role != insolar.StaticRoleVirtual {
+ log.Fatal(errors.Wrap(err, "role in cert is not virtual executor"))
+ }
if err := psAgentLauncher(); err != nil {
log.Warnf("Failed to launch gops agent: %s", err)
@@ -69,60 +152,91 @@ func runInsolardServer(configPath string, genesisConfigPath string, genesisOnly
log.Fatal(errors.Wrap(err, "failed to get API info response"))
}
- switch role {
- case insolar.StaticRoleHeavyMaterial:
- states, _ := initStates(configPath, genesisConfigPath)
- s := server.NewHeavyServer(
- configPath,
- genesisConfigPath,
- genesis.Options{
- States: states,
- ParentDomain: application.GenesisNameRootDomain,
- },
- genesisOnly,
- apiOptions,
- )
- s.Serve()
- case insolar.StaticRoleLightMaterial:
- s := server.NewLightServer(
- configPath,
- apiOptions,
- )
- s.Serve()
- case insolar.StaticRoleVirtual:
- builtinContracts := builtin.BuiltinContracts{
- CodeRegistry: appbuiltin.InitializeContractMethods(),
- CodeRefRegistry: appbuiltin.InitializeCodeRefs(),
- CodeDescriptors: appbuiltin.InitializeCodeDescriptors(),
- PrototypeDescriptors: appbuiltin.InitializePrototypeDescriptors(),
- }
- s := server.NewVirtualServer(
- configPath,
- builtinContracts,
- apiOptions,
- )
- s.Serve()
+ builtinContracts := builtin.BuiltinContracts{
+ CodeRegistry: appbuiltin.InitializeContractMethods(),
+ CodeRefRegistry: appbuiltin.InitializeCodeRefs(),
+ CodeDescriptors: appbuiltin.InitializeCodeDescriptors(),
+ PrototypeDescriptors: appbuiltin.InitializePrototypeDescriptors(),
}
+ s := server.NewVirtualServer(holder, builtinContracts, apiOptions)
+ s.Serve()
}
-func readRole(path string) (insolar.StaticRole, error) {
- var err error
- cfg := configuration.NewHolder()
- if len(path) != 0 {
- err = cfg.LoadFromFile(path)
- } else {
- err = cfg.Load()
+func runLightNode(configPath string) {
+ jww.SetStdoutThreshold(jww.LevelDebug)
+
+ holder, err := readLightConfig(configPath)
+ if err != nil {
+ log.Fatal(errors.Wrap(err, "failed to load configuration"))
}
+
+ role, err := readRole(holder)
if err != nil {
- return insolar.StaticRoleUnknown, errors.Wrap(err, "failed to load configuration from file")
+ log.Fatal(errors.Wrap(err, "readRole failed"))
+ }
+ if role != insolar.StaticRoleLightMaterial {
+ log.Fatal(errors.Wrap(err, "role in cert is not light material"))
}
- data, err := ioutil.ReadFile(filepath.Clean(cfg.Configuration.CertificatePath))
+ apiOptions, err := initAPIOptions()
+ if err != nil {
+ log.Fatal(errors.Wrap(err, "failed to get API info response"))
+ }
+
+ if err := psAgentLauncher(); err != nil {
+ log.Warnf("Failed to launch gops agent: %s", err)
+ }
+
+ s := server.NewLightServer(holder, apiOptions)
+ s.Serve()
+}
+
+// psAgentLauncher is a stub for gops agent launcher (available with 'debug' build tag)
+var psAgentLauncher = func() error { return nil }
+
+func readHeavyBadgerConfig(path string) (*configuration.HeavyBadgerHolder, error) {
+ cfg := configuration.NewHeavyBadgerHolder(path)
+ err := cfg.Load()
+ if err != nil {
+ return nil, errors.Wrap(err, "failed to load configuration")
+ }
+ return cfg, nil
+}
+
+func readHeavyPgConfig(path string) (*configuration.HeavyPgHolder, error) {
+ cfg := configuration.NewHeavyPgHolder(path)
+ err := cfg.Load()
+ if err != nil {
+ return nil, errors.Wrap(err, "failed to load configuration")
+ }
+ return cfg, nil
+}
+
+func readLightConfig(path string) (*configuration.LightHolder, error) {
+ cfg := configuration.NewLightHolder(path)
+ err := cfg.Load()
+ if err != nil {
+ return nil, errors.Wrap(err, "failed to load configuration")
+ }
+ return cfg, nil
+}
+
+func readVirtualConfig(path string) (*configuration.VirtualHolder, error) {
+ cfg := configuration.NewVirtualHolder(path)
+ err := cfg.Load()
+ if err != nil {
+ return nil, errors.Wrap(err, "failed to load configuration")
+ }
+ return cfg, nil
+}
+
+func readRole(holder configuration.ConfigHolder) (insolar.StaticRole, error) {
+ data, err := ioutil.ReadFile(filepath.Clean(holder.GetGenericConfig().CertificatePath))
if err != nil {
return insolar.StaticRoleUnknown, errors.Wrapf(
err,
"failed to read certificate from: %s",
- cfg.Configuration.CertificatePath,
+ holder.GetGenericConfig().CertificatePath,
)
}
cert := certificate.AuthorizationCertificate{}
diff --git a/configuration/configuration.go b/configuration/configuration.go
index c96de04318..38e4ecd526 100644
--- a/configuration/configuration.go
+++ b/configuration/configuration.go
@@ -7,22 +7,18 @@ package configuration
import (
"fmt"
- "path/filepath"
- "reflect"
- "strings"
- "github.com/spf13/viper"
- yaml "gopkg.in/yaml.v2"
+ "gopkg.in/yaml.v2"
)
-// Configuration contains configuration params for all Insolar components
-type Configuration struct {
+const InsolarEnvPrefix string = "insolar"
+
+// GenericConfiguration contains configuration params for all Insolar components
+type GenericConfiguration struct {
Host HostNetwork
Service ServiceNetwork
- Ledger Ledger
Log Log
Metrics Metrics
- LogicRunner LogicRunner
APIRunner APIRunner
AdminAPIRunner APIRunner
AvailabilityChecker AvailabilityChecker
@@ -30,8 +26,25 @@ type Configuration struct {
CertificatePath string
Tracer Tracer
Introspection Introspection
- Exporter Exporter
Bus Bus
+
+ // LightChainLimit is maximum pulse difference (NOT number of pulses)
+ // between current and the latest replicated on heavy.
+ //
+ // IMPORTANT: It should be the same on ALL nodes.
+ LightChainLimit int
+}
+
+func (c GenericConfiguration) GetConfig() interface{} {
+ return &c
+}
+
+// Holds GenericConfiguration + node specific config
+type ConfigHolder interface {
+ // Returns Generic Config struct
+ GetGenericConfig() GenericConfiguration
+ // Returns Node specific config struct
+ GetNodeConfig() interface{}
}
// PulsarConfiguration contains configuration params for the pulsar node
@@ -43,21 +56,13 @@ type PulsarConfiguration struct {
Metrics Metrics
}
-// Holder provides methods to manage configuration
-type Holder struct {
- Configuration Configuration
- viper *viper.Viper
-}
-
-// NewConfiguration creates new default configuration
-func NewConfiguration() Configuration {
- cfg := Configuration{
+// NewGenericConfiguration creates new default configuration
+func NewGenericConfiguration() GenericConfiguration {
+ cfg := GenericConfiguration{
Host: NewHostNetwork(),
Service: NewServiceNetwork(),
- Ledger: NewLedger(),
Log: NewLog(),
Metrics: NewMetrics(),
- LogicRunner: NewLogicRunner(),
APIRunner: NewAPIRunner(false),
AdminAPIRunner: NewAPIRunner(true),
AvailabilityChecker: NewAvailabilityChecker(),
@@ -65,8 +70,8 @@ func NewConfiguration() Configuration {
CertificatePath: "",
Tracer: NewTracer(),
Introspection: NewIntrospection(),
- Exporter: NewExporter(),
Bus: NewBus(),
+ LightChainLimit: 5, // 5 pulses
}
return cfg
@@ -83,136 +88,12 @@ func NewPulsarConfiguration() PulsarConfiguration {
}
}
-// MustInit wrapper around Init function which panics on error.
-func (h *Holder) MustInit(required bool) *Holder {
- _, err := h.Init(required)
- if err != nil {
- panic(err)
- }
- return h
-}
-
-// Init init all configuration data from config file and environment.
-//
-// Does not fail on not found config file if the 'required' flag set to false.
-func (h *Holder) Init(required bool) (*Holder, error) {
- err := h.Load()
- if err != nil {
- if required {
- return nil, err
- }
- if _, ok := err.(viper.ConfigFileNotFoundError); !ok {
- return nil, err
- }
- // read env vars if config file is not required and viper failed to load it.
- h.viper.AutomaticEnv()
- if err = h.viper.Unmarshal(&h.Configuration); err != nil {
- return nil, err
- }
- }
- return h, nil
-}
-
-func (h *Holder) registerDefaultValue(val reflect.Value, parts ...string) {
- variablePath := strings.ToLower(strings.Join(parts, "."))
-
- h.viper.SetDefault(variablePath, val.Interface())
-}
-
-func (h *Holder) registerDifferentValue(val reflect.Value, parts ...string) {
- variablePath := strings.Join(parts, ".")
- previousValue := h.viper.Get(variablePath)
-
- if !reflect.DeepEqual(previousValue, val.Interface()) {
- h.viper.Set(variablePath, val.Interface())
- }
-}
-
-func (h *Holder) recurseCallInLeaf(cb func(reflect.Value, ...string), iface interface{}, parts ...string) {
- fldV := reflect.ValueOf(iface)
- fldT := reflect.TypeOf(iface)
-
- for fldPos := 0; fldPos < fldV.NumField(); fldPos++ {
- fldName, fldValue := fldT.Field(fldPos).Name, fldV.Field(fldPos)
-
- path := append(parts, fldName)
-
- switch fldValue.Kind() {
- case reflect.Struct:
- h.recurseCallInLeaf(cb, fldValue.Interface(), path...)
- default:
- cb(fldValue, path...)
- }
- }
-}
-
-// NewHolder creates new Holder with default configuration
-func NewHolder() *Holder {
- cfg := NewConfiguration()
- holder := &Holder{Configuration: cfg, viper: viper.New()}
-
- holder.viper.SetConfigName(".insolar")
- holder.viper.AddConfigPath(".")
- holder.viper.SetConfigType("yml")
-
- return holder.defaults()
-}
-
-// NewHolderWithFilePaths creates new holder with possible configuration files paths.
-func NewHolderWithFilePaths(files ...string) *Holder {
- cfg := NewConfiguration()
- holder := &Holder{Configuration: cfg, viper: viper.New()}
-
- holder.viper.SetConfigType("yml")
- for _, f := range files {
- dir, file := filepath.Split(f)
- if len(dir) == 0 {
- dir = "."
- }
- file = file[:len(file)-len(filepath.Ext(file))]
-
- holder.viper.AddConfigPath(dir)
- holder.viper.SetConfigName(file)
- }
-
- return holder.defaults()
-}
-
-func (h *Holder) defaults() *Holder {
- h.recurseCallInLeaf(h.registerDefaultValue, h.Configuration)
-
- h.viper.AutomaticEnv()
- h.viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
- h.viper.SetEnvPrefix("insolar")
- return h
-}
-
-// Load method reads configuration from default file path
-func (h *Holder) Load() error {
- err := h.viper.ReadInConfig()
- if err != nil {
- return err
- }
-
- return h.viper.Unmarshal(&h.Configuration)
-}
-
-// LoadFromFile method reads configuration from particular file path
-func (h *Holder) LoadFromFile(path string) error {
- h.viper.SetConfigFile(path)
- return h.Load()
-}
-
-// Save method writes configuration to default file path
-func (h *Holder) Save() error {
- h.recurseCallInLeaf(h.registerDifferentValue, h.Configuration)
- return h.viper.WriteConfig()
+type stringPathGetter struct {
+ Path string
}
-// SaveAs method writes configuration to particular file path
-func (h *Holder) SaveAs(path string) error {
- h.recurseCallInLeaf(h.registerDifferentValue, h.Configuration)
- return h.viper.WriteConfigAs(path)
+func (g *stringPathGetter) GetConfigPath() string {
+ return g.Path
}
// ToString converts any configuration struct to yaml string
diff --git a/configuration/configuration_heavy.go b/configuration/configuration_heavy.go
new file mode 100644
index 0000000000..9d52fd0d17
--- /dev/null
+++ b/configuration/configuration_heavy.go
@@ -0,0 +1,130 @@
+// Copyright 2020 Insolar Network Ltd.
+// All rights reserved.
+// This material is licensed under the Insolar License version 1.0,
+// available at https://github.com/insolar/insolar/blob/master/LICENSE.md.
+
+package configuration
+
+import (
+ "github.com/insolar/insconfig"
+)
+
+const DbTypeBadger = "badger"
+const DbTypePg = "postgres"
+
+// HeavyBadgerConfig contains configuration params for HeavyBadger
+type HeavyBadgerConfig struct {
+ GenericConfiguration `mapstructure:",squash" yaml:",inline"`
+ DatabaseType string
+ Ledger Ledger
+ Exporter Exporter
+}
+
+// ConfigHeavyPg contains configuration params for HeavyPg
+type ConfigHeavyPg struct {
+ GenericConfiguration `mapstructure:",squash" yaml:",inline"`
+ DatabaseType string
+ Ledger LedgerPg
+ Exporter Exporter
+}
+
+// NewHeavyBadgerConfig creates new default configuration
+func NewHeavyBadgerConfig() HeavyBadgerConfig {
+ return HeavyBadgerConfig{
+ DatabaseType: DbTypeBadger,
+ Ledger: NewLedger(),
+ Exporter: NewExporter(),
+ GenericConfiguration: NewGenericConfiguration(),
+ }
+}
+
+// NewHeavyPgConfig creates new default configuration
+func NewHeavyPgConfig() ConfigHeavyPg {
+ cfg := ConfigHeavyPg{
+ DatabaseType: DbTypePg,
+ Ledger: NewLedgerPg(),
+ Exporter: NewExporter(),
+ GenericConfiguration: NewGenericConfiguration(),
+ }
+ return cfg
+}
+
+// HeavyBadgerHolder provides methods to manage heavy configuration
+type HeavyBadgerHolder struct {
+ Configuration *HeavyBadgerConfig
+ Params insconfig.Params
+}
+
+func (h *HeavyBadgerHolder) GetGenericConfig() GenericConfiguration {
+ return h.Configuration.GenericConfiguration
+}
+func (h *HeavyBadgerHolder) GetNodeConfig() interface{} {
+ return h.Configuration
+}
+
+// MustLoad wrapper around Load function which panics on error.
+func (h *HeavyBadgerHolder) MustLoad() *HeavyBadgerHolder {
+ err := h.Load()
+ if err != nil {
+ panic(err)
+ }
+ return h
+}
+
+// NewHeavyBadgerHolder creates new HeavyBadgerHolder with config path
+func NewHeavyBadgerHolder(path string) *HeavyBadgerHolder {
+ params := insconfig.Params{
+ EnvPrefix: InsolarEnvPrefix,
+ ConfigPathGetter: &stringPathGetter{Path: path},
+ }
+ return &HeavyBadgerHolder{Configuration: &HeavyBadgerConfig{}, Params: params}
+}
+
+// Load method reads configuration from params file path
+func (h *HeavyBadgerHolder) Load() error {
+ insConfigurator := insconfig.New(h.Params)
+ if err := insConfigurator.Load(h.Configuration); err != nil {
+ return err
+ }
+ return nil
+}
+
+// HeavyPgHolder provides methods to manage heavy configuration
+type HeavyPgHolder struct {
+ Configuration *ConfigHeavyPg
+ Params insconfig.Params
+}
+
+func (h *HeavyPgHolder) GetGenericConfig() GenericConfiguration {
+ return h.Configuration.GenericConfiguration
+}
+func (h *HeavyPgHolder) GetNodeConfig() interface{} {
+ return h.Configuration
+}
+
+// MustLoad wrapper around Load function which panics on error.
+func (h *HeavyPgHolder) MustLoad() *HeavyPgHolder {
+ err := h.Load()
+ if err != nil {
+ panic(err)
+ }
+ return h
+}
+
+// NewHeavyPgHolder creates new HeavyPgHolder with config path
+func NewHeavyPgHolder(path string) *HeavyPgHolder {
+ params := insconfig.Params{
+ EnvPrefix: InsolarEnvPrefix,
+ ConfigPathGetter: &stringPathGetter{Path: path},
+ }
+ return &HeavyPgHolder{Configuration: &ConfigHeavyPg{}, Params: params}
+}
+
+// Load method reads configuration from params file path
+func (h *HeavyPgHolder) Load() error {
+ insConfigurator := insconfig.New(h.Params)
+ if err := insConfigurator.Load(h.Configuration); err != nil {
+ return err
+ }
+ return nil
+}
diff --git a/configuration/configuration_light.go b/configuration/configuration_light.go
new file mode 100644
index 0000000000..0d44ad88f9
--- /dev/null
+++ b/configuration/configuration_light.go
@@ -0,0 +1,64 @@
+// Copyright 2020 Insolar Network Ltd.
+// All rights reserved.
+// This material is licensed under the Insolar License version 1.0,
+// available at https://github.com/insolar/insolar/blob/master/LICENSE.md.
+
+package configuration
+
+import (
+ "github.com/insolar/insconfig"
+)
+
+// LightConfig contains configuration params for Light
+type LightConfig struct {
+ GenericConfiguration `mapstructure:",squash" yaml:",inline"`
+ Ledger LedgerLight
+}
+
+// NewLightConfig creates new default
+func NewLightConfig() LightConfig {
+ return LightConfig{
+ Ledger: NewLedgerLight(),
+ GenericConfiguration: NewGenericConfiguration(),
+ }
+}
+
+// LightHolder provides methods to manage light configuration
+type LightHolder struct {
+ Configuration *LightConfig
+ Params insconfig.Params
+}
+
+func (h *LightHolder) GetGenericConfig() GenericConfiguration {
+ return h.Configuration.GenericConfiguration
+}
+func (h *LightHolder) GetNodeConfig() interface{} {
+ return h.Configuration
+}
+
+// NewLightHolder creates new LightHolder with config path
+func NewLightHolder(path string) *LightHolder {
+ params := insconfig.Params{
+ EnvPrefix: InsolarEnvPrefix,
+ ConfigPathGetter: &stringPathGetter{Path: path},
+ }
+ return &LightHolder{Configuration: &LightConfig{}, Params: params}
+}
+
+// Load method reads configuration from params file path
+func (h *LightHolder) Load() error {
+ insConfigurator := insconfig.New(h.Params)
+ if err := insConfigurator.Load(h.Configuration); err != nil {
+ return err
+ }
+ return nil
+}
+
+// MustLoad wrapper around Load function which panics on error.
+func (h *LightHolder) MustLoad() *LightHolder {
+ err := h.Load()
+ if err != nil {
+ panic(err)
+ }
+ return h
+}
diff --git a/configuration/configuration_test.go b/configuration/configuration_test.go
index fe03f56f0e..fcc74c8baf 100644
--- a/configuration/configuration_test.go
+++ b/configuration/configuration_test.go
@@ -7,124 +7,80 @@ package configuration
import (
"fmt"
- "io/ioutil"
"os"
- "path"
"strings"
"testing"
- "github.com/spf13/viper"
"github.com/stretchr/testify/require"
)
func TestConfiguration_Load_Default(t *testing.T) {
- holder := NewHolder()
- err := holder.LoadFromFile("testdata/default.yml")
+ holder := NewLightHolder("testdata/insolard-light.yaml")
+ err := holder.Load()
require.NoError(t, err)
- cfg := NewConfiguration()
- require.Equal(t, cfg, holder.Configuration)
+ cfg := NewLightConfig()
+ t.Log(ToString(cfg))
+ require.Equal(t, cfg, *holder.Configuration)
}
-func TestConfiguration_Load_Changed(t *testing.T) {
- holder := NewHolder()
- err := holder.LoadFromFile("testdata/changed.yml")
+func TestConfiguration_DoubleLoad(t *testing.T) {
+ holder := NewLightHolder("testdata/insolard-light.yaml")
+ err := holder.Load()
require.NoError(t, err)
- cfg := NewConfiguration()
- require.NotEqual(t, cfg, holder.Configuration)
-
- cfg.Log.Level = "Debug"
- require.Equal(t, cfg, holder.Configuration)
-}
-
-func TestConfiguration_Save_Default(t *testing.T) {
- dir, err := ioutil.TempDir("", "")
- require.NoError(t, err)
- defer os.RemoveAll(dir)
-
- newConfigurationPath := path.Join(dir, "insolar.yml")
-
- holder := NewHolder()
- holder.Configuration.Host.Transport.FixedPublicAddress = "192.168.1.1"
- err = holder.SaveAs(newConfigurationPath)
- require.NoError(t, err)
-
- holder2 := NewHolder()
- err = holder2.LoadFromFile(newConfigurationPath)
+ holder2 := NewLightHolder("testdata/insolard-light.yaml")
+ err = holder2.Load()
require.NoError(t, err)
-
- require.Nil(t, holder2.viper.Get("insolar"))
- require.Equal(t, holder.Configuration, holder2.Configuration)
+ require.Equal(t, holder2.Configuration, holder.Configuration)
}
func TestConfiguration_Load_Invalid(t *testing.T) {
- holder := NewHolder()
- err := holder.LoadFromFile("testdata/invalid.yml")
+ holder := NewLightHolder("testdata/invalid.yaml")
+ err := holder.Load()
require.Error(t, err)
}
func TestConfiguration_LoadEnv(t *testing.T) {
- holder := NewHolder()
+ holder := NewLightHolder("testdata/insolard-light.yaml")
require.NoError(t, os.Setenv("INSOLAR_HOST_TRANSPORT_ADDRESS", "127.0.0.2:5555"))
- err := holder.LoadFromFile("testdata/default.yml")
+ err := holder.Load()
require.NoError(t, err)
require.NoError(t, os.Unsetenv("INSOLAR_HOST_TRANSPORT_ADDRESS"))
require.NoError(t, err)
require.Equal(t, "127.0.0.2:5555", holder.Configuration.Host.Transport.Address)
- defaultCfg := NewConfiguration()
+ defaultCfg := NewLightConfig()
require.Equal(t, "127.0.0.1:0", defaultCfg.Host.Transport.Address)
}
-func TestConfiguration_Init(t *testing.T) {
- var (
- holder *Holder
- err error
- )
- holder, err = NewHolder().Init(false)
- require.NoError(t, err)
- require.NotNil(t, holder)
+func TestConfiguration_Load_EmptyPath(t *testing.T) {
+ holder := NewLightHolder("")
+ err := holder.Load()
+ require.Error(t, err)
- holder = NewHolder().MustInit(false)
- require.NotNil(t, holder)
+ require.Panics(t, func() { NewLightHolder("").MustLoad() })
+}
- holder, err = NewHolder().Init(true)
- require.Error(t, err)
- require.IsType(t, viper.ConfigFileNotFoundError{}, err)
- require.Nil(t, holder)
+func TestConfiguration_Load_ENVOverridesEmpty(t *testing.T) {
+ _ = os.Setenv("INSOLAR_HOST_TRANSPORT_ADDRESS", "127.0.0.2:5555")
+ defer os.Unsetenv("INSOLAR_HOST_TRANSPORT_ADDRESS")
+ holder := NewLightHolder("testdata/insolard-light-empty.yaml")
+ err := holder.Load()
+ require.NoError(t, err)
- require.Panics(t, func() { NewHolder().MustInit(true) })
+ require.Equal(t, "127.0.0.2:5555", holder.Configuration.Host.Transport.Address)
}
-func TestConfiguration_WithFilePaths(t *testing.T) {
- okCases := [][]string{
- {"testdata/changed.yml"},
- {"testdata/default.yml"},
- {"testdata/changed.yml", "testdata/default.yml"},
- {"testdata/changed.yml", "testdata/changed.yml"},
- {"testdata/default.yml", "testdata/default.yml"},
- {"notexists", "notexists.yaml", "testdata/default.yml", "testdata/default.yml"},
- }
- for _, tCase := range okCases {
- holder, err := NewHolderWithFilePaths(tCase...).Init(true)
- require.NoErrorf(t, err, "case: %#v", tCase)
- require.NotNil(t, holder)
- }
+func TestNewVirtualHolder_LoadDefault(t *testing.T) {
+ holder := NewVirtualHolder("testdata/insolard-virtual.yaml")
+ err := holder.Load()
+ require.NoError(t, err)
- failCases := [][]string{
- {"testdata/invalid.yml"},
- {"nonexists"},
- {"notexists", "notexists"},
- {"testdata/default.yml", "testdata/invalid.yml"},
- }
- for _, tCase := range failCases {
- holder, err := NewHolderWithFilePaths(tCase...).Init(true)
- require.Errorf(t, err, "case: %#v", tCase)
- require.Nil(t, holder)
- }
+ cfg := NewVirtualConfig()
+ require.Equal(t, cfg, *holder.Configuration)
}
func TestMain(m *testing.M) {
@@ -144,7 +100,7 @@ func TestMain(m *testing.M) {
}
// run tests
- m.Run()
+ exitCode := m.Run()
// restore back variables
for varName, varValue := range variablesBackup {
@@ -154,4 +110,5 @@ func TestMain(m *testing.M) {
}
}
+ os.Exit(exitCode)
}
diff --git a/configuration/configuration_virtual.go b/configuration/configuration_virtual.go
new file mode 100644
index 0000000000..6582e5d351
--- /dev/null
+++ b/configuration/configuration_virtual.go
@@ -0,0 +1,59 @@
+// Copyright 2020 Insolar Network Ltd.
+// All rights reserved.
+// This material is licensed under the Insolar License version 1.0,
+// available at https://github.com/insolar/insolar/blob/master/LICENSE.md.
+
+package configuration
+
+import (
+ "github.com/insolar/insconfig"
+)
+
+// VirtualConfig contains configuration params for Virtual node
+type VirtualConfig struct {
+ GenericConfiguration `mapstructure:",squash" yaml:",inline"`
+ LogicRunner LogicRunner
+}
+
+func (c VirtualConfig) GetConfig() interface{} {
+ return &c
+}
+
+// NewVirtualConfig creates new default configuration
+func NewVirtualConfig() VirtualConfig {
+ return VirtualConfig{
+ LogicRunner: NewLogicRunner(),
+ GenericConfiguration: NewGenericConfiguration(),
+ }
+}
+
+// VirtualHolder provides methods to manage virtual node configuration
+type VirtualHolder struct {
+ Configuration *VirtualConfig
+ Params insconfig.Params
+}
+
+func (h *VirtualHolder) GetGenericConfig() GenericConfiguration {
+ return h.Configuration.GenericConfiguration
+}
+func (h *VirtualHolder) GetNodeConfig() interface{} {
+ return h.Configuration
+}
+
+// NewVirtualHolder creates new VirtualHolder with config path
+func NewVirtualHolder(path string) *VirtualHolder {
+ params := insconfig.Params{
+ EnvPrefix: InsolarEnvPrefix,
+ ConfigPathGetter: &stringPathGetter{Path: path},
+ }
+ return &VirtualHolder{Configuration: &VirtualConfig{}, Params: params}
+}
+
+// Load method reads configuration from params file path
+func (h *VirtualHolder) Load() error {
+ insConfigurator := insconfig.New(h.Params)
+ if err := insConfigurator.Load(h.Configuration); err != nil {
+ return err
+ }
+ return nil
+}
diff --git a/configuration/doc.go b/configuration/doc.go
index c9ccb35717..c8cfc2d715 100644
--- a/configuration/doc.go
+++ b/configuration/doc.go
@@ -17,8 +17,8 @@ Usage:
)
func main() {
- holder := configuration.NewHolder()
- fmt.Printf("Default configuration:\n %+v\n", holder.Configuration)
+ holder := configuration.LightHolder()
+ fmt.Printf("Default configuration:\n %+v\n", holder.VirtualConfig)
holder.SaveAs("insolar.yml")
}
diff --git a/configuration/ledger.go b/configuration/ledger.go
index fea35aee43..0b40eb8ddc 100644
--- a/configuration/ledger.go
+++ b/configuration/ledger.go
@@ -17,55 +17,14 @@ type Storage struct {
GCRunFrequency uint
}
-type PostgreSQL struct {
- URL string // postgresql:// connection string
- MigrationPath string // path to the directory with migration scripts
-}
-
-// JetSplit holds configuration for jet split.
-type JetSplit struct {
- // RecordsCountThreshold is a drop threshold in records to perform split for jet.
- ThresholdRecordsCount int
- // ThresholdOverflowCount is a how many times in row ThresholdRecordsCount should be surpassed.
- ThresholdOverflowCount int
- // DepthLimit limits jet tree depth (maximum possible jets = 2^DepthLimit)
- DepthLimit uint8
-}
-
// Ledger holds configuration for ledger.
type Ledger struct {
// Storage defines storage configuration.
Storage Storage
- // PostgreSQL defines configuration related to PostgreSQL.
- PostgreSQL PostgreSQL
-
- // JetSplit holds jet split configuration.
- JetSplit JetSplit
-
// common/sharable values:
-
- // LightChainLimit is maximum pulse difference (NOT number of pulses)
- // between current and the latest replicated on heavy.
- //
- // IMPORTANT: It should be the same on ALL nodes.
- LightChainLimit int
-
// Backup holds configuration of BackupMaker
Backup Backup
-
- // CleanerDelay holds value of pulses, that should happen before end of LightChainLimit and start
- // of LME's data cleaning
- CleanerDelay int
-
- // MaxNotificationsPerPulse holds the limit for abandoned requests notifications limit
- MaxNotificationsPerPulse uint
-
- // FilamentCacheLimit holds the limit for cache items for an object
- FilamentCacheLimit int
-
- // IsPostgresBase indicates that heavy uses Postgres as a database
- IsPostgresBase bool
}
// Backup holds configuration for backuping.
@@ -118,14 +77,6 @@ func NewLedger() Ledger {
GCRunFrequency: 1,
},
- JetSplit: JetSplit{
- // TODO: find best default values
- ThresholdRecordsCount: 100,
- ThresholdOverflowCount: 3,
- DepthLimit: 5, // limit to 32 jets
- },
- LightChainLimit: 5, // 5 pulses
-
Backup: Backup{
Enabled: false,
DirNameTemplate: "pulse-%d",
@@ -134,10 +85,5 @@ func NewLedger() Ledger {
BackupFile: "incr.bkp",
ConfirmFile: "BACKUPED",
},
-
- CleanerDelay: 3, // 3 pulses
- MaxNotificationsPerPulse: 100, // 100 objects
- FilamentCacheLimit: 3000, // 3000 records for every object
- IsPostgresBase: false,
}
}
diff --git a/configuration/ledger_light.go b/configuration/ledger_light.go
new file mode 100644
index 0000000000..2aeaa9cedc
--- /dev/null
+++ b/configuration/ledger_light.go
@@ -0,0 +1,48 @@
+// Copyright 2020 Insolar Network Ltd.
+// All rights reserved.
+// This material is licensed under the Insolar License version 1.0,
+// available at https://github.com/insolar/insolar/blob/master/LICENSE.md.
+
+package configuration
+
+// Ledger holds configuration for ledger.
+type LedgerLight struct {
+ // JetSplit holds jet split configuration.
+ JetSplit JetSplit
+
+ // CleanerDelay holds value of pulses, that should happen before end of LightChainLimit and start
+ // of LME's data cleaning
+ CleanerDelay int
+
+ // MaxNotificationsPerPulse holds the limit for abandoned requests notifications limit
+ MaxNotificationsPerPulse uint
+
+ // FilamentCacheLimit holds the limit for cache items for an object
+ FilamentCacheLimit int
+}
+
+// JetSplit holds configuration for jet split.
+type JetSplit struct {
+ // RecordsCountThreshold is a drop threshold in records to perform split for jet.
+ ThresholdRecordsCount int
+ // ThresholdOverflowCount is a how many times in row ThresholdRecordsCount should be surpassed.
+ ThresholdOverflowCount int
+ // DepthLimit limits jet tree depth (maximum possible jets = 2^DepthLimit)
+ DepthLimit uint8
+}
+
+// NewLedger creates new default Ledger configuration.
+func NewLedgerLight() LedgerLight {
+ return LedgerLight{
+ JetSplit: JetSplit{
+ // TODO: find best default values
+ ThresholdRecordsCount: 100,
+ ThresholdOverflowCount: 3,
+ DepthLimit: 5, // limit to 32 jets
+ },
+
+ CleanerDelay: 3, // 3 pulses
+ MaxNotificationsPerPulse: 100, // 100 objects
+ FilamentCacheLimit: 3000, // 3000 records for every object
+ }
+}
diff --git a/configuration/ledger_pg.go b/configuration/ledger_pg.go
new file mode 100644
index 0000000000..355cce41dd
--- /dev/null
+++ b/configuration/ledger_pg.go
@@ -0,0 +1,27 @@
+// Copyright 2020 Insolar Network Ltd.
+// All rights reserved.
+// This material is licensed under the Insolar License version 1.0,
+// available at https://github.com/insolar/insolar/blob/master/LICENSE.md.
+
+package configuration
+
+type PostgreSQL struct {
+ URL string // postgresql:// connection string
+ MigrationPath string // path to the directory with migration scripts
+}
+
+// Ledger holds configuration for ledger.
+type LedgerPg struct {
+ // PostgreSQL defines configuration related to PostgreSQL.
+ PostgreSQL PostgreSQL
+}
+
+// NewLedger creates new default Ledger configuration.
+func NewLedgerPg() LedgerPg {
+ return LedgerPg{
+ PostgreSQL: PostgreSQL{
+ URL: "postgres://postgres@localhost/postgres?sslmode=disable",
+ MigrationPath: "migrations",
+ },
+ }
+}
diff --git a/configuration/testdata/changed.yml b/configuration/testdata/changed.yml
index 3e45d8a6d9..f8afa04eba 100644
--- a/configuration/testdata/changed.yml
+++ b/configuration/testdata/changed.yml
@@ -2,14 +2,85 @@ host:
transport:
protocol: TCP
address: 127.0.0.1:0
- behindnat: false
- bootstraphosts: []
- isrelay: false
-node:
- nodes: []
+ fixedpublicaddress: ""
+ mintimeout: 10
+ maxtimeout: 2000
+ timeoutmult: 2
+ signmessages: false
+ handshakesessionttl: 5000
+service:
+ cachedirectory: network_cache
+ledger:
+ storage:
+ datadirectory: ./data
+ badgervalueloggcdiscardratio: 0.4
+ gcrunfrequency: 1
+ jetsplit:
+ thresholdrecordscount: 100
+ thresholdoverflowcount: 3
+ depthlimit: 5
+ lightchainlimit: 5
+ backup:
+ enabled: false
+ tmpdirectory: ""
+ targetdirectory: ""
+ metainfofile: meta.json
+ confirmfile: BACKUPED
+ backupfile: incr.bkp
+ dirnametemplate: pulse-%d
+ backupwaitperiod: 60
+ postprocessbackupcmd: []
+ cleanerdelay: 3
+ maxnotificationsperpulse: 100
+ filamentcachelimit: 3000
log:
- format: ""
level: Debug
- output: insolar.log
-stats:
- listenaddress: 0.0.0.0:8080
+ adapter: zerolog
+ formatter: json
+ outputtype: stderr
+ outputparallellimit: ""
+ outputparams: ""
+ buffersize: 0
+ llbuffersize: 0
+metrics:
+ listenaddress: 0.0.0.0:9091
+ namespace: insolar
+ zpagesenabled: true
+ reportingperiod: 0s
+logicrunner:
+ rpclisten: 127.0.0.1:7778
+ rpcprotocol: tcp
+ builtin: true
+ goplugin:
+ runnerlisten: 127.0.0.1:7777
+ runnerprotocol: tcp
+ pulselrusize: 100
+apirunner:
+ address: localhost:19101
+ rpc: /api/rpc
+ isadmin: false
+ swaggerpath: application/api/spec/api-exported.yaml
+adminapirunner:
+ address: localhost:19001
+ rpc: /admin-api/rpc
+ isadmin: true
+ swaggerpath: application/api/spec/api-exported.yaml
+availabilitychecker:
+ enabled: true
+ keeperurl: ""
+ requesttimeout: 15
+ checkperiod: 5
+keyspath: ./
+certificatepath: ""
+tracer:
+ jaeger:
+ collectorendpoint: ""
+ agentendpoint: ""
+ probabilityrate: 1
+ samplingrules: {}
+introspection:
+ addr: ""
+exporter:
+ addr: :5678
+bus:
+ replytimeout: 15s
diff --git a/configuration/testdata/default.yml b/configuration/testdata/default.yml
index 5dcee0b05a..ee0aee7d7b 100644
--- a/configuration/testdata/default.yml
+++ b/configuration/testdata/default.yml
@@ -2,55 +2,80 @@ host:
transport:
protocol: TCP
address: 127.0.0.1:0
- behindnat: false
- bootstraphosts: []
- isrelay: false
- infinitybootstrap: false
- timeout: 4
+ fixedpublicaddress: ""
+ mintimeout: 10
+ maxtimeout: 2000
+ timeoutmult: 2
signmessages: false
+ handshakesessionttl: 5000
service:
- service: {}
+ cachedirectory: network_cache
ledger:
storage:
datadirectory: ./data
- txretriesonconflict: 3
- jetcoordinator:
- rolecounts:
- 1: 1
- 2: 1
- 3: 1
- 4: 1
- 5: 1
+ badgervalueloggcdiscardratio: 0.4
+ gcrunfrequency: 1
+ jetsplit:
+ thresholdrecordscount: 100
+ thresholdoverflowcount: 3
+ depthlimit: 5
+ backup:
+ enabled: false
+ tmpdirectory: ""
+ targetdirectory: ""
+ metainfofile: meta.json
+ confirmfile: BACKUPED
+ backupfile: incr.bkp
+ dirnametemplate: pulse-%d
+ backupwaitperiod: 60
+ postprocessbackupcmd: []
+ cleanerdelay: 3
+ maxnotificationsperpulse: 100
+ filamentcachelimit: 3000
+ ispostgresbase: false
log:
level: Info
adapter: zerolog
+ formatter: json
+ outputtype: stderr
+ outputparallellimit: ""
+ outputparams: ""
+ buffersize: 0
+ llbuffersize: 0
metrics:
listenaddress: 0.0.0.0:9091
+ namespace: insolar
+ zpagesenabled: true
+ reportingperiod: 0s
logicrunner:
+ pulselrusize: 100
apirunner:
- port: 19191
- location: /api/v1
-pulsar:
- pulsetime: 10000
- receivingsigntimeout: 1000
- receivingnumbertimeout: 1000
- receivingvectortimeout: 1000
- receivingsignsforchosentimeout: 0
- neighbours: []
- numberdelta: 10
- distributiontransport:
- protocol: TCP
- address: 0.0.0.0:18091
- behindnat: false
- pulsedistributor:
- bootstraphosts:
- - localhost:53837
-bootstrap:
- rootkeys: ""
- rootbalance: 0
-privatekey: |-
- -----BEGIN PRIVATE KEY-----
- MHcCAQEEID6XJHMb2aiaK1bp2GHHw0r4LrzZZ4exlcmx8GrjGsMFoAoGCCqGSM49
- AwEHoUQDQgAE7DE4ArqxIYbY/UAyLLFBGuFu2gROPaqp4vxbEeie7mnZeqsYexmN
- BkrXBEFO5LF4diHC7OJ3xsfebvI0moQRLw==
- -----END PRIVATE KEY-----
+ address: localhost:19101
+ rpc: /api/rpc
+ isadmin: false
+ swaggerpath: application/api/spec/api-exported.yaml
+adminapirunner:
+ address: localhost:19001
+ rpc: /admin-api/rpc
+ isadmin: true
+ swaggerpath: application/api/spec/api-exported.yaml
+availabilitychecker:
+ enabled: true
+ keeperurl: ""
+ requesttimeout: 15
+ checkperiod: 5
+keyspath: ./
+certificatepath: ""
+tracer:
+ jaeger:
+ collectorendpoint: ""
+ agentendpoint: ""
+ probabilityrate: 1
+ samplingrules: {}
+introspection:
+ addr: ""
+exporter:
+ addr: :5678
+bus:
+ replytimeout: 15s
+lightchainlimit: 5
diff --git a/configuration/testdata/insolard-heavy-badger.yaml b/configuration/testdata/insolard-heavy-badger.yaml
new file mode 100644
index 0000000000..44ad705127
--- /dev/null
+++ b/configuration/testdata/insolard-heavy-badger.yaml
@@ -0,0 +1,72 @@
+host:
+ transport:
+ protocol: TCP
+ address: 127.0.0.1:13831
+ fixedpublicaddress: ""
+ mintimeout: 10
+ maxtimeout: 2000
+ timeoutmult: 2
+ signmessages: false
+ handshakesessionttl: 5000
+service:
+ cachedirectory: network_cache
+databasetype: badger
+ledger:
+ storage:
+ datadirectory: .artifacts/launchnet/discoverynodes/1/data
+ badgervalueloggcdiscardratio: 0.4
+ gcrunfrequency: 1
+ backup:
+ enabled: false
+ tmpdirectory: ""
+ targetdirectory: ""
+ metainfofile: meta.json
+ confirmfile: BACKUPED
+ backupfile: incr.bkp
+ dirnametemplate: pulse-%d
+ backupwaitperiod: 60
+ postprocessbackupcmd: []
+log:
+ level: Debug
+ adapter: zerolog
+ formatter: json
+ outputtype: stderr
+ outputparallellimit: ""
+ outputparams: ""
+ buffersize: 0
+ llbuffersize: 0
+metrics:
+ listenaddress: 127.0.0.1:8001
+ namespace: insolar
+ zpagesenabled: false
+ reportingperiod: 0s
+apirunner:
+ address: 127.0.0.1:19101
+ rpc: /api/rpc
+ isadmin: false
+ swaggerpath: application/api/spec/api-exported.yaml
+adminapirunner:
+ address: 127.0.0.1:19001
+ rpc: /admin-api/rpc
+ isadmin: true
+ swaggerpath: application/api/spec/api-exported.yaml
+availabilitychecker:
+ enabled: true
+ keeperurl: http://127.0.0.1:12012/check
+ requesttimeout: 15
+ checkperiod: 5
+keyspath: .artifacts/launchnet/reusekeys/discovery//node_01.json
+certificatepath: .artifacts/launchnet/discoverynodes/certs/discovery_cert_1.json
+tracer:
+ jaeger:
+ collectorendpoint: ""
+ agentendpoint: ""
+ probabilityrate: 1
+ samplingrules: {}
+introspection:
+ addr: 127.0.0.1:55501
+exporter:
+ addr: :5678
+bus:
+ replytimeout: 15s
+lightchainlimit: 5
diff --git a/configuration/testdata/insolard-heavy-pg.yaml b/configuration/testdata/insolard-heavy-pg.yaml
new file mode 100644
index 0000000000..812f1abd73
--- /dev/null
+++ b/configuration/testdata/insolard-heavy-pg.yaml
@@ -0,0 +1,61 @@
+host:
+ transport:
+ protocol: TCP
+ address: 127.0.0.1:13831
+ fixedpublicaddress: ""
+ mintimeout: 10
+ maxtimeout: 2000
+ timeoutmult: 2
+ signmessages: false
+ handshakesessionttl: 5000
+service:
+ cachedirectory: network_cache
+databasetype: badger
+ledger:
+ postgresql:
+ url: postgres://postgres@localhost/postgres?sslmode=disable
+ migrationpath: migration
+log:
+ level: Debug
+ adapter: zerolog
+ formatter: json
+ outputtype: stderr
+ outputparallellimit: ""
+ outputparams: ""
+ buffersize: 0
+ llbuffersize: 0
+metrics:
+ listenaddress: 127.0.0.1:8001
+ namespace: insolar
+ zpagesenabled: false
+ reportingperiod: 0s
+apirunner:
+ address: 127.0.0.1:19101
+ rpc: /api/rpc
+ isadmin: false
+ swaggerpath: application/api/spec/api-exported.yaml
+adminapirunner:
+ address: 127.0.0.1:19001
+ rpc: /admin-api/rpc
+ isadmin: true
+ swaggerpath: application/api/spec/api-exported.yaml
+availabilitychecker:
+ enabled: true
+ keeperurl: http://127.0.0.1:12012/check
+ requesttimeout: 15
+ checkperiod: 5
+keyspath: .artifacts/launchnet/reusekeys/discovery//node_01.json
+certificatepath: .artifacts/launchnet/discoverynodes/certs/discovery_cert_1.json
+tracer:
+ jaeger:
+ collectorendpoint: ""
+ agentendpoint: ""
+ probabilityrate: 1
+ samplingrules: {}
+introspection:
+ addr: 127.0.0.1:55501
+exporter:
+ addr: :5678
+bus:
+ replytimeout: 15s
+lightchainlimit: 5
diff --git a/configuration/testdata/insolard-light-empty.yaml b/configuration/testdata/insolard-light-empty.yaml
new file mode 100644
index 0000000000..23d0a540ac
--- /dev/null
+++ b/configuration/testdata/insolard-light-empty.yaml
@@ -0,0 +1,61 @@
+host:
+ transport:
+ protocol: TCP
+ fixedpublicaddress: ""
+ mintimeout: 10
+ maxtimeout: 2000
+ timeoutmult: 2
+ signmessages: false
+ handshakesessionttl: 5000
+service:
+ cachedirectory: network_cache
+log:
+ level: Info
+ adapter: zerolog
+ formatter: json
+ outputtype: stderr
+ outputparallellimit: ""
+ outputparams: ""
+ buffersize: 0
+ llbuffersize: 0
+metrics:
+ listenaddress: 0.0.0.0:9091
+ namespace: insolar
+ zpagesenabled: true
+ reportingperiod: 0s
+apirunner:
+ address: localhost:19101
+ rpc: /api/rpc
+ isadmin: false
+ swaggerpath: application/api/spec/api-exported.yaml
+adminapirunner:
+ address: localhost:19001
+ rpc: /admin-api/rpc
+ isadmin: true
+ swaggerpath: application/api/spec/api-exported.yaml
+availabilitychecker:
+ enabled: true
+ keeperurl: ""
+ requesttimeout: 15
+ checkperiod: 5
+keyspath: ./
+certificatepath: ""
+tracer:
+ jaeger:
+ collectorendpoint: ""
+ agentendpoint: ""
+ probabilityrate: 1
+ samplingrules: {}
+introspection:
+ addr: ""
+bus:
+ replytimeout: 15s
+lightchainlimit: 5
+ledger:
+ jetsplit:
+ thresholdrecordscount: 100
+ thresholdoverflowcount: 3
+ depthlimit: 5
+ cleanerdelay: 3
+ maxnotificationsperpulse: 100
+ filamentcachelimit: 3000
diff --git a/configuration/testdata/insolard-light.yaml b/configuration/testdata/insolard-light.yaml
new file mode 100644
index 0000000000..6a3780bb25
--- /dev/null
+++ b/configuration/testdata/insolard-light.yaml
@@ -0,0 +1,62 @@
+host:
+ transport:
+ protocol: TCP
+ address: 127.0.0.1:0
+ fixedpublicaddress: ""
+ mintimeout: 10
+ maxtimeout: 2000
+ timeoutmult: 2
+ signmessages: false
+ handshakesessionttl: 5000
+service:
+ cachedirectory: network_cache
+log:
+ level: Info
+ adapter: zerolog
+ formatter: json
+ outputtype: stderr
+ outputparallellimit: ""
+ outputparams: ""
+ buffersize: 0
+ llbuffersize: 0
+metrics:
+ listenaddress: 0.0.0.0:9091
+ namespace: insolar
+ zpagesenabled: true
+ reportingperiod: 0s
+apirunner:
+ address: localhost:19101
+ rpc: /api/rpc
+ isadmin: false
+ swaggerpath: application/api/spec/api-exported.yaml
+adminapirunner:
+ address: localhost:19001
+ rpc: /admin-api/rpc
+ isadmin: true
+ swaggerpath: application/api/spec/api-exported.yaml
+availabilitychecker:
+ enabled: true
+ keeperurl: ""
+ requesttimeout: 15
+ checkperiod: 5
+keyspath: ./
+certificatepath: ""
+tracer:
+ jaeger:
+ collectorendpoint: ""
+ agentendpoint: ""
+ probabilityrate: 1
+ samplingrules: {}
+introspection:
+ addr: ""
+bus:
+ replytimeout: 15s
+lightchainlimit: 5
+ledger:
+ jetsplit:
+ thresholdrecordscount: 100
+ thresholdoverflowcount: 3
+ depthlimit: 5
+ cleanerdelay: 3
+ maxnotificationsperpulse: 100
+ filamentcachelimit: 3000
diff --git a/configuration/testdata/insolard-virtual.yaml b/configuration/testdata/insolard-virtual.yaml
new file mode 100644
index 0000000000..4dfdd8291c
--- /dev/null
+++ b/configuration/testdata/insolard-virtual.yaml
@@ -0,0 +1,62 @@
+host:
+ transport:
+ protocol: TCP
+ address: 127.0.0.1:0
+ fixedpublicaddress: ""
+ mintimeout: 10
+ maxtimeout: 2000
+ timeoutmult: 2
+ signmessages: false
+ handshakesessionttl: 5000
+service:
+ cachedirectory: network_cache
+log:
+ level: Info
+ adapter: zerolog
+ formatter: json
+ outputtype: stderr
+ outputparallellimit: ""
+ outputparams: ""
+ buffersize: 0
+ llbuffersize: 0
+metrics:
+ listenaddress: 0.0.0.0:9091
+ namespace: insolar
+ zpagesenabled: true
+ reportingperiod: 0s
+apirunner:
+ address: localhost:19101
+ rpc: /api/rpc
+ isadmin: false
+ swaggerpath: application/api/spec/api-exported.yaml
+adminapirunner:
+ address: localhost:19001
+ rpc: /admin-api/rpc
+ isadmin: true
+ swaggerpath: application/api/spec/api-exported.yaml
+availabilitychecker:
+ enabled: true
+ keeperurl: ""
+ requesttimeout: 15
+ checkperiod: 5
+keyspath: ./
+certificatepath: ""
+tracer:
+ jaeger:
+ collectorendpoint: ""
+ agentendpoint: ""
+ probabilityrate: 1
+ samplingrules: {}
+introspection:
+ addr: ""
+bus:
+ replytimeout: 15s
+lightchainlimit: 5
+logicrunner:
+ rpclisten: 127.0.0.1:7778
+ rpcprotocol: tcp
+ builtin: true
+ goplugin:
+ runnerlisten: 127.0.0.1:7777
+ runnerprotocol: tcp
+ pulselrusize: 100
diff --git a/go.mod b/go.mod
index 47d84d123d..c833363ef3 100644
--- a/go.mod
+++ b/go.mod
@@ -12,7 +12,6 @@ require (
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f // indirect
github.com/dgraph-io/badger v1.6.0-rc1.0.20191024172150-efb9d9d15d7f
github.com/dustin/go-humanize v1.0.0
- github.com/fortytw2/leaktest v1.3.0 // indirect
github.com/fsnotify/fsnotify v1.4.7
github.com/getkin/kin-openapi v0.2.1-0.20191211203508-0d9caf80ada6
github.com/gogo/protobuf v1.2.1
@@ -24,20 +23,20 @@ require (
github.com/hashicorp/golang-lru v0.5.3
github.com/insolar/component-manager v0.2.1-0.20191028200619-751a91771d2f
github.com/insolar/go-actors v0.0.0-20190805151516-2fcc7bfc8ff9
+ github.com/insolar/insconfig v0.0.0-20200227134411-011eca6dc866
github.com/insolar/rpc v1.2.2-0.20190812143745-c27e1d218f1f
github.com/insolar/x-crypto v0.0.0-20191031140942-75fab8a325f6
github.com/jackc/pgx/v4 v4.2.1
github.com/jbenet/go-base58 v0.0.0-20150317085156-6237cf65f3a6
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 // indirect
github.com/kr/pty v1.1.8 // indirect
- github.com/magiconair/properties v1.8.1 // indirect
github.com/mattn/go-colorable v0.1.4 // indirect
github.com/olekukonko/tablewriter v0.0.1
github.com/onrik/gomerkle v1.0.0
github.com/opentracing/opentracing-go v1.1.0
github.com/ory/dockertest/v3 v3.5.2
github.com/pelletier/go-toml v1.4.0 // indirect
- github.com/pkg/errors v0.8.1
+ github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.0.0
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 // indirect
github.com/prometheus/common v0.6.0 // indirect
@@ -47,8 +46,8 @@ require (
github.com/spf13/afero v1.2.2 // indirect
github.com/spf13/cobra v0.0.5
github.com/spf13/jwalterweatherman v1.1.0
- github.com/spf13/pflag v1.0.3
- github.com/spf13/viper v1.4.0
+ github.com/spf13/pflag v1.0.5
+ github.com/spf13/viper v1.6.2
github.com/stretchr/objx v0.2.0 // indirect
github.com/stretchr/testify v1.4.0
github.com/tylerb/gls v0.0.0-20150407001822-e606233f194d
@@ -65,7 +64,7 @@ require (
gonum.org/v1/gonum v0.0.0-20191018104224-74cb7b153f2c
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55
google.golang.org/grpc v1.21.0
- gopkg.in/yaml.v2 v2.2.7
+ gopkg.in/yaml.v2 v2.2.8
)
replace github.com/insolar/insolar => ./
diff --git a/go.sum b/go.sum
index a205e30538..6dd4d333a1 100644
--- a/go.sum
+++ b/go.sum
@@ -32,6 +32,7 @@ github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghf
github.com/cheggaaa/pb/v3 v3.0.1 h1:m0BngUk2LuSRYdx4fujDKNRXNDpbNCfptPfVT2m6OJY=
github.com/cheggaaa/pb/v3 v3.0.1/go.mod h1:SqqeMF/pMOIu3xgGoxtPYhMNQP258xE4x/XRTYua+KU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I=
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd h1:qMd81Ts1T2OTKmB4acZcyKaMtRnY5Y44NuXGX2GFJ1w=
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
@@ -64,8 +65,6 @@ github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25Kn
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
-github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
-github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/getkin/kin-openapi v0.2.1-0.20191211203508-0d9caf80ada6 h1:4nv60wGOeFauhMx5mAy0Jy5fcsQs2JtPraUxDPlw8Lw=
@@ -78,6 +77,7 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/gofrs/uuid v3.2.0+incompatible h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4+jfEaewE=
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE=
@@ -104,7 +104,10 @@ github.com/google/gops v0.3.6 h1:6akvbMlpZrEYOuoebn2kR+ZJekbZqJ28fJXTs84+8to=
github.com/google/gops v0.3.6/go.mod h1:RZ1rH95wsAGX4vMWKmqBOIWynmWisBf4QFdgT/k/xOI=
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
+github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
+github.com/gotestyourself/gotestyourself v1.3.0 h1:9X3T0HDKAY/58/sEPpTkmyOg4wbb1ab9tZfV44mTSeE=
github.com/gotestyourself/gotestyourself v1.3.0/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
@@ -129,6 +132,10 @@ github.com/insolar/component-manager v0.2.1-0.20191028200619-751a91771d2f h1:06p
github.com/insolar/component-manager v0.2.1-0.20191028200619-751a91771d2f/go.mod h1:pyNB4e1NrTdT7BJJGMedR5OYIa6+zHLpak2Jwk9Aj88=
github.com/insolar/go-actors v0.0.0-20190805151516-2fcc7bfc8ff9 h1:476W50z1EA/U8uqXdVPS6avGmaL2hiBLrT6zKdETgB0=
github.com/insolar/go-actors v0.0.0-20190805151516-2fcc7bfc8ff9/go.mod h1:vh6gyvTJhKxCMROgV7ADLE1jS19NAd6gIaHCjHgVWKQ=
+github.com/insolar/insconfig v0.0.0-20200219113659-151f8a89d79e h1:PZ/cFu/emDPOuKye1NGi2SgUWMRgcY15PW11DhGDDPw=
+github.com/insolar/insconfig v0.0.0-20200219113659-151f8a89d79e/go.mod h1:zB9bawcGFKS4hwXcu6yH4rYH06EZnGlFfhl0+KMKM9k=
+github.com/insolar/insconfig v0.0.0-20200227134411-011eca6dc866 h1:821agB4jwkceJbV2lniBH3/mGLqSaHPhmurMfeGZAVg=
+github.com/insolar/insconfig v0.0.0-20200227134411-011eca6dc866/go.mod h1:zB9bawcGFKS4hwXcu6yH4rYH06EZnGlFfhl0+KMKM9k=
github.com/insolar/rpc v1.2.2-0.20190812143745-c27e1d218f1f h1:ULc0JNaPBjv2yxucU06zkqoXtDgX5Xokb4Dv3iJAcsE=
github.com/insolar/rpc v1.2.2-0.20190812143745-c27e1d218f1f/go.mod h1:BZcTsPtQu8QG8RqqQdAnuNAG8n6TOrdNxIHro0h99Ik=
github.com/insolar/x-crypto v0.0.0-20191031140942-75fab8a325f6 h1:WS4a7qw+P1pcnviyxyMTA/aR+T51wJok1IC9rJkHrTg=
@@ -143,6 +150,7 @@ github.com/jackc/pgconn v1.2.1 h1:+73KD6pbtv6Dbs6/rqlSRUa8XffPlW6YBd1hyFLpwuA=
github.com/jackc/pgconn v1.2.1/go.mod h1:GgY/Lbj1VonNaVdNUHs9AwWom3yP2eymFQ1C8z9r/Lk=
github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE=
github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
+github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2 h1:JVX6jT/XfzNqIjye4717ITLaNwV9mWbJx0dLCpcRzdA=
github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
@@ -171,6 +179,8 @@ github.com/jbenet/go-base58 v0.0.0-20150317085156-6237cf65f3a6 h1:4zOlv2my+vf98j
github.com/jbenet/go-base58 v0.0.0-20150317085156-6237cf65f3a6/go.mod h1:r/8JmuR0qjuCiEhAolkfvdZgmPiHTnJaG0UXCSeR1Zo=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
+github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
@@ -192,6 +202,7 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/lib/pq v0.0.0-20180327071824-d34b9ff171c2/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
+github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lithammer/shortuuid/v3 v3.0.4 h1:uj4xhotfY92Y1Oa6n6HUiFn87CdoEHYUlTy0+IgbLrs=
github.com/lithammer/shortuuid/v3 v3.0.4/go.mod h1:RviRjexKqIzx/7r1peoAITm6m7gnif/h+0zmolKJjzw=
@@ -240,6 +251,8 @@ github.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUr
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
@@ -275,11 +288,16 @@ github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b h1:gQZ0qzfKHQIybL
github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/shirou/gopsutil v0.0.0-20180427012116-c95755e4bcd7/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc=
+github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24 h1:pntxY8Ary0t43dCZ5dqY4YTJCObLY1kIXl0uzMv+7DE=
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
+github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
+github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
+github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
+github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
@@ -294,9 +312,11 @@ github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmq
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
+github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
-github.com/spf13/viper v1.4.0 h1:yXHLWeravcrgGyFSyCgdYpXQ9dR9c/WED3pg1RhxqEU=
-github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
+github.com/spf13/viper v1.6.2 h1:7aKfF+e8/k68gda3LOjo5RxiUqddoFxVq4BKBPrxk5E=
+github.com/spf13/viper v1.6.2/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
@@ -304,6 +324,8 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
+github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tylerb/gls v0.0.0-20150407001822-e606233f194d h1:yYYPFFlbqxF5mrj5sEfETtM/Ssz2LTy0/VKlDdXYctc=
github.com/tylerb/gls v0.0.0-20150407001822-e606233f194d/go.mod h1:0MwyId/pXK5wkYYEXe7NnVknX+aNBuF73fLV3U0reU8=
@@ -366,8 +388,6 @@ golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM=
-golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191003171128-d98b1b443823 h1:Ypyv6BNJh07T1pUSrehkLemqPKXhus2MkfktJ91kRh4=
golang.org/x/net v0.0.0-20191003171128-d98b1b443823/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -406,6 +426,7 @@ golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGm
golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
@@ -437,13 +458,18 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
+gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
+gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
+gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
rsc.io/goversion v1.0.0/go.mod h1:Eih9y/uIBS3ulggl7KNJ09xGSLcuNaLgmvvqa07sgfo=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
diff --git a/instrumentation/instracer/examples/clientserver_test.go b/instrumentation/instracer/examples/clientserver_test.go
index f741078c5c..8deca5eaea 100644
--- a/instrumentation/instracer/examples/clientserver_test.go
+++ b/instrumentation/instracer/examples/clientserver_test.go
@@ -40,7 +40,7 @@ func TestClientServerExample(t *testing.T) {
}
func Example_ClientServer() {
- cfgHolder := configuration.NewHolder().MustInit(false)
+ cfgHolder := configuration.NewLightHolder("testdata/insolard-light.yaml").MustLoad()
jconf := cfgHolder.Configuration.Tracer.Jaeger
ctx := context.Background()
inslogger.FromContext(ctx).Infof("jconf => %+v", jconf)
diff --git a/instrumentation/instracer/examples/testdata/insolard-light.yaml b/instrumentation/instracer/examples/testdata/insolard-light.yaml
new file mode 100644
index 0000000000..6a3780bb25
--- /dev/null
+++ b/instrumentation/instracer/examples/testdata/insolard-light.yaml
@@ -0,0 +1,62 @@
+host:
+ transport:
+ protocol: TCP
+ address: 127.0.0.1:0
+ fixedpublicaddress: ""
+ mintimeout: 10
+ maxtimeout: 2000
+ timeoutmult: 2
+ signmessages: false
+ handshakesessionttl: 5000
+service:
+ cachedirectory: network_cache
+log:
+ level: Info
+ adapter: zerolog
+ formatter: json
+ outputtype: stderr
+ outputparallellimit: ""
+ outputparams: ""
+ buffersize: 0
+ llbuffersize: 0
+metrics:
+ listenaddress: 0.0.0.0:9091
+ namespace: insolar
+ zpagesenabled: true
+ reportingperiod: 0s
+apirunner:
+ address: localhost:19101
+ rpc: /api/rpc
+ isadmin: false
+ swaggerpath: application/api/spec/api-exported.yaml
+adminapirunner:
+ address: localhost:19001
+ rpc: /admin-api/rpc
+ isadmin: true
+ swaggerpath: application/api/spec/api-exported.yaml
+availabilitychecker:
+ enabled: true
+ keeperurl: ""
+ requesttimeout: 15
+ checkperiod: 5
+keyspath: ./
+certificatepath: ""
+tracer:
+ jaeger:
+ collectorendpoint: ""
+ agentendpoint: ""
+ probabilityrate: 1
+ samplingrules: {}
+introspection:
+ addr: ""
+bus:
+ replytimeout: 15s
+lightchainlimit: 5
+ledger:
+ jetsplit:
+ thresholdrecordscount: 100
+ thresholdoverflowcount: 3
+ depthlimit: 5
+ cleanerdelay: 3
+ maxnotificationsperpulse: 100
+ filamentcachelimit: 3000
diff --git a/ledger/heavy/handler/handler.go b/ledger/heavy/handler/handler.go
index 6892e498d5..7213d0ae61 100644
--- a/ledger/heavy/handler/handler.go
+++ b/ledger/heavy/handler/handler.go
@@ -11,7 +11,6 @@ import (
watermillMsg "github.com/ThreeDotsLabs/watermill/message"
- "github.com/insolar/insolar/configuration"
"github.com/insolar/insolar/insolar/bus"
"github.com/insolar/insolar/insolar/bus/meta"
"github.com/insolar/insolar/insolar/jet"
@@ -32,8 +31,8 @@ import (
// Handler is a base struct for heavy's methods
type Handler struct {
- cfg configuration.Ledger
- gcRunner executor.GCRunInfo
+ lightChainLimit int
+ gcRunner executor.GCRunInfo
JetCoordinator jet.Coordinator
PCS insolar.PlatformCryptographyScheme
@@ -62,10 +61,10 @@ type Handler struct {
}
// New creates a new handler.
-func New(cfg configuration.Ledger, gcRunner executor.GCRunInfo) *Handler {
+func New(lightChainLimit int, gcRunner executor.GCRunInfo) *Handler {
h := &Handler{
- cfg: cfg,
- gcRunner: gcRunner,
+ lightChainLimit: lightChainLimit,
+ gcRunner: gcRunner,
}
dep := proc.Dependencies{
PassState: func(p *proc.PassState) {
@@ -192,7 +191,7 @@ func (h *Handler) handle(ctx context.Context, meta payload.Meta) error {
h.dep.SendCode(p)
err = p.Proceed(ctx)
case payload.TypeReplication:
- p := proc.NewReplication(meta, h.cfg)
+ p := proc.NewReplication(meta)
h.dep.Replication(p)
err = p.Proceed(ctx)
case payload.TypeGetJet:
@@ -214,7 +213,7 @@ func (h *Handler) handle(ctx context.Context, meta payload.Meta) error {
case payload.TypeGotHotConfirmation:
h.handleGotHotConfirmation(ctx, meta)
case payload.TypeGetLightInitialState:
- p := proc.NewSendInitialState(meta, h.cfg)
+ p := proc.NewSendInitialState(meta, h.lightChainLimit)
h.dep.SendInitialState(p)
err = p.Proceed(ctx)
case payload.TypeGetPulse:
diff --git a/ledger/heavy/integration/server_test.go b/ledger/heavy/integration/server_test.go
index 3d276fde1e..33054e7289 100644
--- a/ledger/heavy/integration/server_test.go
+++ b/ledger/heavy/integration/server_test.go
@@ -96,14 +96,14 @@ type Server struct {
}
// After using it you have to remove directory configuration.Storage.DataDirectory by yourself
-func DefaultHeavyConfig() configuration.Configuration {
+func DefaultHeavyConfig() configuration.HeavyBadgerConfig {
tmpDir, err := ioutil.TempDir("", "heavy-integr-test-")
if err != nil {
panic(err)
}
- cfg := configuration.Configuration{}
+ cfg := configuration.HeavyBadgerConfig{}
cfg.KeysPath = "testdata/bootstrap_keys.json"
- cfg.Ledger.LightChainLimit = math.MaxInt32
+ cfg.LightChainLimit = math.MaxInt32
cfg.Bus.ReplyTimeout = time.Minute
cfg.Ledger.Storage = configuration.Storage{
DataDirectory: tmpDir,
@@ -117,7 +117,7 @@ func defaultReceiveCallback(meta payload.Meta, pl payload.Payload) []payload.Pay
func NewBadgerServer(
ctx context.Context,
- cfg configuration.Configuration,
+ cfg configuration.HeavyBadgerConfig,
genesisCfg genesis.HeavyConfig,
receiveCallback func(meta payload.Meta, pl payload.Payload) []payload.Payload,
) (*Server, error) {
@@ -174,7 +174,7 @@ func NewBadgerServer(
Pulses = insolarPulse.NewBadgerDB(DB)
Jets = jet.NewBadgerDBStore(DB)
- c := jetcoordinator.NewJetCoordinator(cfg.Ledger.LightChainLimit, light.ref)
+ c := jetcoordinator.NewJetCoordinator(cfg.LightChainLimit, light.ref)
c.PulseCalculator = Pulses
c.PulseAccessor = Pulses
c.JetAccessor = Jets
@@ -195,7 +195,7 @@ func NewBadgerServer(
ClientPubSub = gochannel.NewGoChannel(gochannel.Config{}, logger)
ServerBus = bus.NewBus(cfg.Bus, ServerPubSub, Pulses, Coordinator, CryptoScheme)
- c := jetcoordinator.NewJetCoordinator(cfg.Ledger.LightChainLimit, virtual.ref)
+ c := jetcoordinator.NewJetCoordinator(cfg.LightChainLimit, virtual.ref)
c.PulseCalculator = Pulses
c.PulseAccessor = Pulses
c.JetAccessor = Jets
@@ -239,9 +239,9 @@ func NewBadgerServer(
pm.PulseAccessor = Pulses
pm.JetModifier = Jets
pm.StartPulse = sp
- pm.FinalizationKeeper = executor.NewFinalizationKeeperDefault(JetKeeper, Pulses, cfg.Ledger.LightChainLimit)
+ pm.FinalizationKeeper = executor.NewFinalizationKeeperDefault(JetKeeper, Pulses, cfg.LightChainLimit)
- h := handler.New(cfg.Ledger, gcRunInfo)
+ h := handler.New(cfg.LightChainLimit, gcRunInfo)
h.RecordAccessor = Records
h.RecordModifier = Records
h.JetCoordinator = Coordinator
diff --git a/ledger/heavy/proc/replication.go b/ledger/heavy/proc/replication.go
index 1bedd7bef1..ee790ae541 100644
--- a/ledger/heavy/proc/replication.go
+++ b/ledger/heavy/proc/replication.go
@@ -9,27 +9,25 @@ import (
"context"
"fmt"
- "github.com/insolar/insolar/configuration"
+ "github.com/pkg/errors"
+ "go.opencensus.io/stats"
+
"github.com/insolar/insolar/insolar/payload"
"github.com/insolar/insolar/instrumentation/inslogger"
"github.com/insolar/insolar/ledger/heavy/executor"
- "github.com/pkg/errors"
- "go.opencensus.io/stats"
)
type Replication struct {
message payload.Meta
- cfg configuration.Ledger
dep struct {
replicator executor.HeavyReplicator
}
}
-func NewReplication(msg payload.Meta, cfg configuration.Ledger) *Replication {
+func NewReplication(msg payload.Meta) *Replication {
return &Replication{
message: msg,
- cfg: cfg,
}
}
diff --git a/ledger/heavy/proc/send_initial_state.go b/ledger/heavy/proc/send_initial_state.go
index 872670370c..af48d4e06e 100644
--- a/ledger/heavy/proc/send_initial_state.go
+++ b/ledger/heavy/proc/send_initial_state.go
@@ -9,7 +9,6 @@ import (
"context"
"fmt"
- "github.com/insolar/insolar/configuration"
"github.com/insolar/insolar/insolar"
"github.com/insolar/insolar/insolar/bus"
"github.com/insolar/insolar/insolar/payload"
@@ -19,8 +18,8 @@ import (
)
type SendInitialState struct {
- meta payload.Meta
- cfg configuration.Ledger
+ meta payload.Meta
+ lightChainLimit int
dep struct {
startPulse pulse.StartPulse
@@ -45,10 +44,10 @@ func (p *SendInitialState) Dep(
p.dep.sender = sender
}
-func NewSendInitialState(meta payload.Meta, cfg configuration.Ledger) *SendInitialState {
+func NewSendInitialState(meta payload.Meta, lightChainLimit int) *SendInitialState {
return &SendInitialState{
- meta: meta,
- cfg: cfg,
+ meta: meta,
+ lightChainLimit: lightChainLimit,
}
}
@@ -112,7 +111,7 @@ func (p *SendInitialState) sendForNetworkStart(
Drops: state.Drops,
Indexes: state.Indexes,
Pulse: *pulse.ToProto(&topSyncPulse),
- LightChainLimit: uint32(p.cfg.LightChainLimit),
+ LightChainLimit: uint32(p.lightChainLimit),
})
if err != nil {
logger.Fatal("Couldn't make message", err)
@@ -126,7 +125,7 @@ func (p *SendInitialState) sendForJoiner(ctx context.Context, topSyncPulse insol
msg, err := payload.NewMessage(&payload.LightInitialState{
NetworkStart: false,
Pulse: *pulse.ToProto(&topSyncPulse),
- LightChainLimit: uint32(p.cfg.LightChainLimit),
+ LightChainLimit: uint32(p.lightChainLimit),
})
if err != nil {
logger.Fatal("Couldn't make message", err)
diff --git a/ledger/heavy/proc/send_initial_state_test.go b/ledger/heavy/proc/send_initial_state_test.go
index f557e9833d..f920f53311 100644
--- a/ledger/heavy/proc/send_initial_state_test.go
+++ b/ledger/heavy/proc/send_initial_state_test.go
@@ -11,7 +11,6 @@ import (
"github.com/ThreeDotsLabs/watermill/message"
"github.com/gojuno/minimock/v3"
- "github.com/insolar/insolar/configuration"
"github.com/insolar/insolar/insolar"
"github.com/insolar/insolar/insolar/bus"
"github.com/insolar/insolar/insolar/gen"
@@ -29,7 +28,7 @@ func TestNewSendInitialState(t *testing.T) {
expected := &SendInitialState{
meta: meta,
}
- is := NewSendInitialState(meta, configuration.Ledger{})
+ is := NewSendInitialState(meta, 0)
require.Equal(t, expected, is)
}
@@ -40,7 +39,7 @@ func TestSendInitialState_Dep(t *testing.T) {
pulseAccessor := pulse.NewAccessorMock(t)
sender := bus.NewSenderMock(t)
- is := NewSendInitialState(payload.Meta{}, configuration.Ledger{})
+ is := NewSendInitialState(payload.Meta{}, 0)
is.Dep(startPulse, jetKeeper, stateAccessor, pulseAccessor, sender)
require.Equal(t, startPulse, is.dep.startPulse)
require.Equal(t, jetKeeper, is.dep.jetKeeper)
@@ -59,7 +58,7 @@ func TestSendInitialState_ProceedNoPulse(t *testing.T) {
require.Equal(t, payload.CodeNoStartPulse, resErr.Code)
require.Equal(t, "Couldn't get start pulse", resErr.Text)
})
- is := NewSendInitialState(payload.Meta{}, configuration.Ledger{})
+ is := NewSendInitialState(payload.Meta{}, 0)
is.dep.startPulse = pulse.NewStartPulse()
is.dep.sender = sender
err := is.Proceed(ctx)
@@ -70,7 +69,7 @@ func TestSendInitialState_ProceedUnknownRequest(t *testing.T) {
ctx := inslogger.TestContext(t)
p, err := payload.Marshal(&payload.Request{})
require.NoError(t, err)
- is := NewSendInitialState(payload.Meta{Payload: p}, configuration.Ledger{})
+ is := NewSendInitialState(payload.Meta{Payload: p}, 0)
is.dep.startPulse = pulse.NewStartPulse()
is.dep.startPulse.SetStartPulse(ctx, insolar.Pulse{PulseNumber: 1000})
@@ -126,7 +125,7 @@ func TestSendInitialState_ProceedForNetworkStart(t *testing.T) {
Payload: p,
Sender: light,
Pulse: 1000,
- }, configuration.Ledger{})
+ }, 0)
is.dep.startPulse = startPulse
is.dep.jetKeeper = jetKeeper
is.dep.pulseAccessor = pulseAccessor
@@ -170,7 +169,7 @@ func TestSendInitialState_ProceedForJoiner(t *testing.T) {
Payload: p,
Sender: light,
Pulse: 1001,
- }, configuration.Ledger{})
+ }, 0)
is.dep.startPulse = startPulse
is.dep.jetKeeper = jetKeeper
diff --git a/ledger/light/executor/state_initer.go b/ledger/light/executor/state_initer.go
index 0ddd4ca2dc..34e4fe87e8 100644
--- a/ledger/light/executor/state_initer.go
+++ b/ledger/light/executor/state_initer.go
@@ -13,7 +13,6 @@ import (
"github.com/ThreeDotsLabs/watermill/message"
"go.opencensus.io/stats"
- "github.com/insolar/insolar/configuration"
"github.com/insolar/insolar/insolar"
"github.com/insolar/insolar/insolar/backoff"
"github.com/insolar/insolar/insolar/bus"
@@ -41,7 +40,7 @@ const timeout = 10 * time.Second
// NewStateIniter creates StateIniterDefault with all required components.
func NewStateIniter(
- cfg configuration.Ledger,
+ lightChainLimit int,
jetModifier jet.Modifier,
jetReleaser JetReleaser,
drops drop.Modifier,
@@ -53,16 +52,16 @@ func NewStateIniter(
indexes object.MemoryIndexModifier,
) *StateIniterDefault {
return &StateIniterDefault{
- cfg: cfg,
- jetModifier: jetModifier,
- jetReleaser: jetReleaser,
- drops: drops,
- nodes: nodes,
- sender: sender,
- pulseAppender: pulseAppender,
- pulseAccessor: pulseAccessor,
- jetCalculator: calc,
- indexes: indexes,
+ lightChainLimit: lightChainLimit,
+ jetModifier: jetModifier,
+ jetReleaser: jetReleaser,
+ drops: drops,
+ nodes: nodes,
+ sender: sender,
+ pulseAppender: pulseAppender,
+ pulseAccessor: pulseAccessor,
+ jetCalculator: calc,
+ indexes: indexes,
backoff: backoff.Backoff{
Factor: 2,
Jitter: true,
@@ -74,17 +73,17 @@ func NewStateIniter(
// StateIniterDefault implements StateIniter.
type StateIniterDefault struct {
- cfg configuration.Ledger
- jetModifier jet.Modifier
- jetReleaser JetReleaser
- drops drop.Modifier
- nodes node.Accessor
- sender bus.Sender
- pulseAppender insolarPulse.Appender
- pulseAccessor insolarPulse.Accessor
- jetCalculator JetCalculator
- backoff backoff.Backoff
- indexes object.MemoryIndexModifier
+ lightChainLimit int
+ jetModifier jet.Modifier
+ jetReleaser JetReleaser
+ drops drop.Modifier
+ nodes node.Accessor
+ sender bus.Sender
+ pulseAppender insolarPulse.Appender
+ pulseAccessor insolarPulse.Accessor
+ jetCalculator JetCalculator
+ backoff backoff.Backoff
+ indexes object.MemoryIndexModifier
}
func (s *StateIniterDefault) PrepareState(
@@ -184,11 +183,11 @@ func (s *StateIniterDefault) loadStateRetry(
return nil, fmt.Errorf("unexpected reply %T", pl)
}
- if uint32(s.cfg.LightChainLimit) != state.LightChainLimit {
+ if uint32(s.lightChainLimit) != state.LightChainLimit {
panic(fmt.Sprintf(
"configuration mismatch: LightChainLimit: from heavy %v, from light %v",
state.LightChainLimit,
- s.cfg.LightChainLimit,
+ s.lightChainLimit,
))
}
diff --git a/ledger/light/executor/state_initer_test.go b/ledger/light/executor/state_initer_test.go
index f0c1afac5e..ab52891b56 100644
--- a/ledger/light/executor/state_initer_test.go
+++ b/ledger/light/executor/state_initer_test.go
@@ -13,7 +13,6 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
- "github.com/insolar/insolar/configuration"
"github.com/insolar/insolar/insolar"
"github.com/insolar/insolar/insolar/bus"
"github.com/insolar/insolar/insolar/gen"
@@ -61,7 +60,7 @@ func TestStateIniterDefault_PrepareState(t *testing.T) {
defer mc.Finish()
s := executor.NewStateIniter(
- configuration.Ledger{},
+ 0,
jetModifier,
jetReleaser,
drops,
@@ -83,7 +82,7 @@ func TestStateIniterDefault_PrepareState(t *testing.T) {
var heavy []insolar.Node
s := executor.NewStateIniter(
- configuration.Ledger{},
+ 0,
jetModifier,
jetReleaser,
drops,
@@ -107,7 +106,7 @@ func TestStateIniterDefault_PrepareState(t *testing.T) {
jets := []insolar.JetID{gen.JetID(), gen.JetID(), gen.JetID()}
s := executor.NewStateIniter(
- configuration.Ledger{},
+ 0,
jetModifier,
jetReleaser,
drops,
@@ -139,7 +138,7 @@ func TestStateIniterDefault_PrepareState(t *testing.T) {
heavy := []insolar.Node{{ID: *insolar.NewReference(gen.ID()), Role: insolar.StaticRoleHeavyMaterial}}
s := executor.NewStateIniter(
- configuration.Ledger{},
+ 0,
jetModifier,
jetReleaser,
drops,
@@ -171,9 +170,7 @@ func TestStateIniterDefault_PrepareState(t *testing.T) {
})
s := executor.NewStateIniter(
- configuration.Ledger{
- LightChainLimit: 5,
- },
+ 5,
jetModifier,
jetReleaser,
drops,
@@ -217,7 +214,7 @@ func TestStateIniterDefault_PrepareState(t *testing.T) {
})
s := executor.NewStateIniter(
- configuration.Ledger{},
+ 0,
jetModifier.UpdateMock.Return(nil),
jetReleaser.UnlockMock.Return(nil),
drops.SetMock.Return(nil),
diff --git a/ledger/light/integration/abandoned_notification_test.go b/ledger/light/integration/abandoned_notification_test.go
index 6f15290754..96ef9d1f09 100644
--- a/ledger/light/integration/abandoned_notification_test.go
+++ b/ledger/light/integration/abandoned_notification_test.go
@@ -37,7 +37,7 @@ func Test_AbandonedNotification_WhenLightEmpty(t *testing.T) {
// Configs.
ctx := inslogger.TestContext(t)
cfg := DefaultLightConfig()
- cfg.Ledger.LightChainLimit = 5
+ cfg.LightChainLimit = 5
// Responses from server.
received := make(chan payload.AbandonedRequestsNotification)
@@ -165,7 +165,7 @@ func Test_AbandonedNotification_WhenLightInit(t *testing.T) {
// Configs.
ctx := inslogger.TestContext(t)
cfg := DefaultLightConfig()
- cfg.Ledger.LightChainLimit = 5
+ cfg.LightChainLimit = 5
// Responses from server.
received := make(chan payload.AbandonedRequestsNotification)
@@ -244,7 +244,7 @@ func Test_AbandonedNotification_WhenLightInit(t *testing.T) {
func Test_AbandonsMetricValue(t *testing.T) {
ctx := inslogger.TestContext(t)
cfg := DefaultLightConfig()
- cfg.Ledger.LightChainLimit = 5
+ cfg.LightChainLimit = 5
s, err := NewServer(ctx, cfg, nil)
require.NoError(t, err)
defer s.Stop()
diff --git a/ledger/light/integration/server_test.go b/ledger/light/integration/server_test.go
index 42bbac2992..168c8e5d6e 100644
--- a/ledger/light/integration/server_test.go
+++ b/ledger/light/integration/server_test.go
@@ -87,10 +87,10 @@ type Server struct {
metrics *metrics.Metrics
}
-func DefaultLightConfig() configuration.Configuration {
- cfg := configuration.Configuration{}
+func DefaultLightConfig() configuration.LightConfig {
+ cfg := configuration.LightConfig{}
cfg.KeysPath = "testdata/bootstrap_keys.json"
- cfg.Ledger.LightChainLimit = math.MaxInt32
+ cfg.LightChainLimit = math.MaxInt32
cfg.Ledger.JetSplit.DepthLimit = math.MaxUint8
cfg.Ledger.JetSplit.ThresholdOverflowCount = math.MaxInt32
cfg.Ledger.JetSplit.ThresholdRecordsCount = math.MaxInt32
@@ -134,7 +134,7 @@ func defaultReceiveCallback(meta payload.Meta, pl payload.Payload) []payload.Pay
func NewServer(
ctx context.Context,
- cfg configuration.Configuration,
+ cfg configuration.LightConfig,
receiveCallback func(meta payload.Meta, pl payload.Payload) []payload.Payload,
) (*Server, error) {
// Cryptography.
@@ -181,7 +181,7 @@ func NewServer(
Pulses = insolarPulse.NewStorageMem()
Jets = jet.NewStore()
- c := jetcoordinator.NewJetCoordinator(cfg.Ledger.LightChainLimit, light.ref)
+ c := jetcoordinator.NewJetCoordinator(cfg.LightChainLimit, light.ref)
c.PulseCalculator = Pulses
c.PulseAccessor = Pulses
c.JetAccessor = Jets
@@ -203,7 +203,7 @@ func NewServer(
ClientPubSub = gochannel.NewGoChannel(gochannel.Config{}, logger)
ServerBus = bus.NewBus(cfg.Bus, ServerPubSub, Pulses, Coordinator, CryptoScheme)
- c := jetcoordinator.NewJetCoordinator(cfg.Ledger.LightChainLimit, virtual.ref)
+ c := jetcoordinator.NewJetCoordinator(cfg.LightChainLimit, virtual.ref)
c.PulseCalculator = Pulses
c.PulseAccessor = Pulses
c.JetAccessor = Jets
@@ -257,7 +257,7 @@ func NewServer(
Pulses,
indexes,
filamentCalculator,
- conf.LightChainLimit,
+ cfg.LightChainLimit,
conf.CleanerDelay,
conf.FilamentCacheLimit,
)
@@ -282,12 +282,12 @@ func NewServer(
indexes,
Pulses,
Jets,
- conf.LightChainLimit,
+ cfg.LightChainLimit,
ServerBus,
)
stateIniter := executor.NewStateIniter(
- conf, Jets, hotWaitReleaser, drops, Nodes, ServerBus, Pulses, Pulses, jetCalculator, indexes,
+ cfg.LightChainLimit, Jets, hotWaitReleaser, drops, Nodes, ServerBus, Pulses, Pulses, jetCalculator, indexes,
)
metricsRegistry := executor.NewMetricsRegistry()
@@ -309,7 +309,7 @@ func NewServer(
filamentCalculator,
requestChecker,
detachedNotifier,
- configuration.NewLedger(),
+ configuration.NewLedgerLight(),
metricsRegistry,
)
diff --git a/ledger/light/proc/proc.go b/ledger/light/proc/proc.go
index 4881954a59..5bbfdda8c8 100644
--- a/ledger/light/proc/proc.go
+++ b/ledger/light/proc/proc.go
@@ -35,7 +35,7 @@ type Dependencies struct {
SetCode func(*SetCode)
SendFilament func(*SendFilament)
HasPendings func(*HasPendings)
- Config func() configuration.Ledger
+ Config func() configuration.LedgerLight
}
func NewDependencies(
@@ -61,7 +61,7 @@ func NewDependencies(
requestChecker executor.RequestChecker,
detachedNotifier executor.DetachedNotifier,
- config configuration.Ledger,
+ config configuration.LedgerLight,
registry executor.MetricsRegistry,
) *Dependencies {
dep := &Dependencies{
@@ -205,7 +205,7 @@ func NewDependencies(
sender,
)
},
- Config: func() configuration.Ledger {
+ Config: func() configuration.LedgerLight {
return config
},
}
@@ -235,6 +235,6 @@ func NewDependenciesMock() *Dependencies {
SendFilament: func(*SendFilament) {},
HasPendings: func(*HasPendings) {},
GetRequestInfo: func(*SendRequestInfo) {},
- Config: configuration.NewLedger,
+ Config: configuration.NewLedgerLight,
}
}
diff --git a/log/log.go b/log/log.go
index ccd5d2f472..7875e2ada4 100644
--- a/log/log.go
+++ b/log/log.go
@@ -155,8 +155,7 @@ func InitTicker() {
// GlobalLogger creates global logger with correct skipCallNumber
func createNoConfigGlobalLogger() {
- holder := configuration.NewHolder().MustInit(false)
- logCfg := holder.Configuration.Log
+ logCfg := configuration.NewGenericConfiguration().Log
// enforce buffer-less for a non-configured logger
logCfg.BufferSize = 0
diff --git a/network/gateway/bootstrap/requester_test.go b/network/gateway/bootstrap/requester_test.go
index 1171aff7aa..c243c79462 100644
--- a/network/gateway/bootstrap/requester_test.go
+++ b/network/gateway/bootstrap/requester_test.go
@@ -34,7 +34,7 @@ func TestRequester_Authorize(t *testing.T) {
t.Skip("Until merge")
cert := GetTestCertificate()
- options := network.ConfigureOptions(configuration.NewConfiguration())
+ options := network.ConfigureOptions(configuration.NewGenericConfiguration().Host)
cs := testutils.NewCryptographyServiceMock(t)
sig := insolar.SignatureFromBytes([]byte("lalal"))
@@ -48,7 +48,7 @@ func TestRequester_Authorize(t *testing.T) {
}
func TestRequester_Bootstrap(t *testing.T) {
- options := network.ConfigureOptions(configuration.NewConfiguration())
+ options := network.ConfigureOptions(configuration.NewGenericConfiguration().Host)
hn := mock.NewHostNetworkMock(t)
hn.SendRequestToHostMock.Set(func(p context.Context, p1 types.PacketType, p2 interface{}, p3 *host.Host) (r network.Future, r1 error) {
diff --git a/network/options.go b/network/options.go
index 811b458da4..fd82b1c69d 100644
--- a/network/options.go
+++ b/network/options.go
@@ -36,8 +36,7 @@ type Options struct {
}
// ConfigureOptions convert daemon configuration to controller options
-func ConfigureOptions(conf configuration.Configuration) *Options {
- config := conf.Host
+func ConfigureOptions(config configuration.HostNetwork) *Options {
return &Options{
TimeoutMult: time.Duration(config.TimeoutMult) * time.Millisecond,
MinTimeout: time.Duration(config.MinTimeout) * time.Millisecond,
diff --git a/network/servicenetwork/servicenetwork.go b/network/servicenetwork/servicenetwork.go
index a2b9fb244e..566c7270c4 100644
--- a/network/servicenetwork/servicenetwork.go
+++ b/network/servicenetwork/servicenetwork.go
@@ -29,7 +29,7 @@ import (
// ServiceNetwork is facade for network.
type ServiceNetwork struct {
- cfg configuration.Configuration
+ cfg configuration.HostNetwork
cm *component.Manager
// dependencies
@@ -58,7 +58,7 @@ type ServiceNetwork struct {
}
// NewServiceNetwork returns a new ServiceNetwork.
-func NewServiceNetwork(conf configuration.Configuration, rootCm *component.Manager) (*ServiceNetwork, error) {
+func NewServiceNetwork(conf configuration.HostNetwork, rootCm *component.Manager) (*ServiceNetwork, error) {
serviceNetwork := &ServiceNetwork{cm: component.NewManager(rootCm), cfg: conf}
return serviceNetwork, nil
}
@@ -75,7 +75,7 @@ func (n *ServiceNetwork) Init(ctx context.Context) error {
cert := n.CertificateManager.GetCertificate()
- nodeNetwork, err := nodenetwork.NewNodeNetwork(n.cfg.Host.Transport, cert)
+ nodeNetwork, err := nodenetwork.NewNodeNetwork(n.cfg.Transport, cert)
if err != nil {
return errors.Wrap(err, "failed to create NodeNetwork")
}
@@ -88,7 +88,7 @@ func (n *ServiceNetwork) Init(ctx context.Context) error {
n.cm.Inject(n,
table,
cert,
- transport.NewFactory(n.cfg.Host.Transport),
+ transport.NewFactory(n.cfg.Transport),
hostNetwork,
nodeNetwork,
controller.NewRPCController(options),
diff --git a/network/servicenetwork/servicenetwork_test.go b/network/servicenetwork/servicenetwork_test.go
index bc09994595..e52073006c 100644
--- a/network/servicenetwork/servicenetwork_test.go
+++ b/network/servicenetwork/servicenetwork_test.go
@@ -40,8 +40,8 @@ func (p *PublisherMock) Close() error {
return nil
}
-func prepareNetwork(t *testing.T, cfg configuration.Configuration) *ServiceNetwork {
- serviceNetwork, err := NewServiceNetwork(cfg, component.NewManager(nil))
+func prepareNetwork(t *testing.T, cfg configuration.GenericConfiguration) *ServiceNetwork {
+ serviceNetwork, err := NewServiceNetwork(cfg.Host, component.NewManager(nil))
require.NoError(t, err)
nodeKeeper := networkUtils.NewNodeKeeperMock(t)
@@ -54,7 +54,7 @@ func prepareNetwork(t *testing.T, cfg configuration.Configuration) *ServiceNetwo
}
func TestSendMessageHandler_ReceiverNotSet(t *testing.T) {
- cfg := configuration.NewConfiguration()
+ cfg := configuration.NewGenericConfiguration()
serviceNetwork := prepareNetwork(t, cfg)
@@ -72,8 +72,8 @@ func TestSendMessageHandler_ReceiverNotSet(t *testing.T) {
}
func TestSendMessageHandler_SameNode(t *testing.T) {
- cfg := configuration.NewConfiguration()
- serviceNetwork, err := NewServiceNetwork(cfg, component.NewManager(nil))
+ cfg := configuration.NewGenericConfiguration()
+ serviceNetwork, err := NewServiceNetwork(cfg.Host, component.NewManager(nil))
nodeRef := gen.Reference()
nodeN := networkUtils.NewNodeKeeperMock(t)
nodeN.GetOriginMock.Set(func() (r insolar.NetworkNode) {
@@ -105,9 +105,9 @@ func TestSendMessageHandler_SameNode(t *testing.T) {
}
func TestSendMessageHandler_SendError(t *testing.T) {
- cfg := configuration.NewConfiguration()
+ cfg := configuration.NewGenericConfiguration()
pubMock := &PublisherMock{}
- serviceNetwork, err := NewServiceNetwork(cfg, component.NewManager(nil))
+ serviceNetwork, err := NewServiceNetwork(cfg.Host, component.NewManager(nil))
serviceNetwork.Pub = pubMock
nodeN := networkUtils.NewNodeKeeperMock(t)
nodeN.GetOriginMock.Set(func() (r insolar.NetworkNode) {
@@ -142,9 +142,9 @@ func TestSendMessageHandler_SendError(t *testing.T) {
}
func TestSendMessageHandler_WrongReply(t *testing.T) {
- cfg := configuration.NewConfiguration()
+ cfg := configuration.NewGenericConfiguration()
pubMock := &PublisherMock{}
- serviceNetwork, err := NewServiceNetwork(cfg, component.NewManager(nil))
+ serviceNetwork, err := NewServiceNetwork(cfg.Host, component.NewManager(nil))
serviceNetwork.Pub = pubMock
nodeN := networkUtils.NewNodeKeeperMock(t)
nodeN.GetOriginMock.Set(func() (r insolar.NetworkNode) {
@@ -179,8 +179,8 @@ func TestSendMessageHandler_WrongReply(t *testing.T) {
}
func TestSendMessageHandler(t *testing.T) {
- cfg := configuration.NewConfiguration()
- serviceNetwork, err := NewServiceNetwork(cfg, component.NewManager(nil))
+ cfg := configuration.NewGenericConfiguration()
+ serviceNetwork, err := NewServiceNetwork(cfg.Host, component.NewManager(nil))
nodeN := networkUtils.NewNodeKeeperMock(t)
nodeN.GetOriginMock.Set(func() (r insolar.NetworkNode) {
n := networkUtils.NewNetworkNodeMock(t)
@@ -227,7 +227,7 @@ func TestServiceNetwork_StartStop(t *testing.T) {
cert := &certificate.Certificate{}
cert.Reference = origin.String()
certManager := certificate.NewCertificateManager(cert)
- serviceNetwork, err := NewServiceNetwork(configuration.NewConfiguration(), cm)
+ serviceNetwork, err := NewServiceNetwork(configuration.NewGenericConfiguration().Host, cm)
require.NoError(t, err)
ctx := context.Background()
defer serviceNetwork.Stop(ctx)
@@ -250,7 +250,7 @@ func (pm *publisherMock) Publish(topic string, messages ...*message.Message) err
func (pm *publisherMock) Close() error { return nil }
func TestServiceNetwork_processIncoming(t *testing.T) {
- serviceNetwork, err := NewServiceNetwork(configuration.NewConfiguration(), component.NewManager(nil))
+ serviceNetwork, err := NewServiceNetwork(configuration.NewGenericConfiguration().Host, component.NewManager(nil))
require.NoError(t, err)
pub := &publisherMock{}
serviceNetwork.Pub = pub
diff --git a/network/tests/suite_test.go b/network/tests/suite_test.go
index ffa0fed8f2..767b56ca5f 100644
--- a/network/tests/suite_test.go
+++ b/network/tests/suite_test.go
@@ -530,13 +530,13 @@ func (p *PublisherMock) Close() error {
// preInitNode inits previously created node with mocks and external dependencies
func (s *testSuite) preInitNode(node *networkNode) {
- cfg := configuration.NewConfiguration()
+ cfg := configuration.NewGenericConfiguration()
cfg.Host.Transport.Address = node.host
cfg.Service.CacheDirectory = cacheDir + node.host
node.componentManager = component.NewManager(nil)
node.componentManager.Register(platformpolicy.NewPlatformCryptographyScheme())
- serviceNetwork, err := servicenetwork.NewServiceNetwork(cfg, node.componentManager)
+ serviceNetwork, err := servicenetwork.NewServiceNetwork(cfg.Host, node.componentManager)
require.NoError(s.t, err)
certManager, cryptographyService := s.initCrypto(node)
diff --git a/server/internal/heavy/components.go b/server/internal/heavy/components.go
index 61ec88c4d9..3a23b0bdde 100644
--- a/server/internal/heavy/components.go
+++ b/server/internal/heavy/components.go
@@ -76,7 +76,7 @@ type components struct {
replicator executor.HeavyReplicator
}
-func initTemporaryCertificateManager(ctx context.Context, cfg *configuration.Configuration) (*certificate.CertificateManager, error) {
+func initTemporaryCertificateManager(ctx context.Context, cfg *configuration.GenericConfiguration) (*certificate.CertificateManager, error) {
earlyComponents := component.NewManager(nil)
keyStore, err := keystore.NewKeyStore(cfg.KeysPath)
@@ -106,7 +106,7 @@ func initTemporaryCertificateManager(ctx context.Context, cfg *configuration.Con
func initWithPostgres(
ctx context.Context,
- cfg configuration.Configuration,
+ cfg configuration.ConfigHeavyPg,
genesisCfg genesis.HeavyConfig,
genesisOptions genesis.Options,
genesisOnly bool,
@@ -177,7 +177,7 @@ func initWithPostgres(
{
var err error
// External communication.
- NetworkService, err = servicenetwork.NewServiceNetwork(cfg, c.cmp)
+ NetworkService, err = servicenetwork.NewServiceNetwork(cfg.GenericConfiguration.Host, c.cmp)
if err != nil {
return nil, errors.Wrap(err, "failed to start Network")
}
@@ -192,7 +192,7 @@ func initWithPostgres(
JetsPostgres *jet.PostgresDBStore
)
{
- c := jetcoordinator.NewJetCoordinator(cfg.Ledger.LightChainLimit, *CertManager.GetCertificate().GetNodeRef())
+ c := jetcoordinator.NewJetCoordinator(cfg.LightChainLimit, *CertManager.GetCertificate().GetNodeRef())
c.PlatformCryptographyScheme = CryptoScheme
Coordinator = c
@@ -342,7 +342,7 @@ func initWithPostgres(
PulseManager.PulseAppender = PulsesPostgres
PulseManager.PulseAccessor = PulsesPostgres
PulseManager.JetModifier = JetsPostgres
- PulseManager.FinalizationKeeper = executor.NewFinalizationKeeperDefault(PostgresJetKeeper, PulsesPostgres, cfg.Ledger.LightChainLimit)
+ PulseManager.FinalizationKeeper = executor.NewFinalizationKeeperDefault(PostgresJetKeeper, PulsesPostgres, cfg.LightChainLimit)
replicator := executor.NewHeavyReplicatorDefault(
RecordsPostgres,
@@ -359,7 +359,7 @@ func initWithPostgres(
PulseManager.StartPulse = sp
- h := handler.New(cfg.Ledger, &executor.PostgresGCRunInfo{})
+ h := handler.New(cfg.LightChainLimit, &executor.PostgresGCRunInfo{})
h.RecordAccessor = RecordsPostgres
h.RecordModifier = RecordsPostgres
h.JetCoordinator = Coordinator
@@ -472,7 +472,7 @@ func initWithPostgres(
func initWithBadger(
ctx context.Context,
- cfg configuration.Configuration,
+ cfg configuration.HeavyBadgerConfig,
genesisCfg genesis.HeavyConfig,
genesisOptions genesis.Options,
genesisOnly bool,
@@ -543,7 +543,7 @@ func initWithBadger(
{
var err error
// External communication.
- NetworkService, err = servicenetwork.NewServiceNetwork(cfg, c.cmp)
+ NetworkService, err = servicenetwork.NewServiceNetwork(cfg.GenericConfiguration.Host, c.cmp)
if err != nil {
return nil, errors.Wrap(err, "failed to start Network")
}
@@ -582,7 +582,7 @@ func initWithBadger(
stats.Record(ctx, statBadgerStartTime.M(float64(timeBadgerStarted.Nanoseconds())/1e6))
logger.Info("badger starts in ", timeBadgerStarted)
- c := jetcoordinator.NewJetCoordinator(cfg.Ledger.LightChainLimit, *CertManager.GetCertificate().GetNodeRef())
+ c := jetcoordinator.NewJetCoordinator(cfg.LightChainLimit, *CertManager.GetCertificate().GetNodeRef())
c.PulseCalculator = Pulses
c.PulseAccessor = Pulses
c.JetAccessor = Jets
@@ -693,13 +693,13 @@ func initWithBadger(
PulseManager.PulseAccessor = Pulses
PulseManager.JetModifier = Jets
PulseManager.StartPulse = sp
- PulseManager.FinalizationKeeper = executor.NewFinalizationKeeperDefault(JetKeeper, Pulses, cfg.Ledger.LightChainLimit)
+ PulseManager.FinalizationKeeper = executor.NewFinalizationKeeperDefault(JetKeeper, Pulses, cfg.LightChainLimit)
gcRunInfo := executor.NewBadgerGCRunInfo(DB, cfg.Ledger.Storage.GCRunFrequency)
replicator := executor.NewHeavyReplicatorDefault(Records, indexes, CryptoScheme, Pulses, drops, JetKeeper, backupMaker, Jets, gcRunInfo)
c.replicator = replicator
- h := handler.New(cfg.Ledger, gcRunInfo)
+ h := handler.New(cfg.LightChainLimit, gcRunInfo)
h.RecordAccessor = Records
h.RecordModifier = Records
h.JetCoordinator = Coordinator
@@ -813,17 +813,20 @@ func initWithBadger(
func newComponents(
ctx context.Context,
- cfg configuration.Configuration,
+ cfg configuration.ConfigHolder,
genesisCfg genesis.HeavyConfig,
genesisOptions genesis.Options,
genesisOnly bool,
apiOptions api.Options,
) (*components, error) {
- if cfg.Ledger.IsPostgresBase {
- return initWithPostgres(ctx, cfg, genesisCfg, genesisOptions, genesisOnly, apiOptions)
- }
-
- return initWithBadger(ctx, cfg, genesisCfg, genesisOptions, genesisOnly, apiOptions)
+ heavyCfg := cfg.GetNodeConfig()
+ switch realCfg := heavyCfg.(type) {
+ case *configuration.ConfigHeavyPg:
+ return initWithPostgres(ctx, *realCfg, genesisCfg, genesisOptions, genesisOnly, apiOptions)
+ case *configuration.HeavyBadgerConfig:
+ return initWithBadger(ctx, *realCfg, genesisCfg, genesisOptions, genesisOnly, apiOptions)
+ }
+ return nil, errors.New("can't start heavy, db configuration error")
}
func (c *components) Start(ctx context.Context) error {
diff --git a/server/internal/heavy/components_test.go b/server/internal/heavy/components_test.go
index 956b890adc..8da23f9d38 100644
--- a/server/internal/heavy/components_test.go
+++ b/server/internal/heavy/components_test.go
@@ -30,7 +30,7 @@ func TestComponents(t *testing.T) {
ctx := inslogger.UpdateLogger(context.Background(), func(logger insolar.Logger) (insolar.Logger, error) {
return logger.Copy().WithBuffer(100, false).Build()
})
- cfg := configuration.NewConfiguration()
+ cfg := configuration.NewHeavyBadgerConfig()
cfg.KeysPath = "testdata/bootstrap_keys.json"
cfg.CertificatePath = "testdata/certificate.json"
cfg.Metrics.ListenAddress = "0.0.0.0:0"
@@ -41,6 +41,10 @@ func TestComponents(t *testing.T) {
cfg.Ledger.Storage.DataDirectory = tmpdir
cfg.Exporter.Addr = ":0"
- _, err = newComponents(ctx, cfg, genesis.HeavyConfig{Skip: true}, genesis.Options{}, false, api.Options{})
+ holder := &configuration.HeavyBadgerHolder{
+ Configuration: &cfg,
+ }
+
+ _, err = newComponents(ctx, holder, genesis.HeavyConfig{Skip: true}, genesis.Options{}, false, api.Options{})
require.NoError(t, err)
}
diff --git a/server/internal/heavy/server.go b/server/internal/heavy/server.go
index 4753ae3f01..4401cab18b 100644
--- a/server/internal/heavy/server.go
+++ b/server/internal/heavy/server.go
@@ -26,7 +26,7 @@ import (
)
type Server struct {
- cfgPath string
+ cfgHolder configuration.ConfigHolder
genesisCfgPath string
genesisOptions genesis.Options
genesisOnly bool
@@ -34,14 +34,14 @@ type Server struct {
}
func New(
- cfgPath string,
+ cfgHolder configuration.ConfigHolder,
genesisCfgPath string,
genesisOptions genesis.Options,
genesisOnly bool,
apiOptions api.Options,
) *Server {
return &Server{
- cfgPath: cfgPath,
+ cfgHolder: cfgHolder,
genesisCfgPath: genesisCfgPath,
genesisOptions: genesisOptions,
genesisOnly: genesisOnly,
@@ -50,17 +50,6 @@ func New(
}
func (s *Server) Serve() {
- cfgHolder := configuration.NewHolder()
- var err error
- if len(s.cfgPath) != 0 {
- err = cfgHolder.LoadFromFile(s.cfgPath)
- } else {
- err = cfgHolder.Load()
- }
- if err != nil {
- log.Fatalf("failed to load configuration: %v", err.Error())
- }
-
b, err := ioutil.ReadFile(s.genesisCfgPath)
if err != nil {
log.Fatalf("failed to load genesis configuration from file: %v", s.genesisCfgPath)
@@ -71,10 +60,10 @@ func (s *Server) Serve() {
log.Fatalf("failed to parse genesis configuration from file: %v", s.genesisCfgPath)
}
- cfg := &cfgHolder.Configuration
+ cfg := s.cfgHolder.GetGenericConfig()
fmt.Println("Version: ", version.GetFullVersion())
- fmt.Println("Starts with configuration:\n", configuration.ToString(cfgHolder.Configuration))
+ fmt.Println("Starts with configuration:\n", configuration.ToString(s.cfgHolder.GetNodeConfig()))
var (
ctx = context.Background()
@@ -86,7 +75,7 @@ func (s *Server) Serve() {
nodeRole = "heavy_material"
nodeReference = ""
)
- certManager, err := initTemporaryCertificateManager(ctx, cfg)
+ certManager, err := initTemporaryCertificateManager(ctx, &cfg)
if err != nil {
log.Warn("Failed to initialize nodeRef, nodeRole fields: ", err.Error())
} else {
@@ -98,7 +87,7 @@ func (s *Server) Serve() {
log.InitTicker()
}
- cmp, err := newComponents(ctx, *cfg, genesisCfg, s.genesisOptions, s.genesisOnly, s.apiOptions)
+ cmp, err := newComponents(ctx, s.cfgHolder, genesisCfg, s.genesisOptions, s.genesisOnly, s.apiOptions)
fatal(ctx, err, "failed to create components")
if cfg.Tracer.Jaeger.AgentEndpoint != "" {
diff --git a/server/internal/light/components.go b/server/internal/light/components.go
index 93beb673a2..fe85306de5 100644
--- a/server/internal/light/components.go
+++ b/server/internal/light/components.go
@@ -50,7 +50,7 @@ type components struct {
cleaner executor.Cleaner
}
-func initTemporaryCertificateManager(ctx context.Context, cfg *configuration.Configuration) (*certificate.CertificateManager, error) {
+func initTemporaryCertificateManager(ctx context.Context, cfg *configuration.LightConfig) (*certificate.CertificateManager, error) {
earlyComponents := component.NewManager(nil)
keyStore, err := keystore.NewKeyStore(cfg.KeysPath)
@@ -78,7 +78,7 @@ func initTemporaryCertificateManager(ctx context.Context, cfg *configuration.Con
return certManager, nil
}
-func newComponents(ctx context.Context, cfg configuration.Configuration, apiOptions api.Options) (*components, error) {
+func newComponents(ctx context.Context, cfg configuration.LightConfig, apiOptions api.Options) (*components, error) {
// Cryptography.
var (
KeyProcessor insolar.KeyProcessor
@@ -142,7 +142,7 @@ func newComponents(ctx context.Context, cfg configuration.Configuration, apiOpti
{
var err error
// External communication.
- NetworkService, err = servicenetwork.NewServiceNetwork(cfg, comps.cmp)
+ NetworkService, err = servicenetwork.NewServiceNetwork(cfg.Host, comps.cmp)
if err != nil {
return nil, errors.Wrap(err, "failed to start Network")
}
@@ -160,7 +160,7 @@ func newComponents(ctx context.Context, cfg configuration.Configuration, apiOpti
Pulses = pulse.NewStorageMem()
Jets = jet.NewStore()
- c := jetcoordinator.NewJetCoordinator(cfg.Ledger.LightChainLimit, *CertManager.GetCertificate().GetNodeRef())
+ c := jetcoordinator.NewJetCoordinator(cfg.LightChainLimit, *CertManager.GetCertificate().GetNodeRef())
c.PulseCalculator = Pulses
c.PulseAccessor = Pulses
c.JetAccessor = Jets
@@ -288,7 +288,7 @@ func newComponents(ctx context.Context, cfg configuration.Configuration, apiOpti
Pulses,
indexes,
filamentCalculator,
- conf.LightChainLimit,
+ cfg.LightChainLimit,
conf.CleanerDelay,
conf.FilamentCacheLimit,
)
@@ -315,12 +315,12 @@ func newComponents(ctx context.Context, cfg configuration.Configuration, apiOpti
indexes,
Pulses,
Jets,
- conf.LightChainLimit,
+ cfg.LightChainLimit,
Sender,
)
stateIniter := executor.NewStateIniter(
- conf, Jets, hotWaitReleaser, drops, Nodes, Sender, Pulses, Pulses, jetCalculator, indexes,
+ cfg.LightChainLimit, Jets, hotWaitReleaser, drops, Nodes, Sender, Pulses, Pulses, jetCalculator, indexes,
)
dep := proc.NewDependencies(
diff --git a/server/internal/light/components_test.go b/server/internal/light/components_test.go
index 3e57403fea..0ef2cab53e 100644
--- a/server/internal/light/components_test.go
+++ b/server/internal/light/components_test.go
@@ -22,7 +22,7 @@ func TestComponents(t *testing.T) {
ctx := inslogger.UpdateLogger(context.Background(), func(logger insolar.Logger) (insolar.Logger, error) {
return logger.Copy().WithBuffer(100, false).Build()
})
- cfg := configuration.NewConfiguration()
+ cfg := configuration.NewLightConfig()
cfg.KeysPath = "testdata/bootstrap_keys.json"
cfg.CertificatePath = "testdata/certificate.json"
cfg.Metrics.ListenAddress = "0.0.0.0:0"
diff --git a/server/internal/light/server.go b/server/internal/light/server.go
index c9ca9b847e..be38e0faa2 100644
--- a/server/internal/light/server.go
+++ b/server/internal/light/server.go
@@ -23,32 +23,22 @@ import (
)
type Server struct {
- cfgPath string
+ cfgHolder *configuration.LightHolder
apiOptions api.Options
}
-func New(cfgPath string, apiOptions api.Options) *Server {
+func New(cfgHolder *configuration.LightHolder, apiOptions api.Options) *Server {
return &Server{
- cfgPath: cfgPath,
+ cfgHolder: cfgHolder,
apiOptions: apiOptions,
}
}
func (s *Server) Serve() {
- cfgHolder := configuration.NewHolder()
- var err error
- if len(s.cfgPath) != 0 {
- err = cfgHolder.LoadFromFile(s.cfgPath)
- } else {
- err = cfgHolder.Load()
- }
- if err != nil {
- log.Warn("failed to load configuration from file: ", err.Error())
- }
- cfg := &cfgHolder.Configuration
+ cfg := *s.cfgHolder.Configuration
fmt.Println("Version: ", version.GetFullVersion())
- fmt.Println("Starts with configuration:\n", configuration.ToString(cfgHolder.Configuration))
+ fmt.Println("Starts with configuration:\n", configuration.ToString(s.cfgHolder.Configuration))
var (
ctx = context.Background()
@@ -60,7 +50,7 @@ func (s *Server) Serve() {
nodeRole = "light_material"
nodeReference = ""
)
- certManager, err := initTemporaryCertificateManager(ctx, cfg)
+ certManager, err := initTemporaryCertificateManager(ctx, &cfg)
if err != nil {
log.Warn("Failed to initialize nodeRef, nodeRole fields: ", err.Error())
} else {
@@ -72,7 +62,7 @@ func (s *Server) Serve() {
log.InitTicker()
}
- cmp, err := newComponents(ctx, *cfg, s.apiOptions)
+ cmp, err := newComponents(ctx, cfg, s.apiOptions)
fatal(ctx, err, "failed to create components")
if cfg.Tracer.Jaeger.AgentEndpoint != "" {
diff --git a/server/internal/virtual/components.go b/server/internal/virtual/components.go
index 41dfa297e5..72dfb7997c 100644
--- a/server/internal/virtual/components.go
+++ b/server/internal/virtual/components.go
@@ -48,7 +48,7 @@ type bootstrapComponents struct {
KeyProcessor insolar.KeyProcessor
}
-func initBootstrapComponents(ctx context.Context, cfg configuration.Configuration) bootstrapComponents {
+func initBootstrapComponents(ctx context.Context, cfg configuration.VirtualConfig) bootstrapComponents {
earlyComponents := component.NewManager(nil)
keyStore, err := keystore.NewKeyStore(cfg.KeysPath)
@@ -71,7 +71,7 @@ func initBootstrapComponents(ctx context.Context, cfg configuration.Configuratio
func initCertificateManager(
ctx context.Context,
- cfg configuration.Configuration,
+ cfg configuration.VirtualConfig,
cryptographyService insolar.CryptographyService,
keyProcessor insolar.KeyProcessor,
) *certificate.CertificateManager {
@@ -90,7 +90,7 @@ func initCertificateManager(
// initComponents creates and links all insolard components
func initComponents(
ctx context.Context,
- cfg configuration.Configuration,
+ cfg configuration.VirtualConfig,
cryptographyService insolar.CryptographyService,
pcs insolar.PlatformCryptographyScheme,
keyStore insolar.KeyStore,
@@ -117,12 +117,12 @@ func initComponents(
publisher = internal.PublisherWrapper(ctx, cm, cfg.Introspection, publisher)
}
- nw, err := servicenetwork.NewServiceNetwork(cfg, cm)
+ nw, err := servicenetwork.NewServiceNetwork(cfg.Host, cm)
checkError(ctx, err, "failed to start Network")
metricsComp := metrics.NewMetrics(cfg.Metrics, metrics.GetInsolarRegistry("virtual"), "virtual")
- jc := jetcoordinator.NewJetCoordinator(cfg.Ledger.LightChainLimit, *certManager.GetCertificate().GetNodeRef())
+ jc := jetcoordinator.NewJetCoordinator(cfg.LightChainLimit, *certManager.GetCertificate().GetNodeRef())
pulses := pulse.NewStorageMem()
b := bus.NewBus(cfg.Bus, publisher, pulses, jc, pcs)
diff --git a/server/internal/virtual/components_test.go b/server/internal/virtual/components_test.go
index 3cfa844eb5..a66958965c 100644
--- a/server/internal/virtual/components_test.go
+++ b/server/internal/virtual/components_test.go
@@ -24,7 +24,7 @@ func TestComponents(t *testing.T) {
ctx := inslogger.UpdateLogger(context.Background(), func(logger insolar.Logger) (insolar.Logger, error) {
return logger.Copy().WithBuffer(100, false).Build()
})
- cfg := configuration.NewConfiguration()
+ cfg := configuration.NewVirtualConfig()
cfg.KeysPath = "testdata/bootstrap_keys.json"
cfg.CertificatePath = "testdata/certificate.json"
cfg.Metrics.ListenAddress = "0.0.0.0:0"
diff --git a/server/internal/virtual/server.go b/server/internal/virtual/server.go
index 756f28800f..7fd5b94432 100644
--- a/server/internal/virtual/server.go
+++ b/server/internal/virtual/server.go
@@ -23,41 +23,31 @@ import (
)
type Server struct {
- cfgPath string
+ cfgHolder *configuration.VirtualHolder
builtinContracts builtin.BuiltinContracts
apiOptions api.Options
}
-func New(cfgPath string, builtinContracts builtin.BuiltinContracts, apiOptions api.Options) *Server {
+func New(cfgHolder *configuration.VirtualHolder, builtinContracts builtin.BuiltinContracts, apiOptions api.Options) *Server {
return &Server{
- cfgPath: cfgPath,
+ cfgHolder: cfgHolder,
builtinContracts: builtinContracts,
apiOptions: apiOptions,
}
}
func (s *Server) Serve() {
- cfgHolder := configuration.NewHolder()
var err error
- if len(s.cfgPath) != 0 {
- err = cfgHolder.LoadFromFile(s.cfgPath)
- } else {
- err = cfgHolder.Load()
- }
- if err != nil {
- log.Warn("failed to load configuration from file: ", err.Error())
- }
-
- cfg := &cfgHolder.Configuration
+ cfg := *s.cfgHolder.Configuration
fmt.Println("Version: ", version.GetFullVersion())
- fmt.Println("Starts with configuration:\n", configuration.ToString(cfgHolder.Configuration))
+ fmt.Println("Starts with configuration:\n", configuration.ToString(s.cfgHolder.Configuration))
ctx := context.Background()
- bootstrapComponents := initBootstrapComponents(ctx, *cfg)
+ bootstrapComponents := initBootstrapComponents(ctx, cfg)
certManager := initCertificateManager(
ctx,
- *cfg,
+ cfg,
bootstrapComponents.CryptographyService,
bootstrapComponents.KeyProcessor,
)
@@ -76,7 +66,7 @@ func (s *Server) Serve() {
cm, stopWatermill := initComponents(
ctx,
- *cfg,
+ cfg,
bootstrapComponents.CryptographyService,
bootstrapComponents.PlatformCryptographyScheme,
bootstrapComponents.KeyStore,
diff --git a/server/server.go b/server/server.go
index 1d89000750..e1129ff63d 100644
--- a/server/server.go
+++ b/server/server.go
@@ -8,6 +8,7 @@ package server
import (
"github.com/insolar/insolar/api"
"github.com/insolar/insolar/applicationbase/genesis"
+ "github.com/insolar/insolar/configuration"
"github.com/insolar/insolar/logicrunner/builtin"
"github.com/insolar/insolar/server/internal/heavy"
"github.com/insolar/insolar/server/internal/light"
@@ -19,23 +20,22 @@ type Server interface {
}
// NewLightServer creates instance of Server for node with Light role
-func NewLightServer(cfgPath string, apiOptions api.Options) Server {
- return light.New(cfgPath, apiOptions)
+func NewLightServer(cfgHolder *configuration.LightHolder, apiOptions api.Options) Server {
+ return light.New(cfgHolder, apiOptions)
}
// NewHeavyServer creates instance of Server for node with Heavy role
func NewHeavyServer(
- cfgPath string,
+ cfgHolder configuration.ConfigHolder,
genesisCfgPath string,
genesisOptions genesis.Options,
genesisOnly bool,
apiOptions api.Options,
) Server {
- return heavy.New(cfgPath, genesisCfgPath, genesisOptions, genesisOnly, apiOptions)
+ return heavy.New(cfgHolder, genesisCfgPath, genesisOptions, genesisOnly, apiOptions)
}
// NewVirtualServer creates instance of Server for node with Virtual role
-func NewVirtualServer(cfgPath string, builtinContracts builtin.BuiltinContracts, apiOptions api.Options,
-) Server {
- return virtual.New(cfgPath, builtinContracts, apiOptions)
+func NewVirtualServer(cfgHolder *configuration.VirtualHolder, builtinContracts builtin.BuiltinContracts, apiOptions api.Options) Server {
+ return virtual.New(cfgHolder, builtinContracts, apiOptions)
}
diff --git a/vendor/github.com/insolar/insconfig/.gitignore b/vendor/github.com/insolar/insconfig/.gitignore
new file mode 100644
index 0000000000..66fd13c903
--- /dev/null
+++ b/vendor/github.com/insolar/insconfig/.gitignore
@@ -0,0 +1,15 @@
+# Binaries for programs and plugins
+*.exe
+*.exe~
+*.dll
+*.so
+*.dylib
+
+# Test binary, built with `go test -c`
+*.test
+
+# Output of the go coverage tool, specifically when used with LiteIDE
+*.out
+
+# Dependency directories (remove the comment below to include it)
+# vendor/
diff --git a/vendor/github.com/insolar/insconfig/README.md b/vendor/github.com/insolar/insconfig/README.md
new file mode 100644
index 0000000000..fbaec9d381
--- /dev/null
+++ b/vendor/github.com/insolar/insconfig/README.md
@@ -0,0 +1,92 @@
+# insconfig
+Config management library.
+This is the wrapper on https://github.com/spf13/viper library
+
+Key features:
+- .yaml format
+- No default config path, path is explicitly set by --config/-c flag. Optionally you can override this by implementing ConfigPathGetter (look at tests)
+- Environment overrides file values
+- Can use only ENV, without file at all
+- Optionally prints config to log on start
+- No default values, all values are set explicitly, if not - returns error
+- No unnecessary values (both in file and ENV), if not - returns error
+- Supports custom flags, go flags and pflags
+- Doesn't support overriding config by flags
+- [wip] Generates empty yaml file with descriptions
+- [wip] By default adds 2 flags --config и --gen-config
+- Doesn't support overriding config on runtime
+- Supports custom viper decode hooks
+
+# Running example
+```
+go run ./example/example.go --config="./example/example_config.yaml"
+```
+
+# Usage
+
+With custom go flags (from example.go)
+```go
+ var testflag1 = flag.String("testflag1", "", "testflag1")
+ mconf := Config{}
+ params := insconfig.Params{
+ EnvPrefix: "example",
+ ConfigPathGetter: &insconfig.FlagPathGetter{
+ GoFlags: flag.CommandLine,
+ },
+ }
+ insConfigurator := insconfig.New(params)
+ _ = insConfigurator.Load(&mconf)
+ fmt.Println(testflag1)
+```
+
+With custom spf13/pflags
+```go
+ var testflag1 = pflag.String("testflag1", "", "testflag1")
+ mconf := Config{}
+ params := insconfig.Params{
+ EnvPrefix: "example",
+ ConfigPathGetter: &insconfig.PFlagPathGetter{
+ PFlags: pflag.CommandLine,
+ },
+ }
+ insConfigurator := insconfig.New(params)
+ _ = insConfigurator.Load(&mconf)
+ fmt.Println(testflag1)
+```
+
+With spf13/cobra. Cobra doesn't provide tools to manage flags parsing, so you need to add config flag yourself
+
+```go
+func main () {
+ var configPath string
+ rootCmd := &cobra.Command{
+ Use: "insolard",
+ }
+ rootCmd.PersistentFlags().StringVarP(&configPath, "config", "c", "", "path to config file")
+ _ = rootCmd.MarkPersistentFlagRequired("config")
+ err := rootCmd.Execute()
+
+ // ...
+
+ // To set your path from flag to insconfig you need to implement simple ConfigPathGetter interface and return path
+ type stringPathGetter struct {
+ Path string
+ }
+
+ func (g *stringPathGetter) GetConfigPath() string {
+ return g.Path
+ }
+}
+
+func read(){
+ cfg := ConfigStruct{}
+ params := insconfig.Params{
+ EnvPrefix: "InsolarEnvPrefix",
+ ConfigPathGetter: &stringPathGetter{Path: configPath},
+ FileRequired: false,
+ }
+ insConfigurator := insconfig.NewInsConfigurator(h.Params)
+ err := insConfigurator.Load(&cfg)
+ println(insconfig.ToString(cfg))
+}
+```
\ No newline at end of file
diff --git a/vendor/github.com/insolar/insconfig/config_path_getters.go b/vendor/github.com/insolar/insconfig/config_path_getters.go
new file mode 100644
index 0000000000..074f478d16
--- /dev/null
+++ b/vendor/github.com/insolar/insconfig/config_path_getters.go
@@ -0,0 +1,48 @@
+package insconfig
+
+import (
+ goflag "flag"
+
+ flag "github.com/spf13/pflag"
+)
+
+// DefaultPathGetter adds "--config" flag and read path from it
+type DefaultPathGetter struct {
+ GoFlags *goflag.FlagSet
+}
+
+func (g *DefaultPathGetter) GetConfigPath() string {
+ configPath := flag.String("config", "", "path to config")
+ flag.Parse()
+ return *configPath
+}
+
+// FlagPathGetter made for go flags compatibility
+// Adds "--config" flag and read path from it, custom go flags should be created before and set to GoFlags
+type FlagPathGetter struct {
+ GoFlags *goflag.FlagSet
+}
+
+func (g *FlagPathGetter) GetConfigPath() string {
+ if g.GoFlags != nil {
+ flag.CommandLine.AddGoFlagSet(g.GoFlags)
+ }
+ configPath := flag.String("config", "", "path to config")
+ flag.Parse()
+ return *configPath
+}
+
+// PFlagPathGetter made for spf13/pflags compatibility.
+// Adds "--config" flag and read path from it, custom pflags should be created before and set to PFlags
+type PFlagPathGetter struct {
+ PFlags *flag.FlagSet
+}
+
+func (g *PFlagPathGetter) GetConfigPath() string {
+ if g.PFlags != nil {
+ flag.CommandLine.AddFlagSet(g.PFlags)
+ }
+ configPath := flag.String("config", "", "path to config")
+ flag.Parse()
+ return *configPath
+}
diff --git a/vendor/github.com/insolar/insconfig/configurator.go b/vendor/github.com/insolar/insconfig/configurator.go
new file mode 100644
index 0000000000..655432a152
--- /dev/null
+++ b/vendor/github.com/insolar/insconfig/configurator.go
@@ -0,0 +1,215 @@
+//
+// Copyright 2019 Insolar Technologies GmbH
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package insconfig
+
+import (
+ "fmt"
+ "os"
+ "reflect"
+ "strings"
+
+ "github.com/mitchellh/mapstructure"
+ "github.com/pkg/errors"
+ "github.com/spf13/viper"
+ "gopkg.in/yaml.v2"
+)
+
+// Params for config parsing
+type Params struct {
+ // EnvPrefix is a prefix for environment variables
+ EnvPrefix string
+ // ViperHooks is custom viper decoding hooks
+ ViperHooks []mapstructure.DecodeHookFunc
+ // ConfigPathGetter should return config path
+ ConfigPathGetter ConfigPathGetter
+ // FileNotRequired - do not return error on file not found
+ FileNotRequired bool
+}
+
+// ConfigPathGetter - implement this if you don't want to use config path from --config flag
+type ConfigPathGetter interface {
+ GetConfigPath() string
+}
+
+type insConfigurator struct {
+ params Params
+ viper *viper.Viper
+}
+
+// New creates new insConfigurator with params
+func New(params Params) insConfigurator {
+ return insConfigurator{
+ params: params,
+ viper: viper.New(),
+ }
+}
+
+// Load loads configuration from path, env and makes checks
+// configStruct is a pointer to your config
+func (i *insConfigurator) Load(configStruct interface{}) error {
+ if i.params.EnvPrefix == "" {
+ return errors.New("EnvPrefix should be defined")
+ }
+
+ configPath := i.params.ConfigPathGetter.GetConfigPath()
+ return i.load(configPath, configStruct)
+}
+
+func (i *insConfigurator) load(path string, configStruct interface{}) error {
+
+ i.viper.AutomaticEnv()
+ i.viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
+ i.viper.SetEnvPrefix(i.params.EnvPrefix)
+
+ i.viper.SetConfigFile(path)
+ if err := i.viper.ReadInConfig(); err != nil {
+ if !i.params.FileNotRequired {
+ return err
+ }
+ fmt.Printf("failed to load config from '%s'\n", path)
+ }
+ i.params.ViperHooks = append(i.params.ViperHooks, mapstructure.StringToTimeDurationHookFunc(), mapstructure.StringToSliceHookFunc(","))
+ err := i.viper.UnmarshalExact(configStruct, viper.DecodeHook(mapstructure.ComposeDecodeHookFunc(
+ i.params.ViperHooks...,
+ )))
+ if err != nil {
+ return errors.Wrapf(err, "failed to unmarshal config file into configuration structure")
+ }
+ configStructKeys, err := i.checkAllValuesIsSet(configStruct)
+ if err != nil {
+ return err
+ }
+
+ if err := i.checkNoExtraENVValues(configStructKeys); err != nil {
+ return err
+ }
+
+ // Second Unmarshal needed because of bug https://github.com/spf13/viper/issues/761
+ // This should be evaluated after manual values overriding is done
+ err = i.viper.UnmarshalExact(configStruct, viper.DecodeHook(mapstructure.ComposeDecodeHookFunc(
+ i.params.ViperHooks...,
+ )))
+ if err != nil {
+ return errors.Wrapf(err, "failed to unmarshal config file into configuration structure 2")
+ }
+ return nil
+}
+
+func (i *insConfigurator) checkNoExtraENVValues(structKeys []string) error {
+ var errorKeys []string
+ prefixLen := len(i.params.EnvPrefix)
+ for _, e := range os.Environ() {
+ if len(e) > prefixLen && e[0:prefixLen]+"_" == strings.ToUpper(i.params.EnvPrefix)+"_" {
+ kv := strings.SplitN(e, "=", 2)
+ key := strings.ReplaceAll(strings.Replace(strings.ToLower(kv[0]), i.params.EnvPrefix+"_", "", 1), "_", ".")
+ if stringInSlice(key, structKeys) {
+ // This manually sets value from ENV and overrides everything, this temporarily fix issue https://github.com/spf13/viper/issues/761
+ i.viper.Set(key, kv[1])
+ } else {
+ errorKeys = append(errorKeys, key)
+ }
+ }
+ }
+ if len(errorKeys) > 0 {
+ return errors.New(fmt.Sprintf("Wrong config keys found in ENV: %s", strings.Join(errorKeys, ", ")))
+ }
+ return nil
+}
+
+func (i *insConfigurator) checkAllValuesIsSet(configStruct interface{}) ([]string, error) {
+ var errorKeys []string
+ names := deepFieldNames(configStruct, "")
+ allKeys := i.viper.AllKeys()
+ for _, keyName := range names {
+ if !i.viper.IsSet(keyName) {
+ // Due to a bug https://github.com/spf13/viper/issues/447 we can't use InConfig, so
+ if !stringInSlice(keyName, allKeys) {
+ errorKeys = append(errorKeys, keyName)
+ }
+ // Value of this key is "null" but it's set in config file
+ }
+ }
+ if len(errorKeys) > 0 {
+ return nil, errors.New(fmt.Sprintf("Keys is not defined in config: %s", strings.Join(errorKeys, ", ")))
+ }
+ return names, nil
+}
+
+func stringInSlice(a string, list []string) bool {
+ for _, b := range list {
+ if strings.ToLower(b) == strings.ToLower(a) {
+ return true
+ }
+ }
+ return false
+}
+
+func deepFieldNames(iface interface{}, prefix string) []string {
+ names := make([]string, 0)
+ v := reflect.ValueOf(iface)
+ ifv := reflect.Indirect(v)
+ s := ifv.Type()
+
+ for i := 0; i < s.NumField(); i++ {
+ v := ifv.Field(i)
+ tagValue := ifv.Type().Field(i).Tag.Get("mapstructure")
+ tagParts := strings.Split(tagValue, ",")
+
+ // If "squash" is specified in the tag, we squash the field down.
+ squash := false
+ for _, tag := range tagParts[1:] {
+ if tag == "squash" {
+ squash = true
+ break
+ }
+ }
+
+ switch v.Kind() {
+ case reflect.Struct:
+ newPrefix := ""
+ currPrefix := ""
+ if !squash {
+ currPrefix = ifv.Type().Field(i).Name
+ }
+ if prefix != "" {
+ newPrefix = strings.Join([]string{prefix, currPrefix}, ".")
+ } else {
+ newPrefix = currPrefix
+ }
+
+ names = append(names, deepFieldNames(v.Interface(), newPrefix)...)
+ default:
+ prefWithPoint := ""
+ if prefix != "" {
+ prefWithPoint = prefix + "."
+ }
+ names = append(names, prefWithPoint+ifv.Type().Field(i).Name)
+ }
+ }
+
+ return names
+}
+
+// ToYaml returns yaml marshalled struct
+func (i *insConfigurator) ToYaml(c interface{}) string {
+ // todo clean password
+ out, err := yaml.Marshal(c)
+ if err != nil {
+ return fmt.Sprintf("failed to marshal config structure: %v", err)
+ }
+ return string(out)
+}
diff --git a/vendor/github.com/insolar/insconfig/go.mod b/vendor/github.com/insolar/insconfig/go.mod
new file mode 100644
index 0000000000..8c93adc582
--- /dev/null
+++ b/vendor/github.com/insolar/insconfig/go.mod
@@ -0,0 +1,12 @@
+module github.com/insolar/insconfig
+
+go 1.12
+
+require (
+ github.com/mitchellh/mapstructure v1.1.2
+ github.com/pkg/errors v0.9.1
+ github.com/spf13/pflag v1.0.5
+ github.com/spf13/viper v1.6.2
+ github.com/stretchr/testify v1.4.0
+ gopkg.in/yaml.v2 v2.2.8
+)
diff --git a/vendor/github.com/insolar/insconfig/go.sum b/vendor/github.com/insolar/insconfig/go.sum
new file mode 100644
index 0000000000..93db162ac9
--- /dev/null
+++ b/vendor/github.com/insolar/insconfig/go.sum
@@ -0,0 +1,159 @@
+cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
+github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
+github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
+github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
+github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
+github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
+github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
+github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
+github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
+github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
+github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
+github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
+github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
+github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
+github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
+github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
+github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
+github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
+github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
+github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
+github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
+github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
+github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
+github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
+github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
+github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
+github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
+github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
+github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
+github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
+github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
+github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
+github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
+github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
+github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
+github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
+github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
+github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
+github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
+github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
+github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
+github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
+github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
+github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
+github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
+github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
+github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
+github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
+github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
+github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
+github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
+github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
+github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/spf13/viper v1.6.2 h1:7aKfF+e8/k68gda3LOjo5RxiUqddoFxVq4BKBPrxk5E=
+github.com/spf13/viper v1.6.2/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
+github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
+github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
+github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
+github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
+github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
+go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
+go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
+go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
+go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
+golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
+gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
+gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
+gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
+gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
+gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
diff --git a/vendor/github.com/insolar/insconfig/test_config.yaml b/vendor/github.com/insolar/insconfig/test_config.yaml
new file mode 100644
index 0000000000..b9c6728315
--- /dev/null
+++ b/vendor/github.com/insolar/insconfig/test_config.yaml
@@ -0,0 +1,6 @@
+level1text: text1
+level2:
+ level2text: text2
+ level3:
+ level3text: text3
+ nullstring: text
diff --git a/vendor/github.com/insolar/insconfig/test_config2.yaml b/vendor/github.com/insolar/insconfig/test_config2.yaml
new file mode 100644
index 0000000000..4940e829ae
--- /dev/null
+++ b/vendor/github.com/insolar/insconfig/test_config2.yaml
@@ -0,0 +1,6 @@
+level1text: text1
+level2:
+ level2text: text2
+ level3:
+ level3text: text3
+ nullstring: null
diff --git a/vendor/github.com/insolar/insconfig/test_config3.yaml b/vendor/github.com/insolar/insconfig/test_config3.yaml
new file mode 100644
index 0000000000..54ca87a867
--- /dev/null
+++ b/vendor/github.com/insolar/insconfig/test_config3.yaml
@@ -0,0 +1,7 @@
+level1text: text1
+level2:
+ level2text: text2
+ level3:
+ level3text: text3
+ nullstring: text
+level4: text4
diff --git a/vendor/github.com/insolar/insconfig/test_config_wrong.yaml b/vendor/github.com/insolar/insconfig/test_config_wrong.yaml
new file mode 100644
index 0000000000..63294c22a7
--- /dev/null
+++ b/vendor/github.com/insolar/insconfig/test_config_wrong.yaml
@@ -0,0 +1,7 @@
+level1text: text1
+level2:
+ level2text: text2
+ level3:
+ level3text: text3
+ nullstring: text
+nonexistent: value
diff --git a/vendor/github.com/insolar/insconfig/test_config_wrong2.yaml b/vendor/github.com/insolar/insconfig/test_config_wrong2.yaml
new file mode 100644
index 0000000000..6b50cc53a9
--- /dev/null
+++ b/vendor/github.com/insolar/insconfig/test_config_wrong2.yaml
@@ -0,0 +1,4 @@
+level2:
+ level2text: text2
+ level3:
+ level3text: text3
diff --git a/vendor/github.com/pkg/errors/.travis.yml b/vendor/github.com/pkg/errors/.travis.yml
index d4b92663ba..9159de03e0 100644
--- a/vendor/github.com/pkg/errors/.travis.yml
+++ b/vendor/github.com/pkg/errors/.travis.yml
@@ -1,15 +1,10 @@
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
+ - 1.12.x
+ - 1.13.x
- tip
script:
- - go test -v ./...
+ - make check
diff --git a/vendor/github.com/pkg/errors/Makefile b/vendor/github.com/pkg/errors/Makefile
new file mode 100644
index 0000000000..ce9d7cded6
--- /dev/null
+++ b/vendor/github.com/pkg/errors/Makefile
@@ -0,0 +1,44 @@
+PKGS := github.com/pkg/errors
+SRCDIRS := $(shell go list -f '{{.Dir}}' $(PKGS))
+GO := go
+
+check: test vet gofmt misspell unconvert staticcheck ineffassign unparam
+
+test:
+ $(GO) test $(PKGS)
+
+vet: | test
+ $(GO) vet $(PKGS)
+
+staticcheck:
+ $(GO) get honnef.co/go/tools/cmd/staticcheck
+ staticcheck -checks all $(PKGS)
+
+misspell:
+ $(GO) get github.com/client9/misspell/cmd/misspell
+ misspell \
+ -locale GB \
+ -error \
+ *.md *.go
+
+unconvert:
+ $(GO) get github.com/mdempsky/unconvert
+ unconvert -v $(PKGS)
+
+ineffassign:
+ $(GO) get github.com/gordonklaus/ineffassign
+ find $(SRCDIRS) -name '*.go' | xargs ineffassign
+
+pedantic: check errcheck
+
+unparam:
+ $(GO) get mvdan.cc/unparam
+ unparam ./...
+
+errcheck:
+ $(GO) get github.com/kisielk/errcheck
+ errcheck $(PKGS)
+
+gofmt:
+ @echo Checking code is gofmted
+ @test -z "$(shell gofmt -s -l -d -e $(SRCDIRS) | tee /dev/stderr)"
diff --git a/vendor/github.com/pkg/errors/README.md b/vendor/github.com/pkg/errors/README.md
index 6483ba2afb..54dfdcb12e 100644
--- a/vendor/github.com/pkg/errors/README.md
+++ b/vendor/github.com/pkg/errors/README.md
@@ -41,11 +41,18 @@ default:
[Read the package documentation for more information](https://godoc.org/github.com/pkg/errors).
+## Roadmap
+
+With the upcoming [Go2 error proposals](https://go.googlesource.com/proposal/+/master/design/go2draft.md) this package is moving into maintenance mode. The roadmap for a 1.0 release is as follows:
+
+- 0.9. Remove pre Go 1.9 and Go 1.10 support, address outstanding pull requests (if possible)
+- 1.0. Final release.
+
## 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.
+Because of the Go2 errors changes, this package is not accepting proposals for new functionality. With that said, we welcome pull requests, bug fixes and issue reports.
-Before proposing a change, please discuss your change by raising an issue.
+Before sending a PR, please discuss your change by raising an issue.
## License
diff --git a/vendor/github.com/pkg/errors/errors.go b/vendor/github.com/pkg/errors/errors.go
index 7421f326ff..161aea2582 100644
--- a/vendor/github.com/pkg/errors/errors.go
+++ b/vendor/github.com/pkg/errors/errors.go
@@ -82,7 +82,7 @@
//
// if err, ok := err.(stackTracer); ok {
// for _, f := range err.StackTrace() {
-// fmt.Printf("%+s:%d", f)
+// fmt.Printf("%+s:%d\n", f, f)
// }
// }
//
@@ -159,6 +159,9 @@ type withStack struct {
func (w *withStack) Cause() error { return w.error }
+// Unwrap provides compatibility for Go 1.13 error chains.
+func (w *withStack) Unwrap() error { return w.error }
+
func (w *withStack) Format(s fmt.State, verb rune) {
switch verb {
case 'v':
@@ -241,6 +244,9 @@ type withMessage struct {
func (w *withMessage) Error() string { return w.msg + ": " + w.cause.Error() }
func (w *withMessage) Cause() error { return w.cause }
+// Unwrap provides compatibility for Go 1.13 error chains.
+func (w *withMessage) Unwrap() error { return w.cause }
+
func (w *withMessage) Format(s fmt.State, verb rune) {
switch verb {
case 'v':
diff --git a/vendor/github.com/pkg/errors/go113.go b/vendor/github.com/pkg/errors/go113.go
new file mode 100644
index 0000000000..be0d10d0c7
--- /dev/null
+++ b/vendor/github.com/pkg/errors/go113.go
@@ -0,0 +1,38 @@
+// +build go1.13
+
+package errors
+
+import (
+ stderrors "errors"
+)
+
+// Is reports whether any error in err's chain matches target.
+//
+// The chain consists of err itself followed by the sequence of errors obtained by
+// repeatedly calling Unwrap.
+//
+// An error is considered to match a target if it is equal to that target or if
+// it implements a method Is(error) bool such that Is(target) returns true.
+func Is(err, target error) bool { return stderrors.Is(err, target) }
+
+// As finds the first error in err's chain that matches target, and if so, sets
+// target to that error value and returns true.
+//
+// The chain consists of err itself followed by the sequence of errors obtained by
+// repeatedly calling Unwrap.
+//
+// An error matches target if the error's concrete value is assignable to the value
+// pointed to by target, or if the error has a method As(interface{}) bool such that
+// As(target) returns true. In the latter case, the As method is responsible for
+// setting target.
+//
+// As will panic if target is not a non-nil pointer to either a type that implements
+// error, or to any interface type. As returns false if err is nil.
+func As(err error, target interface{}) bool { return stderrors.As(err, target) }
+
+// Unwrap returns the result of calling the Unwrap method on err, if err's
+// type contains an Unwrap method returning error.
+// Otherwise, Unwrap returns nil.
+func Unwrap(err error) error {
+ return stderrors.Unwrap(err)
+}
diff --git a/vendor/github.com/pkg/errors/stack.go b/vendor/github.com/pkg/errors/stack.go
index 2874a048cf..779a8348fb 100644
--- a/vendor/github.com/pkg/errors/stack.go
+++ b/vendor/github.com/pkg/errors/stack.go
@@ -5,10 +5,13 @@ import (
"io"
"path"
"runtime"
+ "strconv"
"strings"
)
// Frame represents a program counter inside a stack frame.
+// For historical reasons if Frame is interpreted as a uintptr
+// its value represents the program counter + 1.
type Frame uintptr
// pc returns the program counter for this frame;
@@ -37,6 +40,15 @@ func (f Frame) line() int {
return line
}
+// name returns the name of this function, if known.
+func (f Frame) name() string {
+ fn := runtime.FuncForPC(f.pc())
+ if fn == nil {
+ return "unknown"
+ }
+ return fn.Name()
+}
+
// Format formats the frame according to the fmt.Formatter interface.
//
// %s source file
@@ -54,22 +66,16 @@ func (f Frame) Format(s fmt.State, verb rune) {
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)
- }
+ io.WriteString(s, f.name())
+ io.WriteString(s, "\n\t")
+ io.WriteString(s, f.file())
default:
io.WriteString(s, path.Base(f.file()))
}
case 'd':
- fmt.Fprintf(s, "%d", f.line())
+ io.WriteString(s, strconv.Itoa(f.line()))
case 'n':
- name := runtime.FuncForPC(f.pc()).Name()
- io.WriteString(s, funcname(name))
+ io.WriteString(s, funcname(f.name()))
case 'v':
f.Format(s, 's')
io.WriteString(s, ":")
@@ -77,6 +83,16 @@ func (f Frame) Format(s fmt.State, verb rune) {
}
}
+// MarshalText formats a stacktrace Frame as a text string. The output is the
+// same as that of fmt.Sprintf("%+v", f), but without newlines or tabs.
+func (f Frame) MarshalText() ([]byte, error) {
+ name := f.name()
+ if name == "unknown" {
+ return []byte(name), nil
+ }
+ return []byte(fmt.Sprintf("%s %s:%d", name, f.file(), f.line())), nil
+}
+
// StackTrace is stack of Frames from innermost (newest) to outermost (oldest).
type StackTrace []Frame
@@ -94,16 +110,30 @@ func (st StackTrace) Format(s fmt.State, verb rune) {
switch {
case s.Flag('+'):
for _, f := range st {
- fmt.Fprintf(s, "\n%+v", f)
+ io.WriteString(s, "\n")
+ f.Format(s, verb)
}
case s.Flag('#'):
fmt.Fprintf(s, "%#v", []Frame(st))
default:
- fmt.Fprintf(s, "%v", []Frame(st))
+ st.formatSlice(s, verb)
}
case 's':
- fmt.Fprintf(s, "%s", []Frame(st))
+ st.formatSlice(s, verb)
+ }
+}
+
+// formatSlice will format this StackTrace into the given buffer as a slice of
+// Frame, only valid when called with '%s' or '%v'.
+func (st StackTrace) formatSlice(s fmt.State, verb rune) {
+ io.WriteString(s, "[")
+ for i, f := range st {
+ if i > 0 {
+ io.WriteString(s, " ")
+ }
+ f.Format(s, verb)
}
+ io.WriteString(s, "]")
}
// stack represents a stack of program counters.
diff --git a/vendor/github.com/spf13/pflag/.travis.yml b/vendor/github.com/spf13/pflag/.travis.yml
index f8a63b308b..00d04cb9b0 100644
--- a/vendor/github.com/spf13/pflag/.travis.yml
+++ b/vendor/github.com/spf13/pflag/.travis.yml
@@ -3,8 +3,9 @@ sudo: false
language: go
go:
- - 1.7.3
- - 1.8.1
+ - 1.9.x
+ - 1.10.x
+ - 1.11.x
- tip
matrix:
@@ -12,7 +13,7 @@ matrix:
- go: tip
install:
- - go get github.com/golang/lint/golint
+ - go get golang.org/x/lint/golint
- export PATH=$GOPATH/bin:$PATH
- go install ./...
diff --git a/vendor/github.com/spf13/pflag/README.md b/vendor/github.com/spf13/pflag/README.md
index b052414d12..7eacc5bdbe 100644
--- a/vendor/github.com/spf13/pflag/README.md
+++ b/vendor/github.com/spf13/pflag/README.md
@@ -86,8 +86,8 @@ fmt.Println("ip has value ", *ip)
fmt.Println("flagvar has value ", flagvar)
```
-There are helpers function to get values later if you have the FlagSet but
-it was difficult to keep up with all of the flag pointers in your code.
+There are helper functions available to get the value stored in a Flag if you have a FlagSet but find
+it difficult to keep up with all of the pointers in your code.
If you have a pflag.FlagSet with a flag called 'flagname' of type int you
can use GetInt() to get the int value. But notice that 'flagname' must exist
and it must be an int. GetString("flagname") will fail.
diff --git a/vendor/github.com/spf13/pflag/bool_slice.go b/vendor/github.com/spf13/pflag/bool_slice.go
index 5af02f1a75..3731370d6a 100644
--- a/vendor/github.com/spf13/pflag/bool_slice.go
+++ b/vendor/github.com/spf13/pflag/bool_slice.go
@@ -71,6 +71,44 @@ func (s *boolSliceValue) String() string {
return "[" + out + "]"
}
+func (s *boolSliceValue) fromString(val string) (bool, error) {
+ return strconv.ParseBool(val)
+}
+
+func (s *boolSliceValue) toString(val bool) string {
+ return strconv.FormatBool(val)
+}
+
+func (s *boolSliceValue) Append(val string) error {
+ i, err := s.fromString(val)
+ if err != nil {
+ return err
+ }
+ *s.value = append(*s.value, i)
+ return nil
+}
+
+func (s *boolSliceValue) Replace(val []string) error {
+ out := make([]bool, len(val))
+ for i, d := range val {
+ var err error
+ out[i], err = s.fromString(d)
+ if err != nil {
+ return err
+ }
+ }
+ *s.value = out
+ return nil
+}
+
+func (s *boolSliceValue) GetSlice() []string {
+ out := make([]string, len(*s.value))
+ for i, d := range *s.value {
+ out[i] = s.toString(d)
+ }
+ return out
+}
+
func boolSliceConv(val string) (interface{}, error) {
val = strings.Trim(val, "[]")
// Empty string would cause a slice with one (empty) entry
diff --git a/vendor/github.com/spf13/pflag/count.go b/vendor/github.com/spf13/pflag/count.go
index aa126e44d1..a0b2679f71 100644
--- a/vendor/github.com/spf13/pflag/count.go
+++ b/vendor/github.com/spf13/pflag/count.go
@@ -46,7 +46,7 @@ func (f *FlagSet) GetCount(name string) (int, error) {
// CountVar defines a count flag with specified name, default value, and usage string.
// The argument p points to an int variable in which to store the value of the flag.
-// A count flag will add 1 to its value evey time it is found on the command line
+// A count flag will add 1 to its value every time it is found on the command line
func (f *FlagSet) CountVar(p *int, name string, usage string) {
f.CountVarP(p, name, "", usage)
}
@@ -69,7 +69,7 @@ func CountVarP(p *int, name, shorthand string, usage string) {
// Count defines a count flag with specified name, default value, and usage string.
// The return value is the address of an int variable that stores the value of the flag.
-// A count flag will add 1 to its value evey time it is found on the command line
+// A count flag will add 1 to its value every time it is found on the command line
func (f *FlagSet) Count(name string, usage string) *int {
p := new(int)
f.CountVarP(p, name, "", usage)
diff --git a/vendor/github.com/spf13/pflag/duration_slice.go b/vendor/github.com/spf13/pflag/duration_slice.go
index 52c6b6dc10..badadda53f 100644
--- a/vendor/github.com/spf13/pflag/duration_slice.go
+++ b/vendor/github.com/spf13/pflag/duration_slice.go
@@ -51,6 +51,44 @@ func (s *durationSliceValue) String() string {
return "[" + strings.Join(out, ",") + "]"
}
+func (s *durationSliceValue) fromString(val string) (time.Duration, error) {
+ return time.ParseDuration(val)
+}
+
+func (s *durationSliceValue) toString(val time.Duration) string {
+ return fmt.Sprintf("%s", val)
+}
+
+func (s *durationSliceValue) Append(val string) error {
+ i, err := s.fromString(val)
+ if err != nil {
+ return err
+ }
+ *s.value = append(*s.value, i)
+ return nil
+}
+
+func (s *durationSliceValue) Replace(val []string) error {
+ out := make([]time.Duration, len(val))
+ for i, d := range val {
+ var err error
+ out[i], err = s.fromString(d)
+ if err != nil {
+ return err
+ }
+ }
+ *s.value = out
+ return nil
+}
+
+func (s *durationSliceValue) GetSlice() []string {
+ out := make([]string, len(*s.value))
+ for i, d := range *s.value {
+ out[i] = s.toString(d)
+ }
+ return out
+}
+
func durationSliceConv(val string) (interface{}, error) {
val = strings.Trim(val, "[]")
// Empty string would cause a slice with one (empty) entry
diff --git a/vendor/github.com/spf13/pflag/flag.go b/vendor/github.com/spf13/pflag/flag.go
index 9beeda8ecc..24a5036e95 100644
--- a/vendor/github.com/spf13/pflag/flag.go
+++ b/vendor/github.com/spf13/pflag/flag.go
@@ -57,9 +57,9 @@ that give one-letter shorthands for flags. You can use these by appending
var ip = flag.IntP("flagname", "f", 1234, "help message")
var flagvar bool
func init() {
- flag.BoolVarP("boolname", "b", true, "help message")
+ flag.BoolVarP(&flagvar, "boolname", "b", true, "help message")
}
- flag.VarP(&flagVar, "varname", "v", 1234, "help message")
+ flag.VarP(&flagval, "varname", "v", "help message")
Shorthand letters can be used with single dashes on the command line.
Boolean shorthand flags can be combined with other shorthand flags.
@@ -190,6 +190,18 @@ type Value interface {
Type() string
}
+// SliceValue is a secondary interface to all flags which hold a list
+// of values. This allows full control over the value of list flags,
+// and avoids complicated marshalling and unmarshalling to csv.
+type SliceValue interface {
+ // Append adds the specified value to the end of the flag value list.
+ Append(string) error
+ // Replace will fully overwrite any data currently in the flag value list.
+ Replace([]string) error
+ // GetSlice returns the flag value list as an array of strings.
+ GetSlice() []string
+}
+
// sortFlags returns the flags as a slice in lexicographical sorted order.
func sortFlags(flags map[NormalizedName]*Flag) []*Flag {
list := make(sort.StringSlice, len(flags))
diff --git a/vendor/github.com/spf13/pflag/float32_slice.go b/vendor/github.com/spf13/pflag/float32_slice.go
new file mode 100644
index 0000000000..caa352741a
--- /dev/null
+++ b/vendor/github.com/spf13/pflag/float32_slice.go
@@ -0,0 +1,174 @@
+package pflag
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+)
+
+// -- float32Slice Value
+type float32SliceValue struct {
+ value *[]float32
+ changed bool
+}
+
+func newFloat32SliceValue(val []float32, p *[]float32) *float32SliceValue {
+ isv := new(float32SliceValue)
+ isv.value = p
+ *isv.value = val
+ return isv
+}
+
+func (s *float32SliceValue) Set(val string) error {
+ ss := strings.Split(val, ",")
+ out := make([]float32, len(ss))
+ for i, d := range ss {
+ var err error
+ var temp64 float64
+ temp64, err = strconv.ParseFloat(d, 32)
+ if err != nil {
+ return err
+ }
+ out[i] = float32(temp64)
+
+ }
+ if !s.changed {
+ *s.value = out
+ } else {
+ *s.value = append(*s.value, out...)
+ }
+ s.changed = true
+ return nil
+}
+
+func (s *float32SliceValue) Type() string {
+ return "float32Slice"
+}
+
+func (s *float32SliceValue) String() string {
+ out := make([]string, len(*s.value))
+ for i, d := range *s.value {
+ out[i] = fmt.Sprintf("%f", d)
+ }
+ return "[" + strings.Join(out, ",") + "]"
+}
+
+func (s *float32SliceValue) fromString(val string) (float32, error) {
+ t64, err := strconv.ParseFloat(val, 32)
+ if err != nil {
+ return 0, err
+ }
+ return float32(t64), nil
+}
+
+func (s *float32SliceValue) toString(val float32) string {
+ return fmt.Sprintf("%f", val)
+}
+
+func (s *float32SliceValue) Append(val string) error {
+ i, err := s.fromString(val)
+ if err != nil {
+ return err
+ }
+ *s.value = append(*s.value, i)
+ return nil
+}
+
+func (s *float32SliceValue) Replace(val []string) error {
+ out := make([]float32, len(val))
+ for i, d := range val {
+ var err error
+ out[i], err = s.fromString(d)
+ if err != nil {
+ return err
+ }
+ }
+ *s.value = out
+ return nil
+}
+
+func (s *float32SliceValue) GetSlice() []string {
+ out := make([]string, len(*s.value))
+ for i, d := range *s.value {
+ out[i] = s.toString(d)
+ }
+ return out
+}
+
+func float32SliceConv(val string) (interface{}, error) {
+ val = strings.Trim(val, "[]")
+ // Empty string would cause a slice with one (empty) entry
+ if len(val) == 0 {
+ return []float32{}, nil
+ }
+ ss := strings.Split(val, ",")
+ out := make([]float32, len(ss))
+ for i, d := range ss {
+ var err error
+ var temp64 float64
+ temp64, err = strconv.ParseFloat(d, 32)
+ if err != nil {
+ return nil, err
+ }
+ out[i] = float32(temp64)
+
+ }
+ return out, nil
+}
+
+// GetFloat32Slice return the []float32 value of a flag with the given name
+func (f *FlagSet) GetFloat32Slice(name string) ([]float32, error) {
+ val, err := f.getFlagType(name, "float32Slice", float32SliceConv)
+ if err != nil {
+ return []float32{}, err
+ }
+ return val.([]float32), nil
+}
+
+// Float32SliceVar defines a float32Slice flag with specified name, default value, and usage string.
+// The argument p points to a []float32 variable in which to store the value of the flag.
+func (f *FlagSet) Float32SliceVar(p *[]float32, name string, value []float32, usage string) {
+ f.VarP(newFloat32SliceValue(value, p), name, "", usage)
+}
+
+// Float32SliceVarP is like Float32SliceVar, but accepts a shorthand letter that can be used after a single dash.
+func (f *FlagSet) Float32SliceVarP(p *[]float32, name, shorthand string, value []float32, usage string) {
+ f.VarP(newFloat32SliceValue(value, p), name, shorthand, usage)
+}
+
+// Float32SliceVar defines a float32[] flag with specified name, default value, and usage string.
+// The argument p points to a float32[] variable in which to store the value of the flag.
+func Float32SliceVar(p *[]float32, name string, value []float32, usage string) {
+ CommandLine.VarP(newFloat32SliceValue(value, p), name, "", usage)
+}
+
+// Float32SliceVarP is like Float32SliceVar, but accepts a shorthand letter that can be used after a single dash.
+func Float32SliceVarP(p *[]float32, name, shorthand string, value []float32, usage string) {
+ CommandLine.VarP(newFloat32SliceValue(value, p), name, shorthand, usage)
+}
+
+// Float32Slice defines a []float32 flag with specified name, default value, and usage string.
+// The return value is the address of a []float32 variable that stores the value of the flag.
+func (f *FlagSet) Float32Slice(name string, value []float32, usage string) *[]float32 {
+ p := []float32{}
+ f.Float32SliceVarP(&p, name, "", value, usage)
+ return &p
+}
+
+// Float32SliceP is like Float32Slice, but accepts a shorthand letter that can be used after a single dash.
+func (f *FlagSet) Float32SliceP(name, shorthand string, value []float32, usage string) *[]float32 {
+ p := []float32{}
+ f.Float32SliceVarP(&p, name, shorthand, value, usage)
+ return &p
+}
+
+// Float32Slice defines a []float32 flag with specified name, default value, and usage string.
+// The return value is the address of a []float32 variable that stores the value of the flag.
+func Float32Slice(name string, value []float32, usage string) *[]float32 {
+ return CommandLine.Float32SliceP(name, "", value, usage)
+}
+
+// Float32SliceP is like Float32Slice, but accepts a shorthand letter that can be used after a single dash.
+func Float32SliceP(name, shorthand string, value []float32, usage string) *[]float32 {
+ return CommandLine.Float32SliceP(name, shorthand, value, usage)
+}
diff --git a/vendor/github.com/spf13/pflag/float64_slice.go b/vendor/github.com/spf13/pflag/float64_slice.go
new file mode 100644
index 0000000000..85bf3073d5
--- /dev/null
+++ b/vendor/github.com/spf13/pflag/float64_slice.go
@@ -0,0 +1,166 @@
+package pflag
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+)
+
+// -- float64Slice Value
+type float64SliceValue struct {
+ value *[]float64
+ changed bool
+}
+
+func newFloat64SliceValue(val []float64, p *[]float64) *float64SliceValue {
+ isv := new(float64SliceValue)
+ isv.value = p
+ *isv.value = val
+ return isv
+}
+
+func (s *float64SliceValue) Set(val string) error {
+ ss := strings.Split(val, ",")
+ out := make([]float64, len(ss))
+ for i, d := range ss {
+ var err error
+ out[i], err = strconv.ParseFloat(d, 64)
+ if err != nil {
+ return err
+ }
+
+ }
+ if !s.changed {
+ *s.value = out
+ } else {
+ *s.value = append(*s.value, out...)
+ }
+ s.changed = true
+ return nil
+}
+
+func (s *float64SliceValue) Type() string {
+ return "float64Slice"
+}
+
+func (s *float64SliceValue) String() string {
+ out := make([]string, len(*s.value))
+ for i, d := range *s.value {
+ out[i] = fmt.Sprintf("%f", d)
+ }
+ return "[" + strings.Join(out, ",") + "]"
+}
+
+func (s *float64SliceValue) fromString(val string) (float64, error) {
+ return strconv.ParseFloat(val, 64)
+}
+
+func (s *float64SliceValue) toString(val float64) string {
+ return fmt.Sprintf("%f", val)
+}
+
+func (s *float64SliceValue) Append(val string) error {
+ i, err := s.fromString(val)
+ if err != nil {
+ return err
+ }
+ *s.value = append(*s.value, i)
+ return nil
+}
+
+func (s *float64SliceValue) Replace(val []string) error {
+ out := make([]float64, len(val))
+ for i, d := range val {
+ var err error
+ out[i], err = s.fromString(d)
+ if err != nil {
+ return err
+ }
+ }
+ *s.value = out
+ return nil
+}
+
+func (s *float64SliceValue) GetSlice() []string {
+ out := make([]string, len(*s.value))
+ for i, d := range *s.value {
+ out[i] = s.toString(d)
+ }
+ return out
+}
+
+func float64SliceConv(val string) (interface{}, error) {
+ val = strings.Trim(val, "[]")
+ // Empty string would cause a slice with one (empty) entry
+ if len(val) == 0 {
+ return []float64{}, nil
+ }
+ ss := strings.Split(val, ",")
+ out := make([]float64, len(ss))
+ for i, d := range ss {
+ var err error
+ out[i], err = strconv.ParseFloat(d, 64)
+ if err != nil {
+ return nil, err
+ }
+
+ }
+ return out, nil
+}
+
+// GetFloat64Slice return the []float64 value of a flag with the given name
+func (f *FlagSet) GetFloat64Slice(name string) ([]float64, error) {
+ val, err := f.getFlagType(name, "float64Slice", float64SliceConv)
+ if err != nil {
+ return []float64{}, err
+ }
+ return val.([]float64), nil
+}
+
+// Float64SliceVar defines a float64Slice flag with specified name, default value, and usage string.
+// The argument p points to a []float64 variable in which to store the value of the flag.
+func (f *FlagSet) Float64SliceVar(p *[]float64, name string, value []float64, usage string) {
+ f.VarP(newFloat64SliceValue(value, p), name, "", usage)
+}
+
+// Float64SliceVarP is like Float64SliceVar, but accepts a shorthand letter that can be used after a single dash.
+func (f *FlagSet) Float64SliceVarP(p *[]float64, name, shorthand string, value []float64, usage string) {
+ f.VarP(newFloat64SliceValue(value, p), name, shorthand, usage)
+}
+
+// Float64SliceVar defines a float64[] flag with specified name, default value, and usage string.
+// The argument p points to a float64[] variable in which to store the value of the flag.
+func Float64SliceVar(p *[]float64, name string, value []float64, usage string) {
+ CommandLine.VarP(newFloat64SliceValue(value, p), name, "", usage)
+}
+
+// Float64SliceVarP is like Float64SliceVar, but accepts a shorthand letter that can be used after a single dash.
+func Float64SliceVarP(p *[]float64, name, shorthand string, value []float64, usage string) {
+ CommandLine.VarP(newFloat64SliceValue(value, p), name, shorthand, usage)
+}
+
+// Float64Slice defines a []float64 flag with specified name, default value, and usage string.
+// The return value is the address of a []float64 variable that stores the value of the flag.
+func (f *FlagSet) Float64Slice(name string, value []float64, usage string) *[]float64 {
+ p := []float64{}
+ f.Float64SliceVarP(&p, name, "", value, usage)
+ return &p
+}
+
+// Float64SliceP is like Float64Slice, but accepts a shorthand letter that can be used after a single dash.
+func (f *FlagSet) Float64SliceP(name, shorthand string, value []float64, usage string) *[]float64 {
+ p := []float64{}
+ f.Float64SliceVarP(&p, name, shorthand, value, usage)
+ return &p
+}
+
+// Float64Slice defines a []float64 flag with specified name, default value, and usage string.
+// The return value is the address of a []float64 variable that stores the value of the flag.
+func Float64Slice(name string, value []float64, usage string) *[]float64 {
+ return CommandLine.Float64SliceP(name, "", value, usage)
+}
+
+// Float64SliceP is like Float64Slice, but accepts a shorthand letter that can be used after a single dash.
+func Float64SliceP(name, shorthand string, value []float64, usage string) *[]float64 {
+ return CommandLine.Float64SliceP(name, shorthand, value, usage)
+}
diff --git a/vendor/github.com/spf13/pflag/go.mod b/vendor/github.com/spf13/pflag/go.mod
new file mode 100644
index 0000000000..b2287eec13
--- /dev/null
+++ b/vendor/github.com/spf13/pflag/go.mod
@@ -0,0 +1,3 @@
+module github.com/spf13/pflag
+
+go 1.12
diff --git a/vendor/github.com/spf13/pflag/go.sum b/vendor/github.com/spf13/pflag/go.sum
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/vendor/github.com/spf13/pflag/int32_slice.go b/vendor/github.com/spf13/pflag/int32_slice.go
new file mode 100644
index 0000000000..ff128ff06d
--- /dev/null
+++ b/vendor/github.com/spf13/pflag/int32_slice.go
@@ -0,0 +1,174 @@
+package pflag
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+)
+
+// -- int32Slice Value
+type int32SliceValue struct {
+ value *[]int32
+ changed bool
+}
+
+func newInt32SliceValue(val []int32, p *[]int32) *int32SliceValue {
+ isv := new(int32SliceValue)
+ isv.value = p
+ *isv.value = val
+ return isv
+}
+
+func (s *int32SliceValue) Set(val string) error {
+ ss := strings.Split(val, ",")
+ out := make([]int32, len(ss))
+ for i, d := range ss {
+ var err error
+ var temp64 int64
+ temp64, err = strconv.ParseInt(d, 0, 32)
+ if err != nil {
+ return err
+ }
+ out[i] = int32(temp64)
+
+ }
+ if !s.changed {
+ *s.value = out
+ } else {
+ *s.value = append(*s.value, out...)
+ }
+ s.changed = true
+ return nil
+}
+
+func (s *int32SliceValue) Type() string {
+ return "int32Slice"
+}
+
+func (s *int32SliceValue) String() string {
+ out := make([]string, len(*s.value))
+ for i, d := range *s.value {
+ out[i] = fmt.Sprintf("%d", d)
+ }
+ return "[" + strings.Join(out, ",") + "]"
+}
+
+func (s *int32SliceValue) fromString(val string) (int32, error) {
+ t64, err := strconv.ParseInt(val, 0, 32)
+ if err != nil {
+ return 0, err
+ }
+ return int32(t64), nil
+}
+
+func (s *int32SliceValue) toString(val int32) string {
+ return fmt.Sprintf("%d", val)
+}
+
+func (s *int32SliceValue) Append(val string) error {
+ i, err := s.fromString(val)
+ if err != nil {
+ return err
+ }
+ *s.value = append(*s.value, i)
+ return nil
+}
+
+func (s *int32SliceValue) Replace(val []string) error {
+ out := make([]int32, len(val))
+ for i, d := range val {
+ var err error
+ out[i], err = s.fromString(d)
+ if err != nil {
+ return err
+ }
+ }
+ *s.value = out
+ return nil
+}
+
+func (s *int32SliceValue) GetSlice() []string {
+ out := make([]string, len(*s.value))
+ for i, d := range *s.value {
+ out[i] = s.toString(d)
+ }
+ return out
+}
+
+func int32SliceConv(val string) (interface{}, error) {
+ val = strings.Trim(val, "[]")
+ // Empty string would cause a slice with one (empty) entry
+ if len(val) == 0 {
+ return []int32{}, nil
+ }
+ ss := strings.Split(val, ",")
+ out := make([]int32, len(ss))
+ for i, d := range ss {
+ var err error
+ var temp64 int64
+ temp64, err = strconv.ParseInt(d, 0, 32)
+ if err != nil {
+ return nil, err
+ }
+ out[i] = int32(temp64)
+
+ }
+ return out, nil
+}
+
+// GetInt32Slice return the []int32 value of a flag with the given name
+func (f *FlagSet) GetInt32Slice(name string) ([]int32, error) {
+ val, err := f.getFlagType(name, "int32Slice", int32SliceConv)
+ if err != nil {
+ return []int32{}, err
+ }
+ return val.([]int32), nil
+}
+
+// Int32SliceVar defines a int32Slice flag with specified name, default value, and usage string.
+// The argument p points to a []int32 variable in which to store the value of the flag.
+func (f *FlagSet) Int32SliceVar(p *[]int32, name string, value []int32, usage string) {
+ f.VarP(newInt32SliceValue(value, p), name, "", usage)
+}
+
+// Int32SliceVarP is like Int32SliceVar, but accepts a shorthand letter that can be used after a single dash.
+func (f *FlagSet) Int32SliceVarP(p *[]int32, name, shorthand string, value []int32, usage string) {
+ f.VarP(newInt32SliceValue(value, p), name, shorthand, usage)
+}
+
+// Int32SliceVar defines a int32[] flag with specified name, default value, and usage string.
+// The argument p points to a int32[] variable in which to store the value of the flag.
+func Int32SliceVar(p *[]int32, name string, value []int32, usage string) {
+ CommandLine.VarP(newInt32SliceValue(value, p), name, "", usage)
+}
+
+// Int32SliceVarP is like Int32SliceVar, but accepts a shorthand letter that can be used after a single dash.
+func Int32SliceVarP(p *[]int32, name, shorthand string, value []int32, usage string) {
+ CommandLine.VarP(newInt32SliceValue(value, p), name, shorthand, usage)
+}
+
+// Int32Slice defines a []int32 flag with specified name, default value, and usage string.
+// The return value is the address of a []int32 variable that stores the value of the flag.
+func (f *FlagSet) Int32Slice(name string, value []int32, usage string) *[]int32 {
+ p := []int32{}
+ f.Int32SliceVarP(&p, name, "", value, usage)
+ return &p
+}
+
+// Int32SliceP is like Int32Slice, but accepts a shorthand letter that can be used after a single dash.
+func (f *FlagSet) Int32SliceP(name, shorthand string, value []int32, usage string) *[]int32 {
+ p := []int32{}
+ f.Int32SliceVarP(&p, name, shorthand, value, usage)
+ return &p
+}
+
+// Int32Slice defines a []int32 flag with specified name, default value, and usage string.
+// The return value is the address of a []int32 variable that stores the value of the flag.
+func Int32Slice(name string, value []int32, usage string) *[]int32 {
+ return CommandLine.Int32SliceP(name, "", value, usage)
+}
+
+// Int32SliceP is like Int32Slice, but accepts a shorthand letter that can be used after a single dash.
+func Int32SliceP(name, shorthand string, value []int32, usage string) *[]int32 {
+ return CommandLine.Int32SliceP(name, shorthand, value, usage)
+}
diff --git a/vendor/github.com/spf13/pflag/int64_slice.go b/vendor/github.com/spf13/pflag/int64_slice.go
new file mode 100644
index 0000000000..25464638f3
--- /dev/null
+++ b/vendor/github.com/spf13/pflag/int64_slice.go
@@ -0,0 +1,166 @@
+package pflag
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+)
+
+// -- int64Slice Value
+type int64SliceValue struct {
+ value *[]int64
+ changed bool
+}
+
+func newInt64SliceValue(val []int64, p *[]int64) *int64SliceValue {
+ isv := new(int64SliceValue)
+ isv.value = p
+ *isv.value = val
+ return isv
+}
+
+func (s *int64SliceValue) Set(val string) error {
+ ss := strings.Split(val, ",")
+ out := make([]int64, len(ss))
+ for i, d := range ss {
+ var err error
+ out[i], err = strconv.ParseInt(d, 0, 64)
+ if err != nil {
+ return err
+ }
+
+ }
+ if !s.changed {
+ *s.value = out
+ } else {
+ *s.value = append(*s.value, out...)
+ }
+ s.changed = true
+ return nil
+}
+
+func (s *int64SliceValue) Type() string {
+ return "int64Slice"
+}
+
+func (s *int64SliceValue) String() string {
+ out := make([]string, len(*s.value))
+ for i, d := range *s.value {
+ out[i] = fmt.Sprintf("%d", d)
+ }
+ return "[" + strings.Join(out, ",") + "]"
+}
+
+func (s *int64SliceValue) fromString(val string) (int64, error) {
+ return strconv.ParseInt(val, 0, 64)
+}
+
+func (s *int64SliceValue) toString(val int64) string {
+ return fmt.Sprintf("%d", val)
+}
+
+func (s *int64SliceValue) Append(val string) error {
+ i, err := s.fromString(val)
+ if err != nil {
+ return err
+ }
+ *s.value = append(*s.value, i)
+ return nil
+}
+
+func (s *int64SliceValue) Replace(val []string) error {
+ out := make([]int64, len(val))
+ for i, d := range val {
+ var err error
+ out[i], err = s.fromString(d)
+ if err != nil {
+ return err
+ }
+ }
+ *s.value = out
+ return nil
+}
+
+func (s *int64SliceValue) GetSlice() []string {
+ out := make([]string, len(*s.value))
+ for i, d := range *s.value {
+ out[i] = s.toString(d)
+ }
+ return out
+}
+
+func int64SliceConv(val string) (interface{}, error) {
+ val = strings.Trim(val, "[]")
+ // Empty string would cause a slice with one (empty) entry
+ if len(val) == 0 {
+ return []int64{}, nil
+ }
+ ss := strings.Split(val, ",")
+ out := make([]int64, len(ss))
+ for i, d := range ss {
+ var err error
+ out[i], err = strconv.ParseInt(d, 0, 64)
+ if err != nil {
+ return nil, err
+ }
+
+ }
+ return out, nil
+}
+
+// GetInt64Slice return the []int64 value of a flag with the given name
+func (f *FlagSet) GetInt64Slice(name string) ([]int64, error) {
+ val, err := f.getFlagType(name, "int64Slice", int64SliceConv)
+ if err != nil {
+ return []int64{}, err
+ }
+ return val.([]int64), nil
+}
+
+// Int64SliceVar defines a int64Slice flag with specified name, default value, and usage string.
+// The argument p points to a []int64 variable in which to store the value of the flag.
+func (f *FlagSet) Int64SliceVar(p *[]int64, name string, value []int64, usage string) {
+ f.VarP(newInt64SliceValue(value, p), name, "", usage)
+}
+
+// Int64SliceVarP is like Int64SliceVar, but accepts a shorthand letter that can be used after a single dash.
+func (f *FlagSet) Int64SliceVarP(p *[]int64, name, shorthand string, value []int64, usage string) {
+ f.VarP(newInt64SliceValue(value, p), name, shorthand, usage)
+}
+
+// Int64SliceVar defines a int64[] flag with specified name, default value, and usage string.
+// The argument p points to a int64[] variable in which to store the value of the flag.
+func Int64SliceVar(p *[]int64, name string, value []int64, usage string) {
+ CommandLine.VarP(newInt64SliceValue(value, p), name, "", usage)
+}
+
+// Int64SliceVarP is like Int64SliceVar, but accepts a shorthand letter that can be used after a single dash.
+func Int64SliceVarP(p *[]int64, name, shorthand string, value []int64, usage string) {
+ CommandLine.VarP(newInt64SliceValue(value, p), name, shorthand, usage)
+}
+
+// Int64Slice defines a []int64 flag with specified name, default value, and usage string.
+// The return value is the address of a []int64 variable that stores the value of the flag.
+func (f *FlagSet) Int64Slice(name string, value []int64, usage string) *[]int64 {
+ p := []int64{}
+ f.Int64SliceVarP(&p, name, "", value, usage)
+ return &p
+}
+
+// Int64SliceP is like Int64Slice, but accepts a shorthand letter that can be used after a single dash.
+func (f *FlagSet) Int64SliceP(name, shorthand string, value []int64, usage string) *[]int64 {
+ p := []int64{}
+ f.Int64SliceVarP(&p, name, shorthand, value, usage)
+ return &p
+}
+
+// Int64Slice defines a []int64 flag with specified name, default value, and usage string.
+// The return value is the address of a []int64 variable that stores the value of the flag.
+func Int64Slice(name string, value []int64, usage string) *[]int64 {
+ return CommandLine.Int64SliceP(name, "", value, usage)
+}
+
+// Int64SliceP is like Int64Slice, but accepts a shorthand letter that can be used after a single dash.
+func Int64SliceP(name, shorthand string, value []int64, usage string) *[]int64 {
+ return CommandLine.Int64SliceP(name, shorthand, value, usage)
+}
diff --git a/vendor/github.com/spf13/pflag/int_slice.go b/vendor/github.com/spf13/pflag/int_slice.go
index 1e7c9edde9..e71c39d91a 100644
--- a/vendor/github.com/spf13/pflag/int_slice.go
+++ b/vendor/github.com/spf13/pflag/int_slice.go
@@ -51,6 +51,36 @@ func (s *intSliceValue) String() string {
return "[" + strings.Join(out, ",") + "]"
}
+func (s *intSliceValue) Append(val string) error {
+ i, err := strconv.Atoi(val)
+ if err != nil {
+ return err
+ }
+ *s.value = append(*s.value, i)
+ return nil
+}
+
+func (s *intSliceValue) Replace(val []string) error {
+ out := make([]int, len(val))
+ for i, d := range val {
+ var err error
+ out[i], err = strconv.Atoi(d)
+ if err != nil {
+ return err
+ }
+ }
+ *s.value = out
+ return nil
+}
+
+func (s *intSliceValue) GetSlice() []string {
+ out := make([]string, len(*s.value))
+ for i, d := range *s.value {
+ out[i] = strconv.Itoa(d)
+ }
+ return out
+}
+
func intSliceConv(val string) (interface{}, error) {
val = strings.Trim(val, "[]")
// Empty string would cause a slice with one (empty) entry
diff --git a/vendor/github.com/spf13/pflag/ip_slice.go b/vendor/github.com/spf13/pflag/ip_slice.go
index 7dd196fe3f..775faae4fd 100644
--- a/vendor/github.com/spf13/pflag/ip_slice.go
+++ b/vendor/github.com/spf13/pflag/ip_slice.go
@@ -72,9 +72,47 @@ func (s *ipSliceValue) String() string {
return "[" + out + "]"
}
+func (s *ipSliceValue) fromString(val string) (net.IP, error) {
+ return net.ParseIP(strings.TrimSpace(val)), nil
+}
+
+func (s *ipSliceValue) toString(val net.IP) string {
+ return val.String()
+}
+
+func (s *ipSliceValue) Append(val string) error {
+ i, err := s.fromString(val)
+ if err != nil {
+ return err
+ }
+ *s.value = append(*s.value, i)
+ return nil
+}
+
+func (s *ipSliceValue) Replace(val []string) error {
+ out := make([]net.IP, len(val))
+ for i, d := range val {
+ var err error
+ out[i], err = s.fromString(d)
+ if err != nil {
+ return err
+ }
+ }
+ *s.value = out
+ return nil
+}
+
+func (s *ipSliceValue) GetSlice() []string {
+ out := make([]string, len(*s.value))
+ for i, d := range *s.value {
+ out[i] = s.toString(d)
+ }
+ return out
+}
+
func ipSliceConv(val string) (interface{}, error) {
val = strings.Trim(val, "[]")
- // Emtpy string would cause a slice with one (empty) entry
+ // Empty string would cause a slice with one (empty) entry
if len(val) == 0 {
return []net.IP{}, nil
}
diff --git a/vendor/github.com/spf13/pflag/string_array.go b/vendor/github.com/spf13/pflag/string_array.go
index fa7bc60187..4894af8180 100644
--- a/vendor/github.com/spf13/pflag/string_array.go
+++ b/vendor/github.com/spf13/pflag/string_array.go
@@ -23,6 +23,32 @@ func (s *stringArrayValue) Set(val string) error {
return nil
}
+func (s *stringArrayValue) Append(val string) error {
+ *s.value = append(*s.value, val)
+ return nil
+}
+
+func (s *stringArrayValue) Replace(val []string) error {
+ out := make([]string, len(val))
+ for i, d := range val {
+ var err error
+ out[i] = d
+ if err != nil {
+ return err
+ }
+ }
+ *s.value = out
+ return nil
+}
+
+func (s *stringArrayValue) GetSlice() []string {
+ out := make([]string, len(*s.value))
+ for i, d := range *s.value {
+ out[i] = d
+ }
+ return out
+}
+
func (s *stringArrayValue) Type() string {
return "stringArray"
}
diff --git a/vendor/github.com/spf13/pflag/string_slice.go b/vendor/github.com/spf13/pflag/string_slice.go
index 0cd3ccc083..3cb2e69dba 100644
--- a/vendor/github.com/spf13/pflag/string_slice.go
+++ b/vendor/github.com/spf13/pflag/string_slice.go
@@ -62,6 +62,20 @@ func (s *stringSliceValue) String() string {
return "[" + str + "]"
}
+func (s *stringSliceValue) Append(val string) error {
+ *s.value = append(*s.value, val)
+ return nil
+}
+
+func (s *stringSliceValue) Replace(val []string) error {
+ *s.value = val
+ return nil
+}
+
+func (s *stringSliceValue) GetSlice() []string {
+ return *s.value
+}
+
func stringSliceConv(sval string) (interface{}, error) {
sval = sval[1 : len(sval)-1]
// An empty string would cause a slice with one (empty) string
@@ -84,7 +98,7 @@ func (f *FlagSet) GetStringSlice(name string) ([]string, error) {
// The argument p points to a []string variable in which to store the value of the flag.
// Compared to StringArray flags, StringSlice flags take comma-separated value as arguments and split them accordingly.
// For example:
-// --ss="v1,v2" -ss="v3"
+// --ss="v1,v2" --ss="v3"
// will result in
// []string{"v1", "v2", "v3"}
func (f *FlagSet) StringSliceVar(p *[]string, name string, value []string, usage string) {
@@ -100,7 +114,7 @@ func (f *FlagSet) StringSliceVarP(p *[]string, name, shorthand string, value []s
// The argument p points to a []string variable in which to store the value of the flag.
// Compared to StringArray flags, StringSlice flags take comma-separated value as arguments and split them accordingly.
// For example:
-// --ss="v1,v2" -ss="v3"
+// --ss="v1,v2" --ss="v3"
// will result in
// []string{"v1", "v2", "v3"}
func StringSliceVar(p *[]string, name string, value []string, usage string) {
@@ -116,7 +130,7 @@ func StringSliceVarP(p *[]string, name, shorthand string, value []string, usage
// The return value is the address of a []string variable that stores the value of the flag.
// Compared to StringArray flags, StringSlice flags take comma-separated value as arguments and split them accordingly.
// For example:
-// --ss="v1,v2" -ss="v3"
+// --ss="v1,v2" --ss="v3"
// will result in
// []string{"v1", "v2", "v3"}
func (f *FlagSet) StringSlice(name string, value []string, usage string) *[]string {
@@ -136,7 +150,7 @@ func (f *FlagSet) StringSliceP(name, shorthand string, value []string, usage str
// The return value is the address of a []string variable that stores the value of the flag.
// Compared to StringArray flags, StringSlice flags take comma-separated value as arguments and split them accordingly.
// For example:
-// --ss="v1,v2" -ss="v3"
+// --ss="v1,v2" --ss="v3"
// will result in
// []string{"v1", "v2", "v3"}
func StringSlice(name string, value []string, usage string) *[]string {
diff --git a/vendor/github.com/spf13/pflag/string_to_int64.go b/vendor/github.com/spf13/pflag/string_to_int64.go
new file mode 100644
index 0000000000..a807a04a0b
--- /dev/null
+++ b/vendor/github.com/spf13/pflag/string_to_int64.go
@@ -0,0 +1,149 @@
+package pflag
+
+import (
+ "bytes"
+ "fmt"
+ "strconv"
+ "strings"
+)
+
+// -- stringToInt64 Value
+type stringToInt64Value struct {
+ value *map[string]int64
+ changed bool
+}
+
+func newStringToInt64Value(val map[string]int64, p *map[string]int64) *stringToInt64Value {
+ ssv := new(stringToInt64Value)
+ ssv.value = p
+ *ssv.value = val
+ return ssv
+}
+
+// Format: a=1,b=2
+func (s *stringToInt64Value) Set(val string) error {
+ ss := strings.Split(val, ",")
+ out := make(map[string]int64, len(ss))
+ for _, pair := range ss {
+ kv := strings.SplitN(pair, "=", 2)
+ if len(kv) != 2 {
+ return fmt.Errorf("%s must be formatted as key=value", pair)
+ }
+ var err error
+ out[kv[0]], err = strconv.ParseInt(kv[1], 10, 64)
+ if err != nil {
+ return err
+ }
+ }
+ if !s.changed {
+ *s.value = out
+ } else {
+ for k, v := range out {
+ (*s.value)[k] = v
+ }
+ }
+ s.changed = true
+ return nil
+}
+
+func (s *stringToInt64Value) Type() string {
+ return "stringToInt64"
+}
+
+func (s *stringToInt64Value) String() string {
+ var buf bytes.Buffer
+ i := 0
+ for k, v := range *s.value {
+ if i > 0 {
+ buf.WriteRune(',')
+ }
+ buf.WriteString(k)
+ buf.WriteRune('=')
+ buf.WriteString(strconv.FormatInt(v, 10))
+ i++
+ }
+ return "[" + buf.String() + "]"
+}
+
+func stringToInt64Conv(val string) (interface{}, error) {
+ val = strings.Trim(val, "[]")
+ // An empty string would cause an empty map
+ if len(val) == 0 {
+ return map[string]int64{}, nil
+ }
+ ss := strings.Split(val, ",")
+ out := make(map[string]int64, len(ss))
+ for _, pair := range ss {
+ kv := strings.SplitN(pair, "=", 2)
+ if len(kv) != 2 {
+ return nil, fmt.Errorf("%s must be formatted as key=value", pair)
+ }
+ var err error
+ out[kv[0]], err = strconv.ParseInt(kv[1], 10, 64)
+ if err != nil {
+ return nil, err
+ }
+ }
+ return out, nil
+}
+
+// GetStringToInt64 return the map[string]int64 value of a flag with the given name
+func (f *FlagSet) GetStringToInt64(name string) (map[string]int64, error) {
+ val, err := f.getFlagType(name, "stringToInt64", stringToInt64Conv)
+ if err != nil {
+ return map[string]int64{}, err
+ }
+ return val.(map[string]int64), nil
+}
+
+// StringToInt64Var defines a string flag with specified name, default value, and usage string.
+// The argument p point64s to a map[string]int64 variable in which to store the values of the multiple flags.
+// The value of each argument will not try to be separated by comma
+func (f *FlagSet) StringToInt64Var(p *map[string]int64, name string, value map[string]int64, usage string) {
+ f.VarP(newStringToInt64Value(value, p), name, "", usage)
+}
+
+// StringToInt64VarP is like StringToInt64Var, but accepts a shorthand letter that can be used after a single dash.
+func (f *FlagSet) StringToInt64VarP(p *map[string]int64, name, shorthand string, value map[string]int64, usage string) {
+ f.VarP(newStringToInt64Value(value, p), name, shorthand, usage)
+}
+
+// StringToInt64Var defines a string flag with specified name, default value, and usage string.
+// The argument p point64s to a map[string]int64 variable in which to store the value of the flag.
+// The value of each argument will not try to be separated by comma
+func StringToInt64Var(p *map[string]int64, name string, value map[string]int64, usage string) {
+ CommandLine.VarP(newStringToInt64Value(value, p), name, "", usage)
+}
+
+// StringToInt64VarP is like StringToInt64Var, but accepts a shorthand letter that can be used after a single dash.
+func StringToInt64VarP(p *map[string]int64, name, shorthand string, value map[string]int64, usage string) {
+ CommandLine.VarP(newStringToInt64Value(value, p), name, shorthand, usage)
+}
+
+// StringToInt64 defines a string flag with specified name, default value, and usage string.
+// The return value is the address of a map[string]int64 variable that stores the value of the flag.
+// The value of each argument will not try to be separated by comma
+func (f *FlagSet) StringToInt64(name string, value map[string]int64, usage string) *map[string]int64 {
+ p := map[string]int64{}
+ f.StringToInt64VarP(&p, name, "", value, usage)
+ return &p
+}
+
+// StringToInt64P is like StringToInt64, but accepts a shorthand letter that can be used after a single dash.
+func (f *FlagSet) StringToInt64P(name, shorthand string, value map[string]int64, usage string) *map[string]int64 {
+ p := map[string]int64{}
+ f.StringToInt64VarP(&p, name, shorthand, value, usage)
+ return &p
+}
+
+// StringToInt64 defines a string flag with specified name, default value, and usage string.
+// The return value is the address of a map[string]int64 variable that stores the value of the flag.
+// The value of each argument will not try to be separated by comma
+func StringToInt64(name string, value map[string]int64, usage string) *map[string]int64 {
+ return CommandLine.StringToInt64P(name, "", value, usage)
+}
+
+// StringToInt64P is like StringToInt64, but accepts a shorthand letter that can be used after a single dash.
+func StringToInt64P(name, shorthand string, value map[string]int64, usage string) *map[string]int64 {
+ return CommandLine.StringToInt64P(name, shorthand, value, usage)
+}
diff --git a/vendor/github.com/spf13/pflag/uint_slice.go b/vendor/github.com/spf13/pflag/uint_slice.go
index edd94c600a..5fa924835e 100644
--- a/vendor/github.com/spf13/pflag/uint_slice.go
+++ b/vendor/github.com/spf13/pflag/uint_slice.go
@@ -50,6 +50,48 @@ func (s *uintSliceValue) String() string {
return "[" + strings.Join(out, ",") + "]"
}
+func (s *uintSliceValue) fromString(val string) (uint, error) {
+ t, err := strconv.ParseUint(val, 10, 0)
+ if err != nil {
+ return 0, err
+ }
+ return uint(t), nil
+}
+
+func (s *uintSliceValue) toString(val uint) string {
+ return fmt.Sprintf("%d", val)
+}
+
+func (s *uintSliceValue) Append(val string) error {
+ i, err := s.fromString(val)
+ if err != nil {
+ return err
+ }
+ *s.value = append(*s.value, i)
+ return nil
+}
+
+func (s *uintSliceValue) Replace(val []string) error {
+ out := make([]uint, len(val))
+ for i, d := range val {
+ var err error
+ out[i], err = s.fromString(d)
+ if err != nil {
+ return err
+ }
+ }
+ *s.value = out
+ return nil
+}
+
+func (s *uintSliceValue) GetSlice() []string {
+ out := make([]string, len(*s.value))
+ for i, d := range *s.value {
+ out[i] = s.toString(d)
+ }
+ return out
+}
+
func uintSliceConv(val string) (interface{}, error) {
val = strings.Trim(val, "[]")
// Empty string would cause a slice with one (empty) entry
diff --git a/vendor/github.com/spf13/viper/.gitignore b/vendor/github.com/spf13/viper/.gitignore
index 01b5c44b9c..d6941f324b 100644
--- a/vendor/github.com/spf13/viper/.gitignore
+++ b/vendor/github.com/spf13/viper/.gitignore
@@ -1,29 +1,20 @@
-# Compiled Object files, Static and Dynamic libs (Shared Objects)
-*.o
-*.a
-*.so
+/bin/
+/build/
+/var/
+/vendor/
-# 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
-*.bench
-
-.vscode
-
-# exclude dependencies in the `/vendor` folder
-vendor
+# IDE integration
+/.vscode/*
+!/.vscode/launch.json
+!/.vscode/tasks.json
+/.idea/*
+!/.idea/codeStyles/
+!/.idea/copyright/
+!/.idea/dataSources.xml
+!/.idea/*.iml
+!/.idea/externalDependencies.xml
+!/.idea/go.imports.xml
+!/.idea/modules.xml
+!/.idea/runConfigurations/
+!/.idea/scopes/
+!/.idea/sqldialects.xml
diff --git a/vendor/github.com/spf13/viper/.golangci.yml b/vendor/github.com/spf13/viper/.golangci.yml
new file mode 100644
index 0000000000..0ea9249e79
--- /dev/null
+++ b/vendor/github.com/spf13/viper/.golangci.yml
@@ -0,0 +1,24 @@
+linters-settings:
+ golint:
+ min-confidence: 0.1
+ goimports:
+ local-prefixes: github.com/spf13/viper
+
+linters:
+ enable-all: true
+ disable:
+ - funlen
+ - maligned
+
+ # TODO: fix me
+ - wsl
+ - gochecknoinits
+ - gosimple
+ - gochecknoglobals
+ - errcheck
+ - lll
+ - godox
+ - scopelint
+ - gocyclo
+ - gocognit
+ - gocritic
\ No newline at end of file
diff --git a/vendor/github.com/spf13/viper/.travis.yml b/vendor/github.com/spf13/viper/.travis.yml
index bb83057ba4..ed677bbb81 100644
--- a/vendor/github.com/spf13/viper/.travis.yml
+++ b/vendor/github.com/spf13/viper/.travis.yml
@@ -4,10 +4,13 @@ language: go
env:
global:
- - GO111MODULE="on"
+ - GO111MODULE="on"
+ - GOFLAGS="-mod=readonly"
go:
- 1.11.x
+ - 1.12.x
+ - 1.13.x
- tip
os:
@@ -27,5 +30,3 @@ script:
after_success:
- go get -u -d github.com/spf13/hugo
- cd $GOPATH/src/github.com/spf13/hugo && make && ./hugo -s docs && cd -
-
-sudo: false
diff --git a/vendor/github.com/spf13/viper/Makefile b/vendor/github.com/spf13/viper/Makefile
new file mode 100644
index 0000000000..1c2cab03f4
--- /dev/null
+++ b/vendor/github.com/spf13/viper/Makefile
@@ -0,0 +1,76 @@
+# A Self-Documenting Makefile: http://marmelab.com/blog/2016/02/29/auto-documented-makefile.html
+
+OS = $(shell uname | tr A-Z a-z)
+export PATH := $(abspath bin/):${PATH}
+
+# Build variables
+BUILD_DIR ?= build
+export CGO_ENABLED ?= 0
+export GOOS = $(shell go env GOOS)
+ifeq (${VERBOSE}, 1)
+ifeq ($(filter -v,${GOARGS}),)
+ GOARGS += -v
+endif
+TEST_FORMAT = short-verbose
+endif
+
+# Dependency versions
+GOTESTSUM_VERSION = 0.4.0
+GOLANGCI_VERSION = 1.21.0
+
+# Add the ability to override some variables
+# Use with care
+-include override.mk
+
+.PHONY: clear
+clear: ## Clear the working area and the project
+ rm -rf bin/
+
+.PHONY: check
+check: test lint ## Run tests and linters
+
+bin/gotestsum: bin/gotestsum-${GOTESTSUM_VERSION}
+ @ln -sf gotestsum-${GOTESTSUM_VERSION} bin/gotestsum
+bin/gotestsum-${GOTESTSUM_VERSION}:
+ @mkdir -p bin
+ curl -L https://github.com/gotestyourself/gotestsum/releases/download/v${GOTESTSUM_VERSION}/gotestsum_${GOTESTSUM_VERSION}_${OS}_amd64.tar.gz | tar -zOxf - gotestsum > ./bin/gotestsum-${GOTESTSUM_VERSION} && chmod +x ./bin/gotestsum-${GOTESTSUM_VERSION}
+
+TEST_PKGS ?= ./...
+.PHONY: test
+test: TEST_FORMAT ?= short
+test: SHELL = /bin/bash
+test: export CGO_ENABLED=1
+test: bin/gotestsum ## Run tests
+ @mkdir -p ${BUILD_DIR}
+ bin/gotestsum --no-summary=skipped --junitfile ${BUILD_DIR}/coverage.xml --format ${TEST_FORMAT} -- -race -coverprofile=${BUILD_DIR}/coverage.txt -covermode=atomic $(filter-out -v,${GOARGS}) $(if ${TEST_PKGS},${TEST_PKGS},./...)
+
+bin/golangci-lint: bin/golangci-lint-${GOLANGCI_VERSION}
+ @ln -sf golangci-lint-${GOLANGCI_VERSION} bin/golangci-lint
+bin/golangci-lint-${GOLANGCI_VERSION}:
+ @mkdir -p bin
+ curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | bash -s -- -b ./bin/ v${GOLANGCI_VERSION}
+ @mv bin/golangci-lint $@
+
+.PHONY: lint
+lint: bin/golangci-lint ## Run linter
+ bin/golangci-lint run
+
+.PHONY: fix
+fix: bin/golangci-lint ## Fix lint violations
+ bin/golangci-lint run --fix
+
+# Add custom targets here
+-include custom.mk
+
+.PHONY: list
+list: ## List all make targets
+ @${MAKE} -pRrn : -f $(MAKEFILE_LIST) 2>/dev/null | awk -v RS= -F: '/^# File/,/^# Finished Make data base/ {if ($$1 !~ "^[#.]") {print $$1}}' | egrep -v -e '^[^[:alnum:]]' -e '^$@$$' | sort
+
+.PHONY: help
+.DEFAULT_GOAL := help
+help:
+ @grep -h -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
+
+# Variable outputting/exporting rules
+var-%: ; @echo $($*)
+varexport-%: ; @echo $*=$($*)
diff --git a/vendor/github.com/spf13/viper/README.md b/vendor/github.com/spf13/viper/README.md
index 0208eac84d..a574677f8d 100644
--- a/vendor/github.com/spf13/viper/README.md
+++ b/vendor/github.com/spf13/viper/README.md
@@ -2,6 +2,10 @@
Go configuration with fangs!
+[![Actions](https://github.com/spf13/viper/workflows/CI/badge.svg)](https://github.com/spf13/viper)
+[![Join the chat at https://gitter.im/spf13/viper](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/spf13/viper?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
+[![GoDoc](https://godoc.org/github.com/spf13/viper?status.svg)](https://godoc.org/github.com/spf13/viper)
+
Many Go projects are built using Viper including:
* [Hugo](http://gohugo.io)
@@ -12,8 +16,14 @@ Many Go projects are built using Viper including:
* [BloomApi](https://www.bloomapi.com/)
* [doctl](https://github.com/digitalocean/doctl)
* [Clairctl](https://github.com/jgsqware/clairctl)
+* [Mercure](https://mercure.rocks)
+
-[![Build Status](https://travis-ci.org/spf13/viper.svg)](https://travis-ci.org/spf13/viper) [![Join the chat at https://gitter.im/spf13/viper](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/spf13/viper?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![GoDoc](https://godoc.org/github.com/spf13/viper?status.svg)](https://godoc.org/github.com/spf13/viper)
+## Install
+
+```console
+go get github.com/spf13/viper
+```
## What is Viper?
@@ -23,7 +33,7 @@ to work within an application, and can handle all types of configuration needs
and formats. It supports:
* setting defaults
-* reading from JSON, TOML, YAML, HCL, and Java properties config files
+* reading from JSON, TOML, YAML, HCL, envfile and Java properties config files
* live watching and re-reading of config files (optional)
* reading from environment variables
* reading from remote config systems (etcd or Consul), and watching changes
@@ -31,8 +41,8 @@ and formats. It supports:
* reading from buffer
* setting explicit values
-Viper can be thought of as a registry for all of your applications
-configuration needs.
+Viper can be thought of as a registry for all of your applications configuration needs.
+
## Why Viper?
@@ -42,34 +52,31 @@ Viper is here to help with that.
Viper does the following for you:
-1. Find, load, and unmarshal a configuration file in JSON, TOML, YAML, HCL, or Java properties formats.
-2. Provide a mechanism to set default values for your different
- configuration options.
-3. Provide a mechanism to set override values for options specified through
- command line flags.
-4. Provide an alias system to easily rename parameters without breaking existing
- code.
-5. Make it easy to tell the difference between when a user has provided a
- command line or config file which is the same as the default.
+1. Find, load, and unmarshal a configuration file in JSON, TOML, YAML, HCL, INI, envfile or Java properties formats.
+2. Provide a mechanism to set default values for your different configuration options.
+3. Provide a mechanism to set override values for options specified through command line flags.
+4. Provide an alias system to easily rename parameters without breaking existing code.
+5. Make it easy to tell the difference between when a user has provided a command line or config file which is the same as the default.
-Viper uses the following precedence order. Each item takes precedence over the
-item below it:
+Viper uses the following precedence order. Each item takes precedence over the item below it:
- * explicit call to Set
+ * explicit call to `Set`
* flag
* env
* config
* key/value store
* default
-Viper configuration keys are case insensitive.
+**Important:** Viper configuration keys are case insensitive.
+There are ongoing discussions about making that optional.
+
## Putting Values into Viper
### Establishing Defaults
A good configuration system will support default values. A default value is not
-required for a key, but it’s useful in the event that a key hasn’t been set via
+required for a key, but it’s useful in the event that a key hasn't been set via
config file, environment variable, remote configuration or flag.
Examples:
@@ -83,7 +90,7 @@ viper.SetDefault("Taxonomies", map[string]string{"tag": "tags", "category": "cat
### Reading Config Files
Viper requires minimal configuration so it knows where to look for config files.
-Viper supports JSON, TOML, YAML, HCL, and Java Properties files. Viper can search multiple paths, but
+Viper supports JSON, TOML, YAML, HCL, INI, envfile and Java Properties files. Viper can search multiple paths, but
currently a single Viper instance only supports a single configuration file.
Viper does not default to any configuration search paths leaving defaults decision
to an application.
@@ -94,6 +101,7 @@ where a configuration file is expected.
```go
viper.SetConfigName("config") // name of config file (without extension)
+viper.SetConfigType("yaml") // REQUIRED if the config file does not have the extension in the name
viper.AddConfigPath("/etc/appname/") // path to look for the config file in
viper.AddConfigPath("$HOME/.appname") // call multiple times to add many search paths
viper.AddConfigPath(".") // optionally look for config in the working directory
@@ -103,6 +111,44 @@ if err != nil { // Handle errors reading the config file
}
```
+You can handle the specific case where no config file is found like this:
+
+```go
+if err := viper.ReadInConfig(); err != nil {
+ if _, ok := err.(viper.ConfigFileNotFoundError); ok {
+ // Config file not found; ignore error if desired
+ } else {
+ // Config file was found but another error was produced
+ }
+}
+
+// Config file found and successfully parsed
+```
+
+*NOTE [since 1.6]:* You can also have a file without an extension and specify the format programmaticaly. For those configuration files that lie in the home of the user without any extension like `.bashrc`
+
+### Writing Config Files
+
+Reading from config files is useful, but at times you want to store all modifications made at run time.
+For that, a bunch of commands are available, each with its own purpose:
+
+* WriteConfig - writes the current viper configuration to the predefined path, if exists. Errors if no predefined path. Will overwrite the current config file, if it exists.
+* SafeWriteConfig - writes the current viper configuration to the predefined path. Errors if no predefined path. Will not overwrite the current config file, if it exists.
+* WriteConfigAs - writes the current viper configuration to the given filepath. Will overwrite the given file, if it exists.
+* SafeWriteConfigAs - writes the current viper configuration to the given filepath. Will not overwrite the given file, if it exists.
+
+As a rule of the thumb, everything marked with safe won't overwrite any file, but just create if not existent, whilst the default behavior is to create or truncate.
+
+A small examples section:
+
+```go
+viper.WriteConfig() // writes current config to predefined path set by 'viper.AddConfigPath()' and 'viper.SetConfigName'
+viper.SafeWriteConfig()
+viper.WriteConfigAs("/path/to/my/.config")
+viper.SafeWriteConfigAs("/path/to/my/.config") // will error since it has already been written
+viper.SafeWriteConfigAs("/path/to/my/.other_config")
+```
+
### Watching and re-reading config files
Viper supports the ability to have your application live read a config file while running.
@@ -186,7 +232,7 @@ with ENV:
* `BindEnv(string...) : error`
* `SetEnvPrefix(string)`
* `SetEnvKeyReplacer(string...) *strings.Replacer`
- * `AllowEmptyEnvVar(bool)`
+ * `AllowEmptyEnv(bool)`
_When working with ENV variables, it’s important to recognize that Viper
treats ENV variables as case sensitive._
@@ -199,9 +245,9 @@ prefix.
`BindEnv` takes one or two parameters. The first parameter is the key name, the
second is the name of the environment variable. The name of the environment
variable is case sensitive. If the ENV variable name is not provided, then
-Viper will automatically assume that the key name matches the ENV variable name,
-but the ENV variable is IN ALL CAPS. When you explicitly provide the ENV
-variable name, it **does not** automatically add the prefix.
+Viper will automatically assume that the ENV variable matches the following format: prefix + "_" + the key name in ALL CAPS. When you explicitly provide the ENV variable name (the second parameter),
+it **does not** automatically add the prefix. For example if the second parameter is "id",
+Viper will look for the ENV variable "ID".
One important thing to recognize when working with ENV variables is that the
value will be read each time it is accessed. Viper does not fix the value when
@@ -218,6 +264,9 @@ keys to an extent. This is useful if you want to use `-` or something in your
`Get()` calls, but want your environmental variables to use `_` delimiters. An
example of using it can be found in `viper_test.go`.
+Alternatively, you can use `EnvKeyReplacer` with `NewWithOptions` factory function.
+Unlike `SetEnvKeyReplacer`, it accepts a `StringReplacer` interface allowing you to write custom string replacing logic.
+
By default empty environment variables are considered unset and will fall back to
the next configuration source. To treat empty environment variables as set, use
the `AllowEmptyEnv` method.
@@ -346,7 +395,7 @@ package:
`import _ "github.com/spf13/viper/remote"`
-Viper will read a config string (as JSON, TOML, YAML or HCL) retrieved from a path
+Viper will read a config string (as JSON, TOML, YAML, HCL or envfile) retrieved from a path
in a Key/Value store such as etcd or Consul. These values take precedence over
default values, but are overridden by configuration values retrieved from disk,
flags, or environment variables.
@@ -381,7 +430,7 @@ how to use Consul.
#### etcd
```go
viper.AddRemoteProvider("etcd", "http://127.0.0.1:4001","/config/hugo.json")
-viper.SetConfigType("json") // because there is no file extension in a stream of bytes, supported extensions are "json", "toml", "yaml", "yml", "properties", "props", "prop"
+viper.SetConfigType("json") // because there is no file extension in a stream of bytes, supported extensions are "json", "toml", "yaml", "yml", "properties", "props", "prop", "env", "dotenv"
err := viper.ReadRemoteConfig()
```
@@ -409,7 +458,7 @@ fmt.Println(viper.Get("hostname")) // myhostname.com
```go
viper.AddSecureRemoteProvider("etcd","http://127.0.0.1:4001","/config/hugo.json","/etc/secrets/mykeyring.gpg")
-viper.SetConfigType("json") // because there is no file extension in a stream of bytes, supported extensions are "json", "toml", "yaml", "yml", "properties", "props", "prop"
+viper.SetConfigType("json") // because there is no file extension in a stream of bytes, supported extensions are "json", "toml", "yaml", "yml", "properties", "props", "prop", "env", "dotenv"
err := viper.ReadRemoteConfig()
```
@@ -420,7 +469,7 @@ err := viper.ReadRemoteConfig()
var runtime_viper = viper.New()
runtime_viper.AddRemoteProvider("etcd", "http://127.0.0.1:4001", "/config/hugo.yml")
-runtime_viper.SetConfigType("yaml") // because there is no file extension in a stream of bytes, supported extensions are "json", "toml", "yaml", "yml", "properties", "props", "prop"
+runtime_viper.SetConfigType("yaml") // because there is no file extension in a stream of bytes, supported extensions are "json", "toml", "yaml", "yml", "properties", "props", "prop", "env", "dotenv"
// read from remote config the first time.
err := runtime_viper.ReadRemoteConfig()
@@ -456,6 +505,7 @@ The following functions and methods exist:
* `GetBool(key string) : bool`
* `GetFloat64(key string) : float64`
* `GetInt(key string) : int`
+ * `GetIntSlice(key string) : []int`
* `GetString(key string) : string`
* `GetStringMap(key string) : map[string]interface{}`
* `GetStringMapString(key string) : map[string]string`
@@ -611,15 +661,74 @@ type config struct {
var C config
-err := Unmarshal(&C)
+err := viper.Unmarshal(&C)
+if err != nil {
+ t.Fatalf("unable to decode into struct, %v", err)
+}
+```
+
+If you want to unmarshal configuration where the keys themselves contain dot (the default key delimiter),
+you have to change the delimiter:
+
+```go
+v := viper.NewWithOptions(viper.KeyDelimiter("::"))
+
+v.SetDefault("chart::values", map[string]interface{}{
+ "ingress": map[string]interface{}{
+ "annotations": map[string]interface{}{
+ "traefik.frontend.rule.type": "PathPrefix",
+ "traefik.ingress.kubernetes.io/ssl-redirect": "true",
+ },
+ },
+})
+
+type config struct {
+ Chart struct{
+ Values map[string]interface{}
+ }
+}
+
+var C config
+
+v.Unmarshal(&C)
+```
+
+Viper also supports unmarshaling into embedded structs:
+
+```go
+/*
+Example config:
+
+module:
+ enabled: true
+ token: 89h3f98hbwf987h3f98wenf89ehf
+*/
+type config struct {
+ Module struct {
+ Enabled bool
+
+ moduleConfig `mapstructure:",squash"`
+ }
+}
+
+// moduleConfig could be in a module specific package
+type moduleConfig struct {
+ Token string
+}
+
+var C config
+
+err := viper.Unmarshal(&C)
if err != nil {
t.Fatalf("unable to decode into struct, %v", err)
}
```
+Viper uses [github.com/mitchellh/mapstructure](https://github.com/mitchellh/mapstructure) under the hood for unmarshaling values which uses `mapstructure` tags by default.
+
### Marshalling to string
-You may need to marhsal all the settings held in viper into a string rather than write them to a file.
+You may need to marshal all the settings held in viper into a string rather than write them to a file.
You can use your favorite format's marshaller with the config returned by `AllSettings()`.
```go
@@ -630,11 +739,11 @@ import (
func yamlStringSettings() string {
c := viper.AllSettings()
- bs, err := yaml.Marshal(c)
- if err != nil {
- t.Fatalf("unable to marshal config to YAML: %v", err)
+ bs, err := yaml.Marshal(c)
+ if err != nil {
+ log.Fatalf("unable to marshal config to YAML: %v", err)
}
- return string(bs)
+ return string(bs)
}
```
@@ -672,13 +781,6 @@ different vipers.
## Q & A
-Q: Why not INI files?
-
-A: Ini files are pretty awful. There’s no standard format, and they are hard to
-validate. Viper is designed to work with JSON, TOML or YAML files. If someone
-really wants to add this feature, I’d be happy to merge it. It’s easy to specify
-which formats your application will permit.
-
Q: Why is it called “Viper”?
A: Viper is designed to be a [companion](http://en.wikipedia.org/wiki/Viper_(G.I._Joe))
diff --git a/vendor/github.com/spf13/viper/flags.go b/vendor/github.com/spf13/viper/flags.go
index dd32f4e1c2..b5ddbf5d46 100644
--- a/vendor/github.com/spf13/viper/flags.go
+++ b/vendor/github.com/spf13/viper/flags.go
@@ -36,7 +36,7 @@ type pflagValue struct {
flag *pflag.Flag
}
-// HasChanges returns whether the flag has changes or not.
+// HasChanged returns whether the flag has changes or not.
func (p pflagValue) HasChanged() bool {
return p.flag.Changed
}
diff --git a/vendor/github.com/spf13/viper/go.mod b/vendor/github.com/spf13/viper/go.mod
index 2794300552..0e358cbefb 100644
--- a/vendor/github.com/spf13/viper/go.mod
+++ b/vendor/github.com/spf13/viper/go.mod
@@ -1,5 +1,7 @@
module github.com/spf13/viper
+go 1.12
+
require (
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6 // indirect
github.com/coreos/bbolt v1.3.2 // indirect
@@ -18,16 +20,18 @@ require (
github.com/grpc-ecosystem/grpc-gateway v1.9.0 // indirect
github.com/hashicorp/hcl v1.0.0
github.com/jonboulle/clockwork v0.1.0 // indirect
- github.com/magiconair/properties v1.8.0
+ github.com/magiconair/properties v1.8.1
github.com/mitchellh/mapstructure v1.1.2
github.com/pelletier/go-toml v1.2.0
github.com/prometheus/client_golang v0.9.3 // indirect
+ github.com/smartystreets/goconvey v1.6.4 // indirect
github.com/soheilhy/cmux v0.1.4 // indirect
github.com/spf13/afero v1.1.2
github.com/spf13/cast v1.3.0
github.com/spf13/jwalterweatherman v1.0.0
github.com/spf13/pflag v1.0.3
github.com/stretchr/testify v1.2.2
+ github.com/subosito/gotenv v1.2.0
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5 // indirect
github.com/ugorji/go v1.1.4 // indirect
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 // indirect
@@ -39,5 +43,6 @@ require (
golang.org/x/net v0.0.0-20190522155817-f3200d17e092 // indirect
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 // indirect
google.golang.org/grpc v1.21.0 // indirect
- gopkg.in/yaml.v2 v2.2.2
+ gopkg.in/ini.v1 v1.51.0
+ gopkg.in/yaml.v2 v2.2.4
)
diff --git a/vendor/github.com/spf13/viper/go.sum b/vendor/github.com/spf13/viper/go.sum
index 97afaffe22..d75aee23d8 100644
--- a/vendor/github.com/spf13/viper/go.sum
+++ b/vendor/github.com/spf13/viper/go.sum
@@ -48,6 +48,8 @@ github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y
github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
+github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0 h1:Iju5GlWwrvL6UBg4zJJt3btmonfrMlCDdsejg4CZE7c=
@@ -60,6 +62,8 @@ github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
+github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
+github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
@@ -71,8 +75,8 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
-github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY=
-github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
+github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
+github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
@@ -101,6 +105,10 @@ github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40T
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/sirupsen/logrus v1.2.0 h1:juTguoYk5qI21pwyTXY3B3Y5cOTH3ZUyZCg1v/mihuo=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
+github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
+github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
+github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
+github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/soheilhy/cmux v0.1.4 h1:0HKaf1o97UwFjHH9o5XsHUOF+tqmdA7KEzXLpiyaw0E=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
@@ -115,6 +123,8 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
+github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5 h1:LnC5Kc/wtumK+WB441p7ynQJzVuNRJiqddSIE3IlSEQ=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/ugorji/go v1.1.4 h1:j4s+tAvLfL3bZyefP2SEWmhBzmuIlH/eqNuPdFPgngw=
@@ -159,6 +169,8 @@ golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxb
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190328211700-ab21143f2384 h1:TFlARGu6Czu1z7q93HTxcP1P+/ZFC/IKythI5RzrnRg=
+golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0NQvRW8DG4Yk3Q6T9cu9RcFQDu1tc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
@@ -170,9 +182,11 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
+gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
-gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
+gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
diff --git a/vendor/github.com/spf13/viper/util.go b/vendor/github.com/spf13/viper/util.go
index 952cad44c6..b788969637 100644
--- a/vendor/github.com/spf13/viper/util.go
+++ b/vendor/github.com/spf13/viper/util.go
@@ -114,11 +114,11 @@ func absPathify(inPath string) string {
return ""
}
-// Check if File / Directory Exists
+// Check if file Exists
func exists(fs afero.Fs, path string) (bool, error) {
- _, err := fs.Stat(path)
+ stat, err := fs.Stat(path)
if err == nil {
- return true, nil
+ return !stat.IsDir(), nil
}
if os.IsNotExist(err) {
return false, nil
diff --git a/vendor/github.com/spf13/viper/viper.go b/vendor/github.com/spf13/viper/viper.go
index a3d37f8c2b..265eae7f11 100644
--- a/vendor/github.com/spf13/viper/viper.go
+++ b/vendor/github.com/spf13/viper/viper.go
@@ -3,7 +3,7 @@
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
-// Viper is a application configuration system.
+// Viper is an application configuration system.
// It believes that applications can be configured a variety of ways
// via flags, ENVIRONMENT variables, configuration files retrieved
// from the file system, or a remote key/value store.
@@ -23,6 +23,7 @@ import (
"bytes"
"encoding/csv"
"encoding/json"
+ "errors"
"fmt"
"io"
"log"
@@ -33,18 +34,19 @@ import (
"sync"
"time"
- yaml "gopkg.in/yaml.v2"
-
"github.com/fsnotify/fsnotify"
"github.com/hashicorp/hcl"
"github.com/hashicorp/hcl/hcl/printer"
"github.com/magiconair/properties"
"github.com/mitchellh/mapstructure"
- toml "github.com/pelletier/go-toml"
+ "github.com/pelletier/go-toml"
"github.com/spf13/afero"
"github.com/spf13/cast"
jww "github.com/spf13/jwalterweatherman"
"github.com/spf13/pflag"
+ "github.com/subosito/gotenv"
+ "gopkg.in/ini.v1"
+ "gopkg.in/yaml.v2"
)
// ConfigMarshalError happens when failing to marshal the configuration.
@@ -114,6 +116,14 @@ func (fnfe ConfigFileNotFoundError) Error() string {
return fmt.Sprintf("Config File %q Not Found in %q", fnfe.name, fnfe.locations)
}
+// ConfigFileAlreadyExistsError denotes failure to write new configuration file.
+type ConfigFileAlreadyExistsError string
+
+// Error returns the formatted error when configuration already exists.
+func (faee ConfigFileAlreadyExistsError) Error() string {
+ return fmt.Sprintf("Config File %q Already Exists", string(faee))
+}
+
// A DecoderConfigOption can be passed to viper.Unmarshal to configure
// mapstructure.DecoderConfig options
type DecoderConfigOption func(*mapstructure.DecoderConfig)
@@ -187,7 +197,7 @@ type Viper struct {
envPrefix string
automaticEnvApplied bool
- envKeyReplacer *strings.Replacer
+ envKeyReplacer StringReplacer
allowEmptyEnv bool
config map[string]interface{}
@@ -225,12 +235,58 @@ func New() *Viper {
return v
}
-// Intended for testing, will reset all to default settings.
+// Option configures Viper using the functional options paradigm popularized by Rob Pike and Dave Cheney.
+// If you're unfamiliar with this style,
+// see https://commandcenter.blogspot.com/2014/01/self-referential-functions-and-design.html and
+// https://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis.
+type Option interface {
+ apply(v *Viper)
+}
+
+type optionFunc func(v *Viper)
+
+func (fn optionFunc) apply(v *Viper) {
+ fn(v)
+}
+
+// KeyDelimiter sets the delimiter used for determining key parts.
+// By default it's value is ".".
+func KeyDelimiter(d string) Option {
+ return optionFunc(func(v *Viper) {
+ v.keyDelim = d
+ })
+}
+
+// StringReplacer applies a set of replacements to a string.
+type StringReplacer interface {
+ // Replace returns a copy of s with all replacements performed.
+ Replace(s string) string
+}
+
+// EnvKeyReplacer sets a replacer used for mapping environment variables to internal keys.
+func EnvKeyReplacer(r StringReplacer) Option {
+ return optionFunc(func(v *Viper) {
+ v.envKeyReplacer = r
+ })
+}
+
+// NewWithOptions creates a new Viper instance.
+func NewWithOptions(opts ...Option) *Viper {
+ v := New()
+
+ for _, opt := range opts {
+ opt.apply(v)
+ }
+
+ return v
+}
+
+// Reset is intended for testing, will reset all to default settings.
// In the public interface for the viper package so applications
// can use it in their testing as well.
func Reset() {
v = New()
- SupportedExts = []string{"json", "toml", "yaml", "yml", "properties", "props", "prop", "hcl"}
+ SupportedExts = []string{"json", "toml", "yaml", "yml", "properties", "props", "prop", "hcl", "dotenv", "env", "ini"}
SupportedRemoteProviders = []string{"etcd", "consul"}
}
@@ -269,7 +325,7 @@ type RemoteProvider interface {
}
// SupportedExts are universally supported extensions.
-var SupportedExts = []string{"json", "toml", "yaml", "yml", "properties", "props", "prop", "hcl"}
+var SupportedExts = []string{"json", "toml", "yaml", "yml", "properties", "props", "prop", "hcl", "dotenv", "env", "ini"}
// SupportedRemoteProviders are universally supported remote providers.
var SupportedRemoteProviders = []string{"etcd", "consul"}
@@ -294,6 +350,7 @@ func (v *Viper) WatchConfig() {
filename, err := v.getConfigFile()
if err != nil {
log.Printf("error: %v\n", err)
+ initWG.Done()
return
}
@@ -343,7 +400,7 @@ func (v *Viper) WatchConfig() {
}
}()
watcher.Add(configDir)
- initWG.Done() // done initalizing the watch in this go routine, so the parent routine can move on...
+ initWG.Done() // done initializing the watch in this go routine, so the parent routine can move on...
eventsWG.Wait() // now, wait for event loop to end in this go-routine...
}()
initWG.Wait() // make sure that the go routine above fully ended before returning
@@ -668,7 +725,7 @@ func GetViper() *Viper {
func Get(key string) interface{} { return v.Get(key) }
func (v *Viper) Get(key string) interface{} {
lcaseKey := strings.ToLower(key)
- val := v.find(lcaseKey)
+ val := v.find(lcaseKey, true)
if val == nil {
return nil
}
@@ -705,6 +762,8 @@ func (v *Viper) Get(key string) interface{} {
return cast.ToDuration(val)
case []string:
return cast.ToStringSlice(val)
+ case []int:
+ return cast.ToIntSlice(val)
}
}
@@ -794,6 +853,12 @@ func (v *Viper) GetDuration(key string) time.Duration {
return cast.ToDuration(v.Get(key))
}
+// GetIntSlice returns the value associated with the key as a slice of int values.
+func GetIntSlice(key string) []int { return v.GetIntSlice(key) }
+func (v *Viper) GetIntSlice(key string) []int {
+ return cast.ToIntSlice(v.Get(key))
+}
+
// GetStringSlice returns the value associated with the key as a slice of strings.
func GetStringSlice(key string) []string { return v.GetStringSlice(key) }
func (v *Viper) GetStringSlice(key string) []string {
@@ -884,8 +949,11 @@ func decode(input interface{}, config *mapstructure.DecoderConfig) error {
// UnmarshalExact unmarshals the config into a Struct, erroring if a field is nonexistent
// in the destination struct.
-func (v *Viper) UnmarshalExact(rawVal interface{}) error {
- config := defaultDecoderConfig(rawVal)
+func UnmarshalExact(rawVal interface{}, opts ...DecoderConfigOption) error {
+ return v.UnmarshalExact(rawVal, opts...)
+}
+func (v *Viper) UnmarshalExact(rawVal interface{}, opts ...DecoderConfigOption) error {
+ config := defaultDecoderConfig(rawVal, opts...)
config.ErrorUnused = true
err := decode(v.AllSettings(), config)
@@ -950,7 +1018,7 @@ func BindEnv(input ...string) error { return v.BindEnv(input...) }
func (v *Viper) BindEnv(input ...string) error {
var key, envkey string
if len(input) == 0 {
- return fmt.Errorf("BindEnv missing key to bind to")
+ return fmt.Errorf("missing key to bind to")
}
key = strings.ToLower(input[0])
@@ -967,12 +1035,15 @@ func (v *Viper) BindEnv(input ...string) error {
}
// Given a key, find the value.
-// Viper will check in the following order:
-// flag, env, config file, key/value store, default.
+//
// Viper will check to see if an alias exists first.
+// Viper will then check in the following order:
+// flag, env, config file, key/value store.
+// Lastly, if no value was found and flagDefault is true, and if the key
+// corresponds to a flag, the flag's default value is returned.
+//
// Note: this assumes a lower-cased key given.
-func (v *Viper) find(lcaseKey string) interface{} {
-
+func (v *Viper) find(lcaseKey string, flagDefault bool) interface{} {
var (
val interface{}
exists bool
@@ -1012,6 +1083,11 @@ func (v *Viper) find(lcaseKey string) interface{} {
s = strings.TrimSuffix(s, "]")
res, _ := readAsCSV(s)
return res
+ case "intSlice":
+ s := strings.TrimPrefix(flag.ValueString(), "[")
+ s = strings.TrimSuffix(s, "]")
+ res, _ := readAsCSV(s)
+ return cast.ToIntSlice(res)
default:
return flag.ValueString()
}
@@ -1068,24 +1144,31 @@ func (v *Viper) find(lcaseKey string) interface{} {
return nil
}
- // last chance: if no other value is returned and a flag does exist for the value,
- // get the flag's value even if the flag's value has not changed
- if flag, exists := v.pflags[lcaseKey]; exists {
- switch flag.ValueType() {
- case "int", "int8", "int16", "int32", "int64":
- return cast.ToInt(flag.ValueString())
- case "bool":
- return cast.ToBool(flag.ValueString())
- case "stringSlice":
- s := strings.TrimPrefix(flag.ValueString(), "[")
- s = strings.TrimSuffix(s, "]")
- res, _ := readAsCSV(s)
- return res
- default:
- return flag.ValueString()
+ if flagDefault {
+ // last chance: if no value is found and a flag does exist for the key,
+ // get the flag's default value even if the flag's value has not been set.
+ if flag, exists := v.pflags[lcaseKey]; exists {
+ switch flag.ValueType() {
+ case "int", "int8", "int16", "int32", "int64":
+ return cast.ToInt(flag.ValueString())
+ case "bool":
+ return cast.ToBool(flag.ValueString())
+ case "stringSlice":
+ s := strings.TrimPrefix(flag.ValueString(), "[")
+ s = strings.TrimSuffix(s, "]")
+ res, _ := readAsCSV(s)
+ return res
+ case "intSlice":
+ s := strings.TrimPrefix(flag.ValueString(), "[")
+ s = strings.TrimSuffix(s, "]")
+ res, _ := readAsCSV(s)
+ return cast.ToIntSlice(res)
+ default:
+ return flag.ValueString()
+ }
}
+ // last item, no need to check shadowing
}
- // last item, no need to check shadowing
return nil
}
@@ -1104,7 +1187,7 @@ func readAsCSV(val string) ([]string, error) {
func IsSet(key string) bool { return v.IsSet(key) }
func (v *Viper) IsSet(key string) bool {
lcaseKey := strings.ToLower(key)
- val := v.find(lcaseKey)
+ val := v.find(lcaseKey, false)
return val != nil
}
@@ -1123,8 +1206,8 @@ func (v *Viper) SetEnvKeyReplacer(r *strings.Replacer) {
v.envKeyReplacer = r
}
-// Aliases provide another accessor for the same key.
-// This enables one to change a name without breaking the application
+// RegisterAlias creates an alias that provides another accessor for the same key.
+// This enables one to change a name without breaking the application.
func RegisterAlias(alias string, key string) { v.RegisterAlias(alias, key) }
func (v *Viper) RegisterAlias(alias string, key string) {
v.registerAlias(alias, strings.ToLower(key))
@@ -1311,11 +1394,10 @@ func (v *Viper) WriteConfig() error {
// SafeWriteConfig writes current configuration to file only if the file does not exist.
func SafeWriteConfig() error { return v.SafeWriteConfig() }
func (v *Viper) SafeWriteConfig() error {
- filename, err := v.getConfigFile()
- if err != nil {
- return err
+ if len(v.configPaths) < 1 {
+ return errors.New("missing configuration for 'configPath'")
}
- return v.writeConfig(filename, false)
+ return v.SafeWriteConfigAs(filepath.Join(v.configPaths[0], v.configName+"."+v.configType))
}
// WriteConfigAs writes current configuration to a given filename.
@@ -1327,15 +1409,18 @@ func (v *Viper) WriteConfigAs(filename string) error {
// SafeWriteConfigAs writes current configuration to a given filename if it does not exist.
func SafeWriteConfigAs(filename string) error { return v.SafeWriteConfigAs(filename) }
func (v *Viper) SafeWriteConfigAs(filename string) error {
+ alreadyExists, err := afero.Exists(v.fs, filename)
+ if alreadyExists && err == nil {
+ return ConfigFileAlreadyExistsError(filename)
+ }
return v.writeConfig(filename, false)
}
-func writeConfig(filename string, force bool) error { return v.writeConfig(filename, force) }
func (v *Viper) writeConfig(filename string, force bool) error {
jww.INFO.Println("Attempting to write configuration to file.")
ext := filepath.Ext(filename)
if len(ext) <= 1 {
- return fmt.Errorf("Filename: %s requires valid extension.", filename)
+ return fmt.Errorf("filename: %s requires valid extension", filename)
}
configType := ext[1:]
if !stringInSlice(configType, SupportedExts) {
@@ -1344,21 +1429,21 @@ func (v *Viper) writeConfig(filename string, force bool) error {
if v.config == nil {
v.config = make(map[string]interface{})
}
- var flags int
- if force == true {
- flags = os.O_CREATE | os.O_TRUNC | os.O_WRONLY
- } else {
- if _, err := os.Stat(filename); os.IsNotExist(err) {
- flags = os.O_WRONLY
- } else {
- return fmt.Errorf("File: %s exists. Use WriteConfig to overwrite.", filename)
- }
+ flags := os.O_CREATE | os.O_TRUNC | os.O_WRONLY
+ if !force {
+ flags |= os.O_EXCL
}
f, err := v.fs.OpenFile(filename, flags, v.configPermissions)
if err != nil {
return err
}
- return v.marshalWriter(f, configType)
+ defer f.Close()
+
+ if err := v.marshalWriter(f, configType); err != nil {
+ return err
+ }
+
+ return f.Sync()
}
// Unmarshal a Reader into a map.
@@ -1382,7 +1467,7 @@ func (v *Viper) unmarshalReader(in io.Reader, c map[string]interface{}) error {
}
case "hcl":
- obj, err := hcl.Parse(string(buf.Bytes()))
+ obj, err := hcl.Parse(buf.String())
if err != nil {
return ConfigParseError{err}
}
@@ -1400,6 +1485,15 @@ func (v *Viper) unmarshalReader(in io.Reader, c map[string]interface{}) error {
c[k] = v
}
+ case "dotenv", "env":
+ env, err := gotenv.StrictParse(buf)
+ if err != nil {
+ return ConfigParseError{err}
+ }
+ for k, v := range env {
+ c[k] = v
+ }
+
case "properties", "props", "prop":
v.properties = properties.NewProperties()
var err error
@@ -1415,6 +1509,23 @@ func (v *Viper) unmarshalReader(in io.Reader, c map[string]interface{}) error {
// set innermost value
deepestMap[lastKey] = value
}
+
+ case "ini":
+ cfg := ini.Empty()
+ err := cfg.Append(buf.Bytes())
+ if err != nil {
+ return ConfigParseError{err}
+ }
+ sections := cfg.Sections()
+ for i := 0; i < len(sections); i++ {
+ section := sections[i]
+ keys := section.Keys()
+ for j := 0; j < len(keys); j++ {
+ key := keys[j]
+ value := cfg.Section(section.Name()).Key(key.Name()).String()
+ c[section.Name()+"."+key.Name()] = value
+ }
+ }
}
insensitiviseMap(c)
@@ -1422,9 +1533,6 @@ func (v *Viper) unmarshalReader(in io.Reader, c map[string]interface{}) error {
}
// Marshal a map into Writer.
-func marshalWriter(f afero.File, configType string) error {
- return v.marshalWriter(f, configType)
-}
func (v *Viper) marshalWriter(f afero.File, configType string) error {
c := v.AllSettings()
switch configType {
@@ -1440,6 +1548,9 @@ func (v *Viper) marshalWriter(f afero.File, configType string) error {
case "hcl":
b, err := json.Marshal(c)
+ if err != nil {
+ return ConfigMarshalError{err}
+ }
ast, err := hcl.Parse(string(b))
if err != nil {
return ConfigMarshalError{err}
@@ -1465,6 +1576,18 @@ func (v *Viper) marshalWriter(f afero.File, configType string) error {
return ConfigMarshalError{err}
}
+ case "dotenv", "env":
+ lines := []string{}
+ for _, key := range v.AllKeys() {
+ envName := strings.ToUpper(strings.Replace(key, ".", "_", -1))
+ val := v.Get(key)
+ lines = append(lines, fmt.Sprintf("%v=%v", envName, val))
+ }
+ s := strings.Join(lines, "\n")
+ if _, err := f.WriteString(s); err != nil {
+ return ConfigMarshalError{err}
+ }
+
case "toml":
t, err := toml.TreeFromMap(c)
if err != nil {
@@ -1483,6 +1606,22 @@ func (v *Viper) marshalWriter(f afero.File, configType string) error {
if _, err = f.WriteString(string(b)); err != nil {
return ConfigMarshalError{err}
}
+
+ case "ini":
+ keys := v.AllKeys()
+ cfg := ini.Empty()
+ ini.PrettyFormat = false
+ for i := 0; i < len(keys); i++ {
+ key := keys[i]
+ lastSep := strings.LastIndex(key, ".")
+ sectionName := key[:(lastSep)]
+ keyName := key[(lastSep + 1):]
+ if sectionName == "default" {
+ sectionName = ""
+ }
+ cfg.Section(sectionName).Key(keyName).SetValue(Get(key).(string))
+ }
+ cfg.WriteTo(f)
}
return nil
}
@@ -1629,7 +1768,7 @@ func (v *Viper) getRemoteConfig(provider RemoteProvider) (map[string]interface{}
func (v *Viper) watchKeyValueConfigOnChannel() error {
for _, rp := range v.remoteProviders {
respc, _ := RemoteConfig.WatchChannel(rp)
- //Todo: Add quit channel
+ // Todo: Add quit channel
go func(rc <-chan *RemoteResponse) {
for {
b := <-rc
@@ -1665,7 +1804,7 @@ func (v *Viper) watchRemoteConfig(provider RemoteProvider) (map[string]interface
}
// AllKeys returns all keys holding a value, regardless of where they are set.
-// Nested keys are returned with a v.keyDelim (= ".") separator
+// Nested keys are returned with a v.keyDelim separator
func AllKeys() []string { return v.AllKeys() }
func (v *Viper) AllKeys() []string {
m := map[string]bool{}
@@ -1679,7 +1818,7 @@ func (v *Viper) AllKeys() []string {
m = v.flattenAndMergeMap(m, v.defaults, "")
// convert set of paths to list
- a := []string{}
+ a := make([]string, 0, len(m))
for x := range m {
a = append(a, x)
}
@@ -1688,7 +1827,7 @@ func (v *Viper) AllKeys() []string {
// flattenAndMergeMap recursively flattens the given map into a map[string]bool
// of key paths (used as a set, easier to manipulate than a []string):
-// - each path is merged into a single key string, delimited with v.keyDelim (= ".")
+// - each path is merged into a single key string, delimited with v.keyDelim
// - if a path is shadowed by an earlier value in the initial shadow map,
// it is skipped.
// The resulting set of paths is merged to the given shadow set at the same time.
@@ -1728,7 +1867,7 @@ func (v *Viper) flattenAndMergeMap(shadow map[string]bool, m map[string]interfac
func (v *Viper) mergeFlatMap(shadow map[string]bool, m map[string]interface{}) map[string]bool {
// scan keys
outer:
- for k, _ := range m {
+ for k := range m {
path := strings.Split(k, v.keyDelim)
// scan intermediate paths
var parentKey string
@@ -1837,6 +1976,12 @@ func (v *Viper) searchInPath(in string) (filename string) {
}
}
+ if v.configType != "" {
+ if b, _ := exists(v.fs, filepath.Join(in, v.configName)); b {
+ return filepath.Join(in, v.configName)
+ }
+ }
+
return ""
}
diff --git a/vendor/github.com/subosito/gotenv/.env b/vendor/github.com/subosito/gotenv/.env
new file mode 100644
index 0000000000..6405eca71f
--- /dev/null
+++ b/vendor/github.com/subosito/gotenv/.env
@@ -0,0 +1 @@
+HELLO=world
diff --git a/vendor/github.com/subosito/gotenv/.env.invalid b/vendor/github.com/subosito/gotenv/.env.invalid
new file mode 100644
index 0000000000..016d5e0cea
--- /dev/null
+++ b/vendor/github.com/subosito/gotenv/.env.invalid
@@ -0,0 +1 @@
+lol$wut
diff --git a/vendor/github.com/subosito/gotenv/.gitignore b/vendor/github.com/subosito/gotenv/.gitignore
new file mode 100644
index 0000000000..2b8d456103
--- /dev/null
+++ b/vendor/github.com/subosito/gotenv/.gitignore
@@ -0,0 +1,3 @@
+*.test
+*.out
+annotate.json
diff --git a/vendor/github.com/subosito/gotenv/.travis.yml b/vendor/github.com/subosito/gotenv/.travis.yml
new file mode 100644
index 0000000000..3370d5f408
--- /dev/null
+++ b/vendor/github.com/subosito/gotenv/.travis.yml
@@ -0,0 +1,10 @@
+language: go
+go:
+ - 1.x
+os:
+ - linux
+ - osx
+script:
+ - go test -test.v -coverprofile=coverage.out -covermode=count
+after_success:
+ - bash <(curl -s https://codecov.io/bash)
diff --git a/vendor/github.com/subosito/gotenv/CHANGELOG.md b/vendor/github.com/subosito/gotenv/CHANGELOG.md
new file mode 100644
index 0000000000..67f687382b
--- /dev/null
+++ b/vendor/github.com/subosito/gotenv/CHANGELOG.md
@@ -0,0 +1,47 @@
+# Changelog
+
+## [1.2.0] - 2019-08-03
+
+### Added
+
+- Add `Must` helper to raise an error as panic. It can be used with `Load` and `OverLoad`.
+- Add more tests to be 100% coverage.
+- Add CHANGELOG
+- Add more OS for the test: OSX and Windows
+
+### Changed
+
+- Reduce complexity and improve source code for having `A+` score in [goreportcard](https://goreportcard.com/report/github.com/subosito/gotenv).
+- Updated README with mentions to all available functions
+
+### Removed
+
+- Remove `ErrFormat`
+- Remove `MustLoad` and `MustOverload`, replaced with `Must` helper.
+
+## [1.1.1] - 2018-06-05
+
+### Changed
+
+- Replace `os.Getenv` with `os.LookupEnv` to ensure that the environment variable is not set, by [radding](https://github.com/radding)
+
+## [1.1.0] - 2017-03-20
+
+### Added
+
+- Supports carriage return in env
+- Handle files with UTF-8 BOM
+
+### Changed
+
+- Whitespace handling
+
+### Fixed
+
+- Incorrect variable expansion
+- Handling escaped '$' characters
+
+## [1.0.0] - 2014-10-05
+
+First stable release.
+
diff --git a/vendor/github.com/subosito/gotenv/LICENSE b/vendor/github.com/subosito/gotenv/LICENSE
new file mode 100644
index 0000000000..f64ccaedc3
--- /dev/null
+++ b/vendor/github.com/subosito/gotenv/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2013 Alif Rachmawadi
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/vendor/github.com/subosito/gotenv/README.md b/vendor/github.com/subosito/gotenv/README.md
new file mode 100644
index 0000000000..d610cdf0b8
--- /dev/null
+++ b/vendor/github.com/subosito/gotenv/README.md
@@ -0,0 +1,131 @@
+# gotenv
+
+[![Build Status](https://travis-ci.org/subosito/gotenv.svg?branch=master)](https://travis-ci.org/subosito/gotenv)
+[![Build status](https://ci.appveyor.com/api/projects/status/wb2e075xkfl0m0v2/branch/master?svg=true)](https://ci.appveyor.com/project/subosito/gotenv/branch/master)
+[![Coverage Status](https://badgen.net/codecov/c/github/subosito/gotenv)](https://codecov.io/gh/subosito/gotenv)
+[![Go Report Card](https://goreportcard.com/badge/github.com/subosito/gotenv)](https://goreportcard.com/report/github.com/subosito/gotenv)
+[![GoDoc](https://godoc.org/github.com/subosito/gotenv?status.svg)](https://godoc.org/github.com/subosito/gotenv)
+
+Load environment variables dynamically in Go.
+
+## Usage
+
+Put the gotenv package on your `import` statement:
+
+```go
+import "github.com/subosito/gotenv"
+```
+
+To modify your app environment variables, `gotenv` expose 2 main functions:
+
+- `gotenv.Load`
+- `gotenv.Apply`
+
+By default, `gotenv.Load` will look for a file called `.env` in the current working directory.
+
+Behind the scene, it will then load `.env` file and export the valid variables to the environment variables. Make sure you call the method as soon as possible to ensure it loads all variables, say, put it on `init()` function.
+
+Once loaded you can use `os.Getenv()` to get the value of the variable.
+
+Let's say you have `.env` file:
+
+```
+APP_ID=1234567
+APP_SECRET=abcdef
+```
+
+Here's the example of your app:
+
+```go
+package main
+
+import (
+ "github.com/subosito/gotenv"
+ "log"
+ "os"
+)
+
+func init() {
+ gotenv.Load()
+}
+
+func main() {
+ log.Println(os.Getenv("APP_ID")) // "1234567"
+ log.Println(os.Getenv("APP_SECRET")) // "abcdef"
+}
+```
+
+You can also load other than `.env` file if you wish. Just supply filenames when calling `Load()`. It will load them in order and the first value set for a variable will win.:
+
+```go
+gotenv.Load(".env.production", "credentials")
+```
+
+While `gotenv.Load` loads entries from `.env` file, `gotenv.Apply` allows you to use any `io.Reader`:
+
+```go
+gotenv.Apply(strings.NewReader("APP_ID=1234567"))
+
+log.Println(os.Getenv("APP_ID"))
+// Output: "1234567"
+```
+
+Both `gotenv.Load` and `gotenv.Apply` **DO NOT** overrides existing environment variables. If you want to override existing ones, you can see section below.
+
+### Environment Overrides
+
+Besides above functions, `gotenv` also provides another functions that overrides existing:
+
+- `gotenv.OverLoad`
+- `gotenv.OverApply`
+
+
+Here's the example of this overrides behavior:
+
+```go
+os.Setenv("HELLO", "world")
+
+// NOTE: using Apply existing value will be reserved
+gotenv.Apply(strings.NewReader("HELLO=universe"))
+fmt.Println(os.Getenv("HELLO"))
+// Output: "world"
+
+// NOTE: using OverApply existing value will be overridden
+gotenv.OverApply(strings.NewReader("HELLO=universe"))
+fmt.Println(os.Getenv("HELLO"))
+// Output: "universe"
+```
+
+### Throw a Panic
+
+Both `gotenv.Load` and `gotenv.OverLoad` returns an error on something wrong occurred, like your env file is not exist, and so on. To make it easier to use, `gotenv` also provides `gotenv.Must` helper, to let it panic when an error returned.
+
+```go
+err := gotenv.Load(".env-is-not-exist")
+fmt.Println("error", err)
+// error: open .env-is-not-exist: no such file or directory
+
+gotenv.Must(gotenv.Load, ".env-is-not-exist")
+// it will throw a panic
+// panic: open .env-is-not-exist: no such file or directory
+```
+
+### Another Scenario
+
+Just in case you want to parse environment variables from any `io.Reader`, gotenv keeps its `Parse` and `StrictParse` function as public API so you can use that.
+
+```go
+// import "strings"
+
+pairs := gotenv.Parse(strings.NewReader("FOO=test\nBAR=$FOO"))
+// gotenv.Env{"FOO": "test", "BAR": "test"}
+
+err, pairs = gotenv.StrictParse(strings.NewReader(`FOO="bar"`))
+// gotenv.Env{"FOO": "bar"}
+```
+
+`Parse` ignores invalid lines and returns `Env` of valid environment variables, while `StrictParse` returns an error for invalid lines.
+
+## Notes
+
+The gotenv package is a Go port of [`dotenv`](https://github.com/bkeepers/dotenv) project with some additions made for Go. For general features, it aims to be compatible as close as possible.
diff --git a/vendor/github.com/subosito/gotenv/appveyor.yml b/vendor/github.com/subosito/gotenv/appveyor.yml
new file mode 100644
index 0000000000..33b4c40465
--- /dev/null
+++ b/vendor/github.com/subosito/gotenv/appveyor.yml
@@ -0,0 +1,9 @@
+build: off
+clone_folder: c:\gopath\src\github.com\subosito\gotenv
+environment:
+ GOPATH: c:\gopath
+stack: go 1.10
+before_test:
+ - go get -t
+test_script:
+ - go test -v -cover -race
diff --git a/vendor/github.com/subosito/gotenv/gotenv.go b/vendor/github.com/subosito/gotenv/gotenv.go
new file mode 100644
index 0000000000..745a344899
--- /dev/null
+++ b/vendor/github.com/subosito/gotenv/gotenv.go
@@ -0,0 +1,265 @@
+// Package gotenv provides functionality to dynamically load the environment variables
+package gotenv
+
+import (
+ "bufio"
+ "fmt"
+ "io"
+ "os"
+ "regexp"
+ "strings"
+)
+
+const (
+ // Pattern for detecting valid line format
+ linePattern = `\A\s*(?:export\s+)?([\w\.]+)(?:\s*=\s*|:\s+?)('(?:\'|[^'])*'|"(?:\"|[^"])*"|[^#\n]+)?\s*(?:\s*\#.*)?\z`
+
+ // Pattern for detecting valid variable within a value
+ variablePattern = `(\\)?(\$)(\{?([A-Z0-9_]+)?\}?)`
+)
+
+// Env holds key/value pair of valid environment variable
+type Env map[string]string
+
+/*
+Load is a function to load a file or multiple files and then export the valid variables into environment variables if they do not exist.
+When it's called with no argument, it will load `.env` file on the current path and set the environment variables.
+Otherwise, it will loop over the filenames parameter and set the proper environment variables.
+*/
+func Load(filenames ...string) error {
+ return loadenv(false, filenames...)
+}
+
+/*
+OverLoad is a function to load a file or multiple files and then export and override the valid variables into environment variables.
+*/
+func OverLoad(filenames ...string) error {
+ return loadenv(true, filenames...)
+}
+
+/*
+Must is wrapper function that will panic when supplied function returns an error.
+*/
+func Must(fn func(filenames ...string) error, filenames ...string) {
+ if err := fn(filenames...); err != nil {
+ panic(err.Error())
+ }
+}
+
+/*
+Apply is a function to load an io Reader then export the valid variables into environment variables if they do not exist.
+*/
+func Apply(r io.Reader) error {
+ return parset(r, false)
+}
+
+/*
+OverApply is a function to load an io Reader then export and override the valid variables into environment variables.
+*/
+func OverApply(r io.Reader) error {
+ return parset(r, true)
+}
+
+func loadenv(override bool, filenames ...string) error {
+ if len(filenames) == 0 {
+ filenames = []string{".env"}
+ }
+
+ for _, filename := range filenames {
+ f, err := os.Open(filename)
+ if err != nil {
+ return err
+ }
+
+ err = parset(f, override)
+ if err != nil {
+ return err
+ }
+
+ f.Close()
+ }
+
+ return nil
+}
+
+// parse and set :)
+func parset(r io.Reader, override bool) error {
+ env, err := StrictParse(r)
+ if err != nil {
+ return err
+ }
+
+ for key, val := range env {
+ setenv(key, val, override)
+ }
+
+ return nil
+}
+
+func setenv(key, val string, override bool) {
+ if override {
+ os.Setenv(key, val)
+ } else {
+ if _, present := os.LookupEnv(key); !present {
+ os.Setenv(key, val)
+ }
+ }
+}
+
+// Parse is a function to parse line by line any io.Reader supplied and returns the valid Env key/value pair of valid variables.
+// It expands the value of a variable from the environment variable but does not set the value to the environment itself.
+// This function is skipping any invalid lines and only processing the valid one.
+func Parse(r io.Reader) Env {
+ env, _ := StrictParse(r)
+ return env
+}
+
+// StrictParse is a function to parse line by line any io.Reader supplied and returns the valid Env key/value pair of valid variables.
+// It expands the value of a variable from the environment variable but does not set the value to the environment itself.
+// This function is returning an error if there are any invalid lines.
+func StrictParse(r io.Reader) (Env, error) {
+ env := make(Env)
+ scanner := bufio.NewScanner(r)
+
+ i := 1
+ bom := string([]byte{239, 187, 191})
+
+ for scanner.Scan() {
+ line := scanner.Text()
+
+ if i == 1 {
+ line = strings.TrimPrefix(line, bom)
+ }
+
+ i++
+
+ err := parseLine(line, env)
+ if err != nil {
+ return env, err
+ }
+ }
+
+ return env, nil
+}
+
+func parseLine(s string, env Env) error {
+ rl := regexp.MustCompile(linePattern)
+ rm := rl.FindStringSubmatch(s)
+
+ if len(rm) == 0 {
+ return checkFormat(s, env)
+ }
+
+ key := rm[1]
+ val := rm[2]
+
+ // determine if string has quote prefix
+ hdq := strings.HasPrefix(val, `"`)
+
+ // determine if string has single quote prefix
+ hsq := strings.HasPrefix(val, `'`)
+
+ // trim whitespace
+ val = strings.Trim(val, " ")
+
+ // remove quotes '' or ""
+ rq := regexp.MustCompile(`\A(['"])(.*)(['"])\z`)
+ val = rq.ReplaceAllString(val, "$2")
+
+ if hdq {
+ val = strings.Replace(val, `\n`, "\n", -1)
+ val = strings.Replace(val, `\r`, "\r", -1)
+
+ // Unescape all characters except $ so variables can be escaped properly
+ re := regexp.MustCompile(`\\([^$])`)
+ val = re.ReplaceAllString(val, "$1")
+ }
+
+ rv := regexp.MustCompile(variablePattern)
+ fv := func(s string) string {
+ return varReplacement(s, hsq, env)
+ }
+
+ val = rv.ReplaceAllStringFunc(val, fv)
+ val = parseVal(val, env)
+
+ env[key] = val
+ return nil
+}
+
+func parseExport(st string, env Env) error {
+ if strings.HasPrefix(st, "export") {
+ vs := strings.SplitN(st, " ", 2)
+
+ if len(vs) > 1 {
+ if _, ok := env[vs[1]]; !ok {
+ return fmt.Errorf("line `%s` has an unset variable", st)
+ }
+ }
+ }
+
+ return nil
+}
+
+func varReplacement(s string, hsq bool, env Env) string {
+ if strings.HasPrefix(s, "\\") {
+ return strings.TrimPrefix(s, "\\")
+ }
+
+ if hsq {
+ return s
+ }
+
+ sn := `(\$)(\{?([A-Z0-9_]+)\}?)`
+ rn := regexp.MustCompile(sn)
+ mn := rn.FindStringSubmatch(s)
+
+ if len(mn) == 0 {
+ return s
+ }
+
+ v := mn[3]
+
+ replace, ok := env[v]
+ if !ok {
+ replace = os.Getenv(v)
+ }
+
+ return replace
+}
+
+func checkFormat(s string, env Env) error {
+ st := strings.TrimSpace(s)
+
+ if (st == "") || strings.HasPrefix(st, "#") {
+ return nil
+ }
+
+ if err := parseExport(st, env); err != nil {
+ return err
+ }
+
+ return fmt.Errorf("line `%s` doesn't match format", s)
+}
+
+func parseVal(val string, env Env) string {
+ if strings.Contains(val, "=") {
+ if !(val == "\n" || val == "\r") {
+ kv := strings.Split(val, "\n")
+
+ if len(kv) == 1 {
+ kv = strings.Split(val, "\r")
+ }
+
+ if len(kv) > 1 {
+ val = kv[0]
+
+ for i := 1; i < len(kv); i++ {
+ parseLine(kv[i], env)
+ }
+ }
+ }
+ }
+
+ return val
+}
diff --git a/vendor/gopkg.in/ini.v1/.gitignore b/vendor/gopkg.in/ini.v1/.gitignore
new file mode 100644
index 0000000000..12411127b3
--- /dev/null
+++ b/vendor/gopkg.in/ini.v1/.gitignore
@@ -0,0 +1,6 @@
+testdata/conf_out.ini
+ini.sublime-project
+ini.sublime-workspace
+testdata/conf_reflect.ini
+.idea
+/.vscode
diff --git a/vendor/gopkg.in/ini.v1/.travis.yml b/vendor/gopkg.in/ini.v1/.travis.yml
new file mode 100644
index 0000000000..149b7249f6
--- /dev/null
+++ b/vendor/gopkg.in/ini.v1/.travis.yml
@@ -0,0 +1,20 @@
+sudo: false
+language: go
+go:
+ - 1.6.x
+ - 1.7.x
+ - 1.8.x
+ - 1.9.x
+ - 1.10.x
+ - 1.11.x
+ - 1.12.x
+ - 1.13.x
+
+install: skip
+script:
+ - go get golang.org/x/tools/cmd/cover
+ - go get github.com/smartystreets/goconvey
+ - mkdir -p $HOME/gopath/src/gopkg.in
+ - ln -s $HOME/gopath/src/github.com/go-ini/ini $HOME/gopath/src/gopkg.in/ini.v1
+ - cd $HOME/gopath/src/gopkg.in/ini.v1
+ - go test -v -cover -race
diff --git a/vendor/gopkg.in/ini.v1/LICENSE b/vendor/gopkg.in/ini.v1/LICENSE
new file mode 100644
index 0000000000..d361bbcdf5
--- /dev/null
+++ b/vendor/gopkg.in/ini.v1/LICENSE
@@ -0,0 +1,191 @@
+Apache License
+Version 2.0, January 2004
+http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+"License" shall mean the terms and conditions for use, reproduction, and
+distribution as defined by Sections 1 through 9 of this document.
+
+"Licensor" shall mean the copyright owner or entity authorized by the copyright
+owner that is granting the License.
+
+"Legal Entity" shall mean the union of the acting entity and all other entities
+that control, are controlled by, or are under common control with that entity.
+For the purposes of this definition, "control" means (i) the power, direct or
+indirect, to cause the direction or management of such entity, whether by
+contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
+outstanding shares, or (iii) beneficial ownership of such entity.
+
+"You" (or "Your") shall mean an individual or Legal Entity exercising
+permissions granted by this License.
+
+"Source" form shall mean the preferred form for making modifications, including
+but not limited to software source code, documentation source, and configuration
+files.
+
+"Object" form shall mean any form resulting from mechanical transformation or
+translation of a Source form, including but not limited to compiled object code,
+generated documentation, and conversions to other media types.
+
+"Work" shall mean the work of authorship, whether in Source or Object form, made
+available under the License, as indicated by a copyright notice that is included
+in or attached to the work (an example is provided in the Appendix below).
+
+"Derivative Works" shall mean any work, whether in Source or Object form, that
+is based on (or derived from) the Work and for which the editorial revisions,
+annotations, elaborations, or other modifications represent, as a whole, an
+original work of authorship. For the purposes of this License, Derivative Works
+shall not include works that remain separable from, or merely link (or bind by
+name) to the interfaces of, the Work and Derivative Works thereof.
+
+"Contribution" shall mean any work of authorship, including the original version
+of the Work and any modifications or additions to that Work or Derivative Works
+thereof, that is intentionally submitted to Licensor for inclusion in the Work
+by the copyright owner or by an individual or Legal Entity authorized to submit
+on behalf of the copyright owner. For the purposes of this definition,
+"submitted" means any form of electronic, verbal, or written communication sent
+to the Licensor or its representatives, including but not limited to
+communication on electronic mailing lists, source code control systems, and
+issue tracking systems that are managed by, or on behalf of, the Licensor for
+the purpose of discussing and improving the Work, but excluding communication
+that is conspicuously marked or otherwise designated in writing by the copyright
+owner as "Not a Contribution."
+
+"Contributor" shall mean Licensor and any individual or Legal Entity on behalf
+of whom a Contribution has been received by Licensor and subsequently
+incorporated within the Work.
+
+2. Grant of Copyright License.
+
+Subject to the terms and conditions of this License, each Contributor hereby
+grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
+irrevocable copyright license to reproduce, prepare Derivative Works of,
+publicly display, publicly perform, sublicense, and distribute the Work and such
+Derivative Works in Source or Object form.
+
+3. Grant of Patent License.
+
+Subject to the terms and conditions of this License, each Contributor hereby
+grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
+irrevocable (except as stated in this section) patent license to make, have
+made, use, offer to sell, sell, import, and otherwise transfer the Work, where
+such license applies only to those patent claims licensable by such Contributor
+that are necessarily infringed by their Contribution(s) alone or by combination
+of their Contribution(s) with the Work to which such Contribution(s) was
+submitted. If You institute patent litigation against any entity (including a
+cross-claim or counterclaim in a lawsuit) alleging that the Work or a
+Contribution incorporated within the Work constitutes direct or contributory
+patent infringement, then any patent licenses granted to You under this License
+for that Work shall terminate as of the date such litigation is filed.
+
+4. Redistribution.
+
+You may reproduce and distribute copies of the Work or Derivative Works thereof
+in any medium, with or without modifications, and in Source or Object form,
+provided that You meet the following conditions:
+
+You must give any other recipients of the Work or Derivative Works a copy of
+this License; and
+You must cause any modified files to carry prominent notices stating that You
+changed the files; and
+You must retain, in the Source form of any Derivative Works that You distribute,
+all copyright, patent, trademark, and attribution notices from the Source form
+of the Work, excluding those notices that do not pertain to any part of the
+Derivative Works; and
+If the Work includes a "NOTICE" text file as part of its distribution, then any
+Derivative Works that You distribute must include a readable copy of the
+attribution notices contained within such NOTICE file, excluding those notices
+that do not pertain to any part of the Derivative Works, in at least one of the
+following places: within a NOTICE text file distributed as part of the
+Derivative Works; within the Source form or documentation, if provided along
+with the Derivative Works; or, within a display generated by the Derivative
+Works, if and wherever such third-party notices normally appear. The contents of
+the NOTICE file are for informational purposes only and do not modify the
+License. You may add Your own attribution notices within Derivative Works that
+You distribute, alongside or as an addendum to the NOTICE text from the Work,
+provided that such additional attribution notices cannot be construed as
+modifying the License.
+You may add Your own copyright statement to Your modifications and may provide
+additional or different license terms and conditions for use, reproduction, or
+distribution of Your modifications, or for any such Derivative Works as a whole,
+provided Your use, reproduction, and distribution of the Work otherwise complies
+with the conditions stated in this License.
+
+5. Submission of Contributions.
+
+Unless You explicitly state otherwise, any Contribution intentionally submitted
+for inclusion in the Work by You to the Licensor shall be under the terms and
+conditions of this License, without any additional terms or conditions.
+Notwithstanding the above, nothing herein shall supersede or modify the terms of
+any separate license agreement you may have executed with Licensor regarding
+such Contributions.
+
+6. Trademarks.
+
+This License does not grant permission to use the trade names, trademarks,
+service marks, or product names of the Licensor, except as required for
+reasonable and customary use in describing the origin of the Work and
+reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty.
+
+Unless required by applicable law or agreed to in writing, Licensor provides the
+Work (and each Contributor provides its Contributions) on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+including, without limitation, any warranties or conditions of TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
+solely responsible for determining the appropriateness of using or
+redistributing the Work and assume any risks associated with Your exercise of
+permissions under this License.
+
+8. Limitation of Liability.
+
+In no event and under no legal theory, whether in tort (including negligence),
+contract, or otherwise, unless required by applicable law (such as deliberate
+and grossly negligent acts) or agreed to in writing, shall any Contributor be
+liable to You for damages, including any direct, indirect, special, incidental,
+or consequential damages of any character arising as a result of this License or
+out of the use or inability to use the Work (including but not limited to
+damages for loss of goodwill, work stoppage, computer failure or malfunction, or
+any and all other commercial damages or losses), even if such Contributor has
+been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability.
+
+While redistributing the Work or Derivative Works thereof, You may choose to
+offer, and charge a fee for, acceptance of support, warranty, indemnity, or
+other liability obligations and/or rights consistent with this License. However,
+in accepting such obligations, You may act only on Your own behalf and on Your
+sole responsibility, not on behalf of any other Contributor, and only if You
+agree to indemnify, defend, and hold each Contributor harmless for any liability
+incurred by, or claims asserted against, such Contributor by reason of your
+accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work
+
+To apply the Apache License to your work, attach the following boilerplate
+notice, with the fields enclosed by brackets "[]" replaced with your own
+identifying information. (Don't include the brackets!) The text should be
+enclosed in the appropriate comment syntax for the file format. We also
+recommend that a file or class name and description of purpose be included on
+the same "printed page" as the copyright notice for easier identification within
+third-party archives.
+
+ Copyright 2014 Unknwon
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/vendor/gopkg.in/ini.v1/Makefile b/vendor/gopkg.in/ini.v1/Makefile
new file mode 100644
index 0000000000..af27ff0768
--- /dev/null
+++ b/vendor/gopkg.in/ini.v1/Makefile
@@ -0,0 +1,15 @@
+.PHONY: build test bench vet coverage
+
+build: vet bench
+
+test:
+ go test -v -cover -race
+
+bench:
+ go test -v -cover -race -test.bench=. -test.benchmem
+
+vet:
+ go vet
+
+coverage:
+ go test -coverprofile=c.out && go tool cover -html=c.out && rm c.out
diff --git a/vendor/gopkg.in/ini.v1/README.md b/vendor/gopkg.in/ini.v1/README.md
new file mode 100644
index 0000000000..3d6d3cfc07
--- /dev/null
+++ b/vendor/gopkg.in/ini.v1/README.md
@@ -0,0 +1,39 @@
+# INI
+
+[![Build Status](https://img.shields.io/travis/go-ini/ini/master.svg?style=for-the-badge&logo=travis)](https://travis-ci.org/go-ini/ini) [![Sourcegraph](https://img.shields.io/badge/view%20on-Sourcegraph-brightgreen.svg?style=for-the-badge&logo=sourcegraph)](https://sourcegraph.com/github.com/go-ini/ini)
+
+![](https://avatars0.githubusercontent.com/u/10216035?v=3&s=200)
+
+Package ini provides INI file read and write functionality in Go.
+
+## Features
+
+- Load from multiple data sources(`[]byte`, file and `io.ReadCloser`) with overwrites.
+- Read with recursion values.
+- Read with parent-child sections.
+- Read with auto-increment key names.
+- Read with multiple-line values.
+- Read with tons of helper methods.
+- Read and convert values to Go types.
+- Read and **WRITE** comments of sections and keys.
+- Manipulate sections, keys and comments with ease.
+- Keep sections and keys in order as you parse and save.
+
+## Installation
+
+The minimum requirement of Go is **1.6**.
+
+```sh
+$ go get gopkg.in/ini.v1
+```
+
+Please add `-u` flag to update in the future.
+
+## Getting Help
+
+- [Getting Started](https://ini.unknwon.io/docs/intro/getting_started)
+- [API Documentation](https://gowalker.org/gopkg.in/ini.v1)
+
+## License
+
+This project is under Apache v2 License. See the [LICENSE](LICENSE) file for the full license text.
diff --git a/vendor/gopkg.in/ini.v1/data_source.go b/vendor/gopkg.in/ini.v1/data_source.go
new file mode 100644
index 0000000000..dc0277ec64
--- /dev/null
+++ b/vendor/gopkg.in/ini.v1/data_source.go
@@ -0,0 +1,74 @@
+// Copyright 2019 Unknwon
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package ini
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+)
+
+var (
+ _ dataSource = (*sourceFile)(nil)
+ _ dataSource = (*sourceData)(nil)
+ _ dataSource = (*sourceReadCloser)(nil)
+)
+
+// dataSource is an interface that returns object which can be read and closed.
+type dataSource interface {
+ ReadCloser() (io.ReadCloser, error)
+}
+
+// sourceFile represents an object that contains content on the local file system.
+type sourceFile struct {
+ name string
+}
+
+func (s sourceFile) ReadCloser() (_ io.ReadCloser, err error) {
+ return os.Open(s.name)
+}
+
+// sourceData represents an object that contains content in memory.
+type sourceData struct {
+ data []byte
+}
+
+func (s *sourceData) ReadCloser() (io.ReadCloser, error) {
+ return ioutil.NopCloser(bytes.NewReader(s.data)), nil
+}
+
+// sourceReadCloser represents an input stream with Close method.
+type sourceReadCloser struct {
+ reader io.ReadCloser
+}
+
+func (s *sourceReadCloser) ReadCloser() (io.ReadCloser, error) {
+ return s.reader, nil
+}
+
+func parseDataSource(source interface{}) (dataSource, error) {
+ switch s := source.(type) {
+ case string:
+ return sourceFile{s}, nil
+ case []byte:
+ return &sourceData{s}, nil
+ case io.ReadCloser:
+ return &sourceReadCloser{s}, nil
+ default:
+ return nil, fmt.Errorf("error parsing data source: unknown type %q", s)
+ }
+}
diff --git a/vendor/gopkg.in/ini.v1/deprecated.go b/vendor/gopkg.in/ini.v1/deprecated.go
new file mode 100644
index 0000000000..e8bda06e6f
--- /dev/null
+++ b/vendor/gopkg.in/ini.v1/deprecated.go
@@ -0,0 +1,25 @@
+// Copyright 2019 Unknwon
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package ini
+
+const (
+ // Deprecated: Use "DefaultSection" instead.
+ DEFAULT_SECTION = DefaultSection
+)
+
+var (
+ // Deprecated: AllCapsUnderscore converts to format ALL_CAPS_UNDERSCORE.
+ AllCapsUnderscore = SnackCase
+)
diff --git a/vendor/gopkg.in/ini.v1/error.go b/vendor/gopkg.in/ini.v1/error.go
new file mode 100644
index 0000000000..d88347c54b
--- /dev/null
+++ b/vendor/gopkg.in/ini.v1/error.go
@@ -0,0 +1,34 @@
+// Copyright 2016 Unknwon
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package ini
+
+import (
+ "fmt"
+)
+
+// ErrDelimiterNotFound indicates the error type of no delimiter is found which there should be one.
+type ErrDelimiterNotFound struct {
+ Line string
+}
+
+// IsErrDelimiterNotFound returns true if the given error is an instance of ErrDelimiterNotFound.
+func IsErrDelimiterNotFound(err error) bool {
+ _, ok := err.(ErrDelimiterNotFound)
+ return ok
+}
+
+func (err ErrDelimiterNotFound) Error() string {
+ return fmt.Sprintf("key-value delimiter not found: %s", err.Line)
+}
diff --git a/vendor/gopkg.in/ini.v1/file.go b/vendor/gopkg.in/ini.v1/file.go
new file mode 100644
index 0000000000..017b77c8be
--- /dev/null
+++ b/vendor/gopkg.in/ini.v1/file.go
@@ -0,0 +1,418 @@
+// Copyright 2017 Unknwon
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package ini
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "strings"
+ "sync"
+)
+
+// File represents a combination of a or more INI file(s) in memory.
+type File struct {
+ options LoadOptions
+ dataSources []dataSource
+
+ // Should make things safe, but sometimes doesn't matter.
+ BlockMode bool
+ lock sync.RWMutex
+
+ // To keep data in order.
+ sectionList []string
+ // Actual data is stored here.
+ sections map[string]*Section
+
+ NameMapper
+ ValueMapper
+}
+
+// newFile initializes File object with given data sources.
+func newFile(dataSources []dataSource, opts LoadOptions) *File {
+ if len(opts.KeyValueDelimiters) == 0 {
+ opts.KeyValueDelimiters = "=:"
+ }
+ return &File{
+ BlockMode: true,
+ dataSources: dataSources,
+ sections: make(map[string]*Section),
+ sectionList: make([]string, 0, 10),
+ options: opts,
+ }
+}
+
+// Empty returns an empty file object.
+func Empty() *File {
+ // Ignore error here, we sure our data is good.
+ f, _ := Load([]byte(""))
+ return f
+}
+
+// NewSection creates a new section.
+func (f *File) NewSection(name string) (*Section, error) {
+ if len(name) == 0 {
+ return nil, errors.New("error creating new section: empty section name")
+ } else if f.options.Insensitive && name != DefaultSection {
+ name = strings.ToLower(name)
+ }
+
+ if f.BlockMode {
+ f.lock.Lock()
+ defer f.lock.Unlock()
+ }
+
+ if inSlice(name, f.sectionList) {
+ return f.sections[name], nil
+ }
+
+ f.sectionList = append(f.sectionList, name)
+ f.sections[name] = newSection(f, name)
+ return f.sections[name], nil
+}
+
+// NewRawSection creates a new section with an unparseable body.
+func (f *File) NewRawSection(name, body string) (*Section, error) {
+ section, err := f.NewSection(name)
+ if err != nil {
+ return nil, err
+ }
+
+ section.isRawSection = true
+ section.rawBody = body
+ return section, nil
+}
+
+// NewSections creates a list of sections.
+func (f *File) NewSections(names ...string) (err error) {
+ for _, name := range names {
+ if _, err = f.NewSection(name); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// GetSection returns section by given name.
+func (f *File) GetSection(name string) (*Section, error) {
+ if len(name) == 0 {
+ name = DefaultSection
+ }
+ if f.options.Insensitive {
+ name = strings.ToLower(name)
+ }
+
+ if f.BlockMode {
+ f.lock.RLock()
+ defer f.lock.RUnlock()
+ }
+
+ sec := f.sections[name]
+ if sec == nil {
+ return nil, fmt.Errorf("section '%s' does not exist", name)
+ }
+ return sec, nil
+}
+
+// Section assumes named section exists and returns a zero-value when not.
+func (f *File) Section(name string) *Section {
+ sec, err := f.GetSection(name)
+ if err != nil {
+ // Note: It's OK here because the only possible error is empty section name,
+ // but if it's empty, this piece of code won't be executed.
+ sec, _ = f.NewSection(name)
+ return sec
+ }
+ return sec
+}
+
+// Sections returns a list of Section stored in the current instance.
+func (f *File) Sections() []*Section {
+ if f.BlockMode {
+ f.lock.RLock()
+ defer f.lock.RUnlock()
+ }
+
+ sections := make([]*Section, len(f.sectionList))
+ for i, name := range f.sectionList {
+ sections[i] = f.sections[name]
+ }
+ return sections
+}
+
+// ChildSections returns a list of child sections of given section name.
+func (f *File) ChildSections(name string) []*Section {
+ return f.Section(name).ChildSections()
+}
+
+// SectionStrings returns list of section names.
+func (f *File) SectionStrings() []string {
+ list := make([]string, len(f.sectionList))
+ copy(list, f.sectionList)
+ return list
+}
+
+// DeleteSection deletes a section.
+func (f *File) DeleteSection(name string) {
+ if f.BlockMode {
+ f.lock.Lock()
+ defer f.lock.Unlock()
+ }
+
+ if len(name) == 0 {
+ name = DefaultSection
+ }
+
+ for i, s := range f.sectionList {
+ if s == name {
+ f.sectionList = append(f.sectionList[:i], f.sectionList[i+1:]...)
+ delete(f.sections, name)
+ return
+ }
+ }
+}
+
+func (f *File) reload(s dataSource) error {
+ r, err := s.ReadCloser()
+ if err != nil {
+ return err
+ }
+ defer r.Close()
+
+ return f.parse(r)
+}
+
+// Reload reloads and parses all data sources.
+func (f *File) Reload() (err error) {
+ for _, s := range f.dataSources {
+ if err = f.reload(s); err != nil {
+ // In loose mode, we create an empty default section for nonexistent files.
+ if os.IsNotExist(err) && f.options.Loose {
+ f.parse(bytes.NewBuffer(nil))
+ continue
+ }
+ return err
+ }
+ }
+ return nil
+}
+
+// Append appends one or more data sources and reloads automatically.
+func (f *File) Append(source interface{}, others ...interface{}) error {
+ ds, err := parseDataSource(source)
+ if err != nil {
+ return err
+ }
+ f.dataSources = append(f.dataSources, ds)
+ for _, s := range others {
+ ds, err = parseDataSource(s)
+ if err != nil {
+ return err
+ }
+ f.dataSources = append(f.dataSources, ds)
+ }
+ return f.Reload()
+}
+
+func (f *File) writeToBuffer(indent string) (*bytes.Buffer, error) {
+ equalSign := DefaultFormatLeft + "=" + DefaultFormatRight
+
+ if PrettyFormat || PrettyEqual {
+ equalSign = " = "
+ }
+
+ // Use buffer to make sure target is safe until finish encoding.
+ buf := bytes.NewBuffer(nil)
+ for i, sname := range f.sectionList {
+ sec := f.Section(sname)
+ if len(sec.Comment) > 0 {
+ // Support multiline comments
+ lines := strings.Split(sec.Comment, LineBreak)
+ for i := range lines {
+ if lines[i][0] != '#' && lines[i][0] != ';' {
+ lines[i] = "; " + lines[i]
+ } else {
+ lines[i] = lines[i][:1] + " " + strings.TrimSpace(lines[i][1:])
+ }
+
+ if _, err := buf.WriteString(lines[i] + LineBreak); err != nil {
+ return nil, err
+ }
+ }
+ }
+
+ if i > 0 || DefaultHeader {
+ if _, err := buf.WriteString("[" + sname + "]" + LineBreak); err != nil {
+ return nil, err
+ }
+ } else {
+ // Write nothing if default section is empty
+ if len(sec.keyList) == 0 {
+ continue
+ }
+ }
+
+ if sec.isRawSection {
+ if _, err := buf.WriteString(sec.rawBody); err != nil {
+ return nil, err
+ }
+
+ if PrettySection {
+ // Put a line between sections
+ if _, err := buf.WriteString(LineBreak); err != nil {
+ return nil, err
+ }
+ }
+ continue
+ }
+
+ // Count and generate alignment length and buffer spaces using the
+ // longest key. Keys may be modifed if they contain certain characters so
+ // we need to take that into account in our calculation.
+ alignLength := 0
+ if PrettyFormat {
+ for _, kname := range sec.keyList {
+ keyLength := len(kname)
+ // First case will surround key by ` and second by """
+ if strings.Contains(kname, "\"") || strings.ContainsAny(kname, f.options.KeyValueDelimiters) {
+ keyLength += 2
+ } else if strings.Contains(kname, "`") {
+ keyLength += 6
+ }
+
+ if keyLength > alignLength {
+ alignLength = keyLength
+ }
+ }
+ }
+ alignSpaces := bytes.Repeat([]byte(" "), alignLength)
+
+ KeyList:
+ for _, kname := range sec.keyList {
+ key := sec.Key(kname)
+ if len(key.Comment) > 0 {
+ if len(indent) > 0 && sname != DefaultSection {
+ buf.WriteString(indent)
+ }
+
+ // Support multiline comments
+ lines := strings.Split(key.Comment, LineBreak)
+ for i := range lines {
+ if lines[i][0] != '#' && lines[i][0] != ';' {
+ lines[i] = "; " + strings.TrimSpace(lines[i])
+ } else {
+ lines[i] = lines[i][:1] + " " + strings.TrimSpace(lines[i][1:])
+ }
+
+ if _, err := buf.WriteString(lines[i] + LineBreak); err != nil {
+ return nil, err
+ }
+ }
+ }
+
+ if len(indent) > 0 && sname != DefaultSection {
+ buf.WriteString(indent)
+ }
+
+ switch {
+ case key.isAutoIncrement:
+ kname = "-"
+ case strings.Contains(kname, "\"") || strings.ContainsAny(kname, f.options.KeyValueDelimiters):
+ kname = "`" + kname + "`"
+ case strings.Contains(kname, "`"):
+ kname = `"""` + kname + `"""`
+ }
+
+ for _, val := range key.ValueWithShadows() {
+ if _, err := buf.WriteString(kname); err != nil {
+ return nil, err
+ }
+
+ if key.isBooleanType {
+ if kname != sec.keyList[len(sec.keyList)-1] {
+ buf.WriteString(LineBreak)
+ }
+ continue KeyList
+ }
+
+ // Write out alignment spaces before "=" sign
+ if PrettyFormat {
+ buf.Write(alignSpaces[:alignLength-len(kname)])
+ }
+
+ // In case key value contains "\n", "`", "\"", "#" or ";"
+ if strings.ContainsAny(val, "\n`") {
+ val = `"""` + val + `"""`
+ } else if !f.options.IgnoreInlineComment && strings.ContainsAny(val, "#;") {
+ val = "`" + val + "`"
+ }
+ if _, err := buf.WriteString(equalSign + val + LineBreak); err != nil {
+ return nil, err
+ }
+ }
+
+ for _, val := range key.nestedValues {
+ if _, err := buf.WriteString(indent + " " + val + LineBreak); err != nil {
+ return nil, err
+ }
+ }
+ }
+
+ if PrettySection {
+ // Put a line between sections
+ if _, err := buf.WriteString(LineBreak); err != nil {
+ return nil, err
+ }
+ }
+ }
+
+ return buf, nil
+}
+
+// WriteToIndent writes content into io.Writer with given indention.
+// If PrettyFormat has been set to be true,
+// it will align "=" sign with spaces under each section.
+func (f *File) WriteToIndent(w io.Writer, indent string) (int64, error) {
+ buf, err := f.writeToBuffer(indent)
+ if err != nil {
+ return 0, err
+ }
+ return buf.WriteTo(w)
+}
+
+// WriteTo writes file content into io.Writer.
+func (f *File) WriteTo(w io.Writer) (int64, error) {
+ return f.WriteToIndent(w, "")
+}
+
+// SaveToIndent writes content to file system with given value indention.
+func (f *File) SaveToIndent(filename, indent string) error {
+ // Note: Because we are truncating with os.Create,
+ // so it's safer to save to a temporary file location and rename afte done.
+ buf, err := f.writeToBuffer(indent)
+ if err != nil {
+ return err
+ }
+
+ return ioutil.WriteFile(filename, buf.Bytes(), 0666)
+}
+
+// SaveTo writes content to file system.
+func (f *File) SaveTo(filename string) error {
+ return f.SaveToIndent(filename, "")
+}
diff --git a/vendor/gopkg.in/ini.v1/helper.go b/vendor/gopkg.in/ini.v1/helper.go
new file mode 100644
index 0000000000..f9d80a682a
--- /dev/null
+++ b/vendor/gopkg.in/ini.v1/helper.go
@@ -0,0 +1,24 @@
+// Copyright 2019 Unknwon
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package ini
+
+func inSlice(str string, s []string) bool {
+ for _, v := range s {
+ if str == v {
+ return true
+ }
+ }
+ return false
+}
diff --git a/vendor/gopkg.in/ini.v1/ini.go b/vendor/gopkg.in/ini.v1/ini.go
new file mode 100644
index 0000000000..945fc00c0f
--- /dev/null
+++ b/vendor/gopkg.in/ini.v1/ini.go
@@ -0,0 +1,166 @@
+// +build go1.6
+
+// Copyright 2014 Unknwon
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+// Package ini provides INI file read and write functionality in Go.
+package ini
+
+import (
+ "regexp"
+ "runtime"
+)
+
+const (
+ // DefaultSection is the name of default section. You can use this constant or the string literal.
+ // In most of cases, an empty string is all you need to access the section.
+ DefaultSection = "DEFAULT"
+
+ // Maximum allowed depth when recursively substituing variable names.
+ depthValues = 99
+ version = "1.51.0"
+)
+
+// Version returns current package version literal.
+func Version() string {
+ return version
+}
+
+var (
+ // LineBreak is the delimiter to determine or compose a new line.
+ // This variable will be changed to "\r\n" automatically on Windows at package init time.
+ LineBreak = "\n"
+
+ // Variable regexp pattern: %(variable)s
+ varPattern = regexp.MustCompile(`%\(([^)]+)\)s`)
+
+ // DefaultHeader explicitly writes default section header.
+ DefaultHeader = false
+
+ // PrettySection indicates whether to put a line between sections.
+ PrettySection = true
+ // PrettyFormat indicates whether to align "=" sign with spaces to produce pretty output
+ // or reduce all possible spaces for compact format.
+ PrettyFormat = true
+ // PrettyEqual places spaces around "=" sign even when PrettyFormat is false.
+ PrettyEqual = false
+ // DefaultFormatLeft places custom spaces on the left when PrettyFormat and PrettyEqual are both disabled.
+ DefaultFormatLeft = ""
+ // DefaultFormatRight places custom spaces on the right when PrettyFormat and PrettyEqual are both disabled.
+ DefaultFormatRight = ""
+)
+
+func init() {
+ if runtime.GOOS == "windows" {
+ LineBreak = "\r\n"
+ }
+}
+
+// LoadOptions contains all customized options used for load data source(s).
+type LoadOptions struct {
+ // Loose indicates whether the parser should ignore nonexistent files or return error.
+ Loose bool
+ // Insensitive indicates whether the parser forces all section and key names to lowercase.
+ Insensitive bool
+ // IgnoreContinuation indicates whether to ignore continuation lines while parsing.
+ IgnoreContinuation bool
+ // IgnoreInlineComment indicates whether to ignore comments at the end of value and treat it as part of value.
+ IgnoreInlineComment bool
+ // SkipUnrecognizableLines indicates whether to skip unrecognizable lines that do not conform to key/value pairs.
+ SkipUnrecognizableLines bool
+ // AllowBooleanKeys indicates whether to allow boolean type keys or treat as value is missing.
+ // This type of keys are mostly used in my.cnf.
+ AllowBooleanKeys bool
+ // AllowShadows indicates whether to keep track of keys with same name under same section.
+ AllowShadows bool
+ // AllowNestedValues indicates whether to allow AWS-like nested values.
+ // Docs: http://docs.aws.amazon.com/cli/latest/topic/config-vars.html#nested-values
+ AllowNestedValues bool
+ // AllowPythonMultilineValues indicates whether to allow Python-like multi-line values.
+ // Docs: https://docs.python.org/3/library/configparser.html#supported-ini-file-structure
+ // Relevant quote: Values can also span multiple lines, as long as they are indented deeper
+ // than the first line of the value.
+ AllowPythonMultilineValues bool
+ // SpaceBeforeInlineComment indicates whether to allow comment symbols (\# and \;) inside value.
+ // Docs: https://docs.python.org/2/library/configparser.html
+ // Quote: Comments may appear on their own in an otherwise empty line, or may be entered in lines holding values or section names.
+ // In the latter case, they need to be preceded by a whitespace character to be recognized as a comment.
+ SpaceBeforeInlineComment bool
+ // UnescapeValueDoubleQuotes indicates whether to unescape double quotes inside value to regular format
+ // when value is surrounded by double quotes, e.g. key="a \"value\"" => key=a "value"
+ UnescapeValueDoubleQuotes bool
+ // UnescapeValueCommentSymbols indicates to unescape comment symbols (\# and \;) inside value to regular format
+ // when value is NOT surrounded by any quotes.
+ // Note: UNSTABLE, behavior might change to only unescape inside double quotes but may noy necessary at all.
+ UnescapeValueCommentSymbols bool
+ // UnparseableSections stores a list of blocks that are allowed with raw content which do not otherwise
+ // conform to key/value pairs. Specify the names of those blocks here.
+ UnparseableSections []string
+ // KeyValueDelimiters is the sequence of delimiters that are used to separate key and value. By default, it is "=:".
+ KeyValueDelimiters string
+ // PreserveSurroundedQuote indicates whether to preserve surrounded quote (single and double quotes).
+ PreserveSurroundedQuote bool
+ // DebugFunc is called to collect debug information (currently only useful to debug parsing Python-style multiline values).
+ DebugFunc DebugFunc
+ // ReaderBufferSize is the buffer size of the reader in bytes.
+ ReaderBufferSize int
+}
+
+// DebugFunc is the type of function called to log parse events.
+type DebugFunc func(message string)
+
+// LoadSources allows caller to apply customized options for loading from data source(s).
+func LoadSources(opts LoadOptions, source interface{}, others ...interface{}) (_ *File, err error) {
+ sources := make([]dataSource, len(others)+1)
+ sources[0], err = parseDataSource(source)
+ if err != nil {
+ return nil, err
+ }
+ for i := range others {
+ sources[i+1], err = parseDataSource(others[i])
+ if err != nil {
+ return nil, err
+ }
+ }
+ f := newFile(sources, opts)
+ if err = f.Reload(); err != nil {
+ return nil, err
+ }
+ return f, nil
+}
+
+// Load loads and parses from INI data sources.
+// Arguments can be mixed of file name with string type, or raw data in []byte.
+// It will return error if list contains nonexistent files.
+func Load(source interface{}, others ...interface{}) (*File, error) {
+ return LoadSources(LoadOptions{}, source, others...)
+}
+
+// LooseLoad has exactly same functionality as Load function
+// except it ignores nonexistent files instead of returning error.
+func LooseLoad(source interface{}, others ...interface{}) (*File, error) {
+ return LoadSources(LoadOptions{Loose: true}, source, others...)
+}
+
+// InsensitiveLoad has exactly same functionality as Load function
+// except it forces all section and key names to be lowercased.
+func InsensitiveLoad(source interface{}, others ...interface{}) (*File, error) {
+ return LoadSources(LoadOptions{Insensitive: true}, source, others...)
+}
+
+// ShadowLoad has exactly same functionality as Load function
+// except it allows have shadow keys.
+func ShadowLoad(source interface{}, others ...interface{}) (*File, error) {
+ return LoadSources(LoadOptions{AllowShadows: true}, source, others...)
+}
diff --git a/vendor/gopkg.in/ini.v1/key.go b/vendor/gopkg.in/ini.v1/key.go
new file mode 100644
index 0000000000..3c197410fa
--- /dev/null
+++ b/vendor/gopkg.in/ini.v1/key.go
@@ -0,0 +1,801 @@
+// Copyright 2014 Unknwon
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package ini
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "strconv"
+ "strings"
+ "time"
+)
+
+// Key represents a key under a section.
+type Key struct {
+ s *Section
+ Comment string
+ name string
+ value string
+ isAutoIncrement bool
+ isBooleanType bool
+
+ isShadow bool
+ shadows []*Key
+
+ nestedValues []string
+}
+
+// newKey simply return a key object with given values.
+func newKey(s *Section, name, val string) *Key {
+ return &Key{
+ s: s,
+ name: name,
+ value: val,
+ }
+}
+
+func (k *Key) addShadow(val string) error {
+ if k.isShadow {
+ return errors.New("cannot add shadow to another shadow key")
+ } else if k.isAutoIncrement || k.isBooleanType {
+ return errors.New("cannot add shadow to auto-increment or boolean key")
+ }
+
+ // Deduplicate shadows based on their values.
+ if k.value == val {
+ return nil
+ }
+ for i := range k.shadows {
+ if k.shadows[i].value == val {
+ return nil
+ }
+ }
+
+ shadow := newKey(k.s, k.name, val)
+ shadow.isShadow = true
+ k.shadows = append(k.shadows, shadow)
+ return nil
+}
+
+// AddShadow adds a new shadow key to itself.
+func (k *Key) AddShadow(val string) error {
+ if !k.s.f.options.AllowShadows {
+ return errors.New("shadow key is not allowed")
+ }
+ return k.addShadow(val)
+}
+
+func (k *Key) addNestedValue(val string) error {
+ if k.isAutoIncrement || k.isBooleanType {
+ return errors.New("cannot add nested value to auto-increment or boolean key")
+ }
+
+ k.nestedValues = append(k.nestedValues, val)
+ return nil
+}
+
+// AddNestedValue adds a nested value to the key.
+func (k *Key) AddNestedValue(val string) error {
+ if !k.s.f.options.AllowNestedValues {
+ return errors.New("nested value is not allowed")
+ }
+ return k.addNestedValue(val)
+}
+
+// ValueMapper represents a mapping function for values, e.g. os.ExpandEnv
+type ValueMapper func(string) string
+
+// Name returns name of key.
+func (k *Key) Name() string {
+ return k.name
+}
+
+// Value returns raw value of key for performance purpose.
+func (k *Key) Value() string {
+ return k.value
+}
+
+// ValueWithShadows returns raw values of key and its shadows if any.
+func (k *Key) ValueWithShadows() []string {
+ if len(k.shadows) == 0 {
+ return []string{k.value}
+ }
+ vals := make([]string, len(k.shadows)+1)
+ vals[0] = k.value
+ for i := range k.shadows {
+ vals[i+1] = k.shadows[i].value
+ }
+ return vals
+}
+
+// NestedValues returns nested values stored in the key.
+// It is possible returned value is nil if no nested values stored in the key.
+func (k *Key) NestedValues() []string {
+ return k.nestedValues
+}
+
+// transformValue takes a raw value and transforms to its final string.
+func (k *Key) transformValue(val string) string {
+ if k.s.f.ValueMapper != nil {
+ val = k.s.f.ValueMapper(val)
+ }
+
+ // Fail-fast if no indicate char found for recursive value
+ if !strings.Contains(val, "%") {
+ return val
+ }
+ for i := 0; i < depthValues; i++ {
+ vr := varPattern.FindString(val)
+ if len(vr) == 0 {
+ break
+ }
+
+ // Take off leading '%(' and trailing ')s'.
+ noption := vr[2 : len(vr)-2]
+
+ // Search in the same section.
+ // If not found or found the key itself, then search again in default section.
+ nk, err := k.s.GetKey(noption)
+ if err != nil || k == nk {
+ nk, _ = k.s.f.Section("").GetKey(noption)
+ if nk == nil {
+ // Stop when no results found in the default section,
+ // and returns the value as-is.
+ break
+ }
+ }
+
+ // Substitute by new value and take off leading '%(' and trailing ')s'.
+ val = strings.Replace(val, vr, nk.value, -1)
+ }
+ return val
+}
+
+// String returns string representation of value.
+func (k *Key) String() string {
+ return k.transformValue(k.value)
+}
+
+// Validate accepts a validate function which can
+// return modifed result as key value.
+func (k *Key) Validate(fn func(string) string) string {
+ return fn(k.String())
+}
+
+// parseBool returns the boolean value represented by the string.
+//
+// It accepts 1, t, T, TRUE, true, True, YES, yes, Yes, y, ON, on, On,
+// 0, f, F, FALSE, false, False, NO, no, No, n, OFF, off, Off.
+// Any other value returns an error.
+func parseBool(str string) (value bool, err error) {
+ switch str {
+ case "1", "t", "T", "true", "TRUE", "True", "YES", "yes", "Yes", "y", "ON", "on", "On":
+ return true, nil
+ case "0", "f", "F", "false", "FALSE", "False", "NO", "no", "No", "n", "OFF", "off", "Off":
+ return false, nil
+ }
+ return false, fmt.Errorf("parsing \"%s\": invalid syntax", str)
+}
+
+// Bool returns bool type value.
+func (k *Key) Bool() (bool, error) {
+ return parseBool(k.String())
+}
+
+// Float64 returns float64 type value.
+func (k *Key) Float64() (float64, error) {
+ return strconv.ParseFloat(k.String(), 64)
+}
+
+// Int returns int type value.
+func (k *Key) Int() (int, error) {
+ v, err := strconv.ParseInt(k.String(), 0, 64)
+ return int(v), err
+}
+
+// Int64 returns int64 type value.
+func (k *Key) Int64() (int64, error) {
+ return strconv.ParseInt(k.String(), 0, 64)
+}
+
+// Uint returns uint type valued.
+func (k *Key) Uint() (uint, error) {
+ u, e := strconv.ParseUint(k.String(), 0, 64)
+ return uint(u), e
+}
+
+// Uint64 returns uint64 type value.
+func (k *Key) Uint64() (uint64, error) {
+ return strconv.ParseUint(k.String(), 0, 64)
+}
+
+// Duration returns time.Duration type value.
+func (k *Key) Duration() (time.Duration, error) {
+ return time.ParseDuration(k.String())
+}
+
+// TimeFormat parses with given format and returns time.Time type value.
+func (k *Key) TimeFormat(format string) (time.Time, error) {
+ return time.Parse(format, k.String())
+}
+
+// Time parses with RFC3339 format and returns time.Time type value.
+func (k *Key) Time() (time.Time, error) {
+ return k.TimeFormat(time.RFC3339)
+}
+
+// MustString returns default value if key value is empty.
+func (k *Key) MustString(defaultVal string) string {
+ val := k.String()
+ if len(val) == 0 {
+ k.value = defaultVal
+ return defaultVal
+ }
+ return val
+}
+
+// MustBool always returns value without error,
+// it returns false if error occurs.
+func (k *Key) MustBool(defaultVal ...bool) bool {
+ val, err := k.Bool()
+ if len(defaultVal) > 0 && err != nil {
+ k.value = strconv.FormatBool(defaultVal[0])
+ return defaultVal[0]
+ }
+ return val
+}
+
+// MustFloat64 always returns value without error,
+// it returns 0.0 if error occurs.
+func (k *Key) MustFloat64(defaultVal ...float64) float64 {
+ val, err := k.Float64()
+ if len(defaultVal) > 0 && err != nil {
+ k.value = strconv.FormatFloat(defaultVal[0], 'f', -1, 64)
+ return defaultVal[0]
+ }
+ return val
+}
+
+// MustInt always returns value without error,
+// it returns 0 if error occurs.
+func (k *Key) MustInt(defaultVal ...int) int {
+ val, err := k.Int()
+ if len(defaultVal) > 0 && err != nil {
+ k.value = strconv.FormatInt(int64(defaultVal[0]), 10)
+ return defaultVal[0]
+ }
+ return val
+}
+
+// MustInt64 always returns value without error,
+// it returns 0 if error occurs.
+func (k *Key) MustInt64(defaultVal ...int64) int64 {
+ val, err := k.Int64()
+ if len(defaultVal) > 0 && err != nil {
+ k.value = strconv.FormatInt(defaultVal[0], 10)
+ return defaultVal[0]
+ }
+ return val
+}
+
+// MustUint always returns value without error,
+// it returns 0 if error occurs.
+func (k *Key) MustUint(defaultVal ...uint) uint {
+ val, err := k.Uint()
+ if len(defaultVal) > 0 && err != nil {
+ k.value = strconv.FormatUint(uint64(defaultVal[0]), 10)
+ return defaultVal[0]
+ }
+ return val
+}
+
+// MustUint64 always returns value without error,
+// it returns 0 if error occurs.
+func (k *Key) MustUint64(defaultVal ...uint64) uint64 {
+ val, err := k.Uint64()
+ if len(defaultVal) > 0 && err != nil {
+ k.value = strconv.FormatUint(defaultVal[0], 10)
+ return defaultVal[0]
+ }
+ return val
+}
+
+// MustDuration always returns value without error,
+// it returns zero value if error occurs.
+func (k *Key) MustDuration(defaultVal ...time.Duration) time.Duration {
+ val, err := k.Duration()
+ if len(defaultVal) > 0 && err != nil {
+ k.value = defaultVal[0].String()
+ return defaultVal[0]
+ }
+ return val
+}
+
+// MustTimeFormat always parses with given format and returns value without error,
+// it returns zero value if error occurs.
+func (k *Key) MustTimeFormat(format string, defaultVal ...time.Time) time.Time {
+ val, err := k.TimeFormat(format)
+ if len(defaultVal) > 0 && err != nil {
+ k.value = defaultVal[0].Format(format)
+ return defaultVal[0]
+ }
+ return val
+}
+
+// MustTime always parses with RFC3339 format and returns value without error,
+// it returns zero value if error occurs.
+func (k *Key) MustTime(defaultVal ...time.Time) time.Time {
+ return k.MustTimeFormat(time.RFC3339, defaultVal...)
+}
+
+// In always returns value without error,
+// it returns default value if error occurs or doesn't fit into candidates.
+func (k *Key) In(defaultVal string, candidates []string) string {
+ val := k.String()
+ for _, cand := range candidates {
+ if val == cand {
+ return val
+ }
+ }
+ return defaultVal
+}
+
+// InFloat64 always returns value without error,
+// it returns default value if error occurs or doesn't fit into candidates.
+func (k *Key) InFloat64(defaultVal float64, candidates []float64) float64 {
+ val := k.MustFloat64()
+ for _, cand := range candidates {
+ if val == cand {
+ return val
+ }
+ }
+ return defaultVal
+}
+
+// InInt always returns value without error,
+// it returns default value if error occurs or doesn't fit into candidates.
+func (k *Key) InInt(defaultVal int, candidates []int) int {
+ val := k.MustInt()
+ for _, cand := range candidates {
+ if val == cand {
+ return val
+ }
+ }
+ return defaultVal
+}
+
+// InInt64 always returns value without error,
+// it returns default value if error occurs or doesn't fit into candidates.
+func (k *Key) InInt64(defaultVal int64, candidates []int64) int64 {
+ val := k.MustInt64()
+ for _, cand := range candidates {
+ if val == cand {
+ return val
+ }
+ }
+ return defaultVal
+}
+
+// InUint always returns value without error,
+// it returns default value if error occurs or doesn't fit into candidates.
+func (k *Key) InUint(defaultVal uint, candidates []uint) uint {
+ val := k.MustUint()
+ for _, cand := range candidates {
+ if val == cand {
+ return val
+ }
+ }
+ return defaultVal
+}
+
+// InUint64 always returns value without error,
+// it returns default value if error occurs or doesn't fit into candidates.
+func (k *Key) InUint64(defaultVal uint64, candidates []uint64) uint64 {
+ val := k.MustUint64()
+ for _, cand := range candidates {
+ if val == cand {
+ return val
+ }
+ }
+ return defaultVal
+}
+
+// InTimeFormat always parses with given format and returns value without error,
+// it returns default value if error occurs or doesn't fit into candidates.
+func (k *Key) InTimeFormat(format string, defaultVal time.Time, candidates []time.Time) time.Time {
+ val := k.MustTimeFormat(format)
+ for _, cand := range candidates {
+ if val == cand {
+ return val
+ }
+ }
+ return defaultVal
+}
+
+// InTime always parses with RFC3339 format and returns value without error,
+// it returns default value if error occurs or doesn't fit into candidates.
+func (k *Key) InTime(defaultVal time.Time, candidates []time.Time) time.Time {
+ return k.InTimeFormat(time.RFC3339, defaultVal, candidates)
+}
+
+// RangeFloat64 checks if value is in given range inclusively,
+// and returns default value if it's not.
+func (k *Key) RangeFloat64(defaultVal, min, max float64) float64 {
+ val := k.MustFloat64()
+ if val < min || val > max {
+ return defaultVal
+ }
+ return val
+}
+
+// RangeInt checks if value is in given range inclusively,
+// and returns default value if it's not.
+func (k *Key) RangeInt(defaultVal, min, max int) int {
+ val := k.MustInt()
+ if val < min || val > max {
+ return defaultVal
+ }
+ return val
+}
+
+// RangeInt64 checks if value is in given range inclusively,
+// and returns default value if it's not.
+func (k *Key) RangeInt64(defaultVal, min, max int64) int64 {
+ val := k.MustInt64()
+ if val < min || val > max {
+ return defaultVal
+ }
+ return val
+}
+
+// RangeTimeFormat checks if value with given format is in given range inclusively,
+// and returns default value if it's not.
+func (k *Key) RangeTimeFormat(format string, defaultVal, min, max time.Time) time.Time {
+ val := k.MustTimeFormat(format)
+ if val.Unix() < min.Unix() || val.Unix() > max.Unix() {
+ return defaultVal
+ }
+ return val
+}
+
+// RangeTime checks if value with RFC3339 format is in given range inclusively,
+// and returns default value if it's not.
+func (k *Key) RangeTime(defaultVal, min, max time.Time) time.Time {
+ return k.RangeTimeFormat(time.RFC3339, defaultVal, min, max)
+}
+
+// Strings returns list of string divided by given delimiter.
+func (k *Key) Strings(delim string) []string {
+ str := k.String()
+ if len(str) == 0 {
+ return []string{}
+ }
+
+ runes := []rune(str)
+ vals := make([]string, 0, 2)
+ var buf bytes.Buffer
+ escape := false
+ idx := 0
+ for {
+ if escape {
+ escape = false
+ if runes[idx] != '\\' && !strings.HasPrefix(string(runes[idx:]), delim) {
+ buf.WriteRune('\\')
+ }
+ buf.WriteRune(runes[idx])
+ } else {
+ if runes[idx] == '\\' {
+ escape = true
+ } else if strings.HasPrefix(string(runes[idx:]), delim) {
+ idx += len(delim) - 1
+ vals = append(vals, strings.TrimSpace(buf.String()))
+ buf.Reset()
+ } else {
+ buf.WriteRune(runes[idx])
+ }
+ }
+ idx++
+ if idx == len(runes) {
+ break
+ }
+ }
+
+ if buf.Len() > 0 {
+ vals = append(vals, strings.TrimSpace(buf.String()))
+ }
+
+ return vals
+}
+
+// StringsWithShadows returns list of string divided by given delimiter.
+// Shadows will also be appended if any.
+func (k *Key) StringsWithShadows(delim string) []string {
+ vals := k.ValueWithShadows()
+ results := make([]string, 0, len(vals)*2)
+ for i := range vals {
+ if len(vals) == 0 {
+ continue
+ }
+
+ results = append(results, strings.Split(vals[i], delim)...)
+ }
+
+ for i := range results {
+ results[i] = k.transformValue(strings.TrimSpace(results[i]))
+ }
+ return results
+}
+
+// Float64s returns list of float64 divided by given delimiter. Any invalid input will be treated as zero value.
+func (k *Key) Float64s(delim string) []float64 {
+ vals, _ := k.parseFloat64s(k.Strings(delim), true, false)
+ return vals
+}
+
+// Ints returns list of int divided by given delimiter. Any invalid input will be treated as zero value.
+func (k *Key) Ints(delim string) []int {
+ vals, _ := k.parseInts(k.Strings(delim), true, false)
+ return vals
+}
+
+// Int64s returns list of int64 divided by given delimiter. Any invalid input will be treated as zero value.
+func (k *Key) Int64s(delim string) []int64 {
+ vals, _ := k.parseInt64s(k.Strings(delim), true, false)
+ return vals
+}
+
+// Uints returns list of uint divided by given delimiter. Any invalid input will be treated as zero value.
+func (k *Key) Uints(delim string) []uint {
+ vals, _ := k.parseUints(k.Strings(delim), true, false)
+ return vals
+}
+
+// Uint64s returns list of uint64 divided by given delimiter. Any invalid input will be treated as zero value.
+func (k *Key) Uint64s(delim string) []uint64 {
+ vals, _ := k.parseUint64s(k.Strings(delim), true, false)
+ return vals
+}
+
+// Bools returns list of bool divided by given delimiter. Any invalid input will be treated as zero value.
+func (k *Key) Bools(delim string) []bool {
+ vals, _ := k.parseBools(k.Strings(delim), true, false)
+ return vals
+}
+
+// TimesFormat parses with given format and returns list of time.Time divided by given delimiter.
+// Any invalid input will be treated as zero value (0001-01-01 00:00:00 +0000 UTC).
+func (k *Key) TimesFormat(format, delim string) []time.Time {
+ vals, _ := k.parseTimesFormat(format, k.Strings(delim), true, false)
+ return vals
+}
+
+// Times parses with RFC3339 format and returns list of time.Time divided by given delimiter.
+// Any invalid input will be treated as zero value (0001-01-01 00:00:00 +0000 UTC).
+func (k *Key) Times(delim string) []time.Time {
+ return k.TimesFormat(time.RFC3339, delim)
+}
+
+// ValidFloat64s returns list of float64 divided by given delimiter. If some value is not float, then
+// it will not be included to result list.
+func (k *Key) ValidFloat64s(delim string) []float64 {
+ vals, _ := k.parseFloat64s(k.Strings(delim), false, false)
+ return vals
+}
+
+// ValidInts returns list of int divided by given delimiter. If some value is not integer, then it will
+// not be included to result list.
+func (k *Key) ValidInts(delim string) []int {
+ vals, _ := k.parseInts(k.Strings(delim), false, false)
+ return vals
+}
+
+// ValidInt64s returns list of int64 divided by given delimiter. If some value is not 64-bit integer,
+// then it will not be included to result list.
+func (k *Key) ValidInt64s(delim string) []int64 {
+ vals, _ := k.parseInt64s(k.Strings(delim), false, false)
+ return vals
+}
+
+// ValidUints returns list of uint divided by given delimiter. If some value is not unsigned integer,
+// then it will not be included to result list.
+func (k *Key) ValidUints(delim string) []uint {
+ vals, _ := k.parseUints(k.Strings(delim), false, false)
+ return vals
+}
+
+// ValidUint64s returns list of uint64 divided by given delimiter. If some value is not 64-bit unsigned
+// integer, then it will not be included to result list.
+func (k *Key) ValidUint64s(delim string) []uint64 {
+ vals, _ := k.parseUint64s(k.Strings(delim), false, false)
+ return vals
+}
+
+// ValidBools returns list of bool divided by given delimiter. If some value is not 64-bit unsigned
+// integer, then it will not be included to result list.
+func (k *Key) ValidBools(delim string) []bool {
+ vals, _ := k.parseBools(k.Strings(delim), false, false)
+ return vals
+}
+
+// ValidTimesFormat parses with given format and returns list of time.Time divided by given delimiter.
+func (k *Key) ValidTimesFormat(format, delim string) []time.Time {
+ vals, _ := k.parseTimesFormat(format, k.Strings(delim), false, false)
+ return vals
+}
+
+// ValidTimes parses with RFC3339 format and returns list of time.Time divided by given delimiter.
+func (k *Key) ValidTimes(delim string) []time.Time {
+ return k.ValidTimesFormat(time.RFC3339, delim)
+}
+
+// StrictFloat64s returns list of float64 divided by given delimiter or error on first invalid input.
+func (k *Key) StrictFloat64s(delim string) ([]float64, error) {
+ return k.parseFloat64s(k.Strings(delim), false, true)
+}
+
+// StrictInts returns list of int divided by given delimiter or error on first invalid input.
+func (k *Key) StrictInts(delim string) ([]int, error) {
+ return k.parseInts(k.Strings(delim), false, true)
+}
+
+// StrictInt64s returns list of int64 divided by given delimiter or error on first invalid input.
+func (k *Key) StrictInt64s(delim string) ([]int64, error) {
+ return k.parseInt64s(k.Strings(delim), false, true)
+}
+
+// StrictUints returns list of uint divided by given delimiter or error on first invalid input.
+func (k *Key) StrictUints(delim string) ([]uint, error) {
+ return k.parseUints(k.Strings(delim), false, true)
+}
+
+// StrictUint64s returns list of uint64 divided by given delimiter or error on first invalid input.
+func (k *Key) StrictUint64s(delim string) ([]uint64, error) {
+ return k.parseUint64s(k.Strings(delim), false, true)
+}
+
+// StrictBools returns list of bool divided by given delimiter or error on first invalid input.
+func (k *Key) StrictBools(delim string) ([]bool, error) {
+ return k.parseBools(k.Strings(delim), false, true)
+}
+
+// StrictTimesFormat parses with given format and returns list of time.Time divided by given delimiter
+// or error on first invalid input.
+func (k *Key) StrictTimesFormat(format, delim string) ([]time.Time, error) {
+ return k.parseTimesFormat(format, k.Strings(delim), false, true)
+}
+
+// StrictTimes parses with RFC3339 format and returns list of time.Time divided by given delimiter
+// or error on first invalid input.
+func (k *Key) StrictTimes(delim string) ([]time.Time, error) {
+ return k.StrictTimesFormat(time.RFC3339, delim)
+}
+
+// parseBools transforms strings to bools.
+func (k *Key) parseBools(strs []string, addInvalid, returnOnInvalid bool) ([]bool, error) {
+ vals := make([]bool, 0, len(strs))
+ for _, str := range strs {
+ val, err := parseBool(str)
+ if err != nil && returnOnInvalid {
+ return nil, err
+ }
+ if err == nil || addInvalid {
+ vals = append(vals, val)
+ }
+ }
+ return vals, nil
+}
+
+// parseFloat64s transforms strings to float64s.
+func (k *Key) parseFloat64s(strs []string, addInvalid, returnOnInvalid bool) ([]float64, error) {
+ vals := make([]float64, 0, len(strs))
+ for _, str := range strs {
+ val, err := strconv.ParseFloat(str, 64)
+ if err != nil && returnOnInvalid {
+ return nil, err
+ }
+ if err == nil || addInvalid {
+ vals = append(vals, val)
+ }
+ }
+ return vals, nil
+}
+
+// parseInts transforms strings to ints.
+func (k *Key) parseInts(strs []string, addInvalid, returnOnInvalid bool) ([]int, error) {
+ vals := make([]int, 0, len(strs))
+ for _, str := range strs {
+ valInt64, err := strconv.ParseInt(str, 0, 64)
+ val := int(valInt64)
+ if err != nil && returnOnInvalid {
+ return nil, err
+ }
+ if err == nil || addInvalid {
+ vals = append(vals, val)
+ }
+ }
+ return vals, nil
+}
+
+// parseInt64s transforms strings to int64s.
+func (k *Key) parseInt64s(strs []string, addInvalid, returnOnInvalid bool) ([]int64, error) {
+ vals := make([]int64, 0, len(strs))
+ for _, str := range strs {
+ val, err := strconv.ParseInt(str, 0, 64)
+ if err != nil && returnOnInvalid {
+ return nil, err
+ }
+ if err == nil || addInvalid {
+ vals = append(vals, val)
+ }
+ }
+ return vals, nil
+}
+
+// parseUints transforms strings to uints.
+func (k *Key) parseUints(strs []string, addInvalid, returnOnInvalid bool) ([]uint, error) {
+ vals := make([]uint, 0, len(strs))
+ for _, str := range strs {
+ val, err := strconv.ParseUint(str, 0, 0)
+ if err != nil && returnOnInvalid {
+ return nil, err
+ }
+ if err == nil || addInvalid {
+ vals = append(vals, uint(val))
+ }
+ }
+ return vals, nil
+}
+
+// parseUint64s transforms strings to uint64s.
+func (k *Key) parseUint64s(strs []string, addInvalid, returnOnInvalid bool) ([]uint64, error) {
+ vals := make([]uint64, 0, len(strs))
+ for _, str := range strs {
+ val, err := strconv.ParseUint(str, 0, 64)
+ if err != nil && returnOnInvalid {
+ return nil, err
+ }
+ if err == nil || addInvalid {
+ vals = append(vals, val)
+ }
+ }
+ return vals, nil
+}
+
+// parseTimesFormat transforms strings to times in given format.
+func (k *Key) parseTimesFormat(format string, strs []string, addInvalid, returnOnInvalid bool) ([]time.Time, error) {
+ vals := make([]time.Time, 0, len(strs))
+ for _, str := range strs {
+ val, err := time.Parse(format, str)
+ if err != nil && returnOnInvalid {
+ return nil, err
+ }
+ if err == nil || addInvalid {
+ vals = append(vals, val)
+ }
+ }
+ return vals, nil
+}
+
+// SetValue changes key value.
+func (k *Key) SetValue(v string) {
+ if k.s.f.BlockMode {
+ k.s.f.lock.Lock()
+ defer k.s.f.lock.Unlock()
+ }
+
+ k.value = v
+ k.s.keysHash[k.name] = v
+}
diff --git a/vendor/gopkg.in/ini.v1/parser.go b/vendor/gopkg.in/ini.v1/parser.go
new file mode 100644
index 0000000000..53ab45c46f
--- /dev/null
+++ b/vendor/gopkg.in/ini.v1/parser.go
@@ -0,0 +1,526 @@
+// Copyright 2015 Unknwon
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package ini
+
+import (
+ "bufio"
+ "bytes"
+ "fmt"
+ "io"
+ "regexp"
+ "strconv"
+ "strings"
+ "unicode"
+)
+
+const minReaderBufferSize = 4096
+
+var pythonMultiline = regexp.MustCompile(`^([\t\f ]+)(.*)`)
+
+type parserOptions struct {
+ IgnoreContinuation bool
+ IgnoreInlineComment bool
+ AllowPythonMultilineValues bool
+ SpaceBeforeInlineComment bool
+ UnescapeValueDoubleQuotes bool
+ UnescapeValueCommentSymbols bool
+ PreserveSurroundedQuote bool
+ DebugFunc DebugFunc
+ ReaderBufferSize int
+}
+
+type parser struct {
+ buf *bufio.Reader
+ options parserOptions
+
+ isEOF bool
+ count int
+ comment *bytes.Buffer
+}
+
+func (p *parser) debug(format string, args ...interface{}) {
+ if p.options.DebugFunc != nil {
+ p.options.DebugFunc(fmt.Sprintf(format, args...))
+ }
+}
+
+func newParser(r io.Reader, opts parserOptions) *parser {
+ size := opts.ReaderBufferSize
+ if size < minReaderBufferSize {
+ size = minReaderBufferSize
+ }
+
+ return &parser{
+ buf: bufio.NewReaderSize(r, size),
+ options: opts,
+ count: 1,
+ comment: &bytes.Buffer{},
+ }
+}
+
+// BOM handles header of UTF-8, UTF-16 LE and UTF-16 BE's BOM format.
+// http://en.wikipedia.org/wiki/Byte_order_mark#Representations_of_byte_order_marks_by_encoding
+func (p *parser) BOM() error {
+ mask, err := p.buf.Peek(2)
+ if err != nil && err != io.EOF {
+ return err
+ } else if len(mask) < 2 {
+ return nil
+ }
+
+ switch {
+ case mask[0] == 254 && mask[1] == 255:
+ fallthrough
+ case mask[0] == 255 && mask[1] == 254:
+ p.buf.Read(mask)
+ case mask[0] == 239 && mask[1] == 187:
+ mask, err := p.buf.Peek(3)
+ if err != nil && err != io.EOF {
+ return err
+ } else if len(mask) < 3 {
+ return nil
+ }
+ if mask[2] == 191 {
+ p.buf.Read(mask)
+ }
+ }
+ return nil
+}
+
+func (p *parser) readUntil(delim byte) ([]byte, error) {
+ data, err := p.buf.ReadBytes(delim)
+ if err != nil {
+ if err == io.EOF {
+ p.isEOF = true
+ } else {
+ return nil, err
+ }
+ }
+ return data, nil
+}
+
+func cleanComment(in []byte) ([]byte, bool) {
+ i := bytes.IndexAny(in, "#;")
+ if i == -1 {
+ return nil, false
+ }
+ return in[i:], true
+}
+
+func readKeyName(delimiters string, in []byte) (string, int, error) {
+ line := string(in)
+
+ // Check if key name surrounded by quotes.
+ var keyQuote string
+ if line[0] == '"' {
+ if len(line) > 6 && string(line[0:3]) == `"""` {
+ keyQuote = `"""`
+ } else {
+ keyQuote = `"`
+ }
+ } else if line[0] == '`' {
+ keyQuote = "`"
+ }
+
+ // Get out key name
+ endIdx := -1
+ if len(keyQuote) > 0 {
+ startIdx := len(keyQuote)
+ // FIXME: fail case -> """"""name"""=value
+ pos := strings.Index(line[startIdx:], keyQuote)
+ if pos == -1 {
+ return "", -1, fmt.Errorf("missing closing key quote: %s", line)
+ }
+ pos += startIdx
+
+ // Find key-value delimiter
+ i := strings.IndexAny(line[pos+startIdx:], delimiters)
+ if i < 0 {
+ return "", -1, ErrDelimiterNotFound{line}
+ }
+ endIdx = pos + i
+ return strings.TrimSpace(line[startIdx:pos]), endIdx + startIdx + 1, nil
+ }
+
+ endIdx = strings.IndexAny(line, delimiters)
+ if endIdx < 0 {
+ return "", -1, ErrDelimiterNotFound{line}
+ }
+ return strings.TrimSpace(line[0:endIdx]), endIdx + 1, nil
+}
+
+func (p *parser) readMultilines(line, val, valQuote string) (string, error) {
+ for {
+ data, err := p.readUntil('\n')
+ if err != nil {
+ return "", err
+ }
+ next := string(data)
+
+ pos := strings.LastIndex(next, valQuote)
+ if pos > -1 {
+ val += next[:pos]
+
+ comment, has := cleanComment([]byte(next[pos:]))
+ if has {
+ p.comment.Write(bytes.TrimSpace(comment))
+ }
+ break
+ }
+ val += next
+ if p.isEOF {
+ return "", fmt.Errorf("missing closing key quote from '%s' to '%s'", line, next)
+ }
+ }
+ return val, nil
+}
+
+func (p *parser) readContinuationLines(val string) (string, error) {
+ for {
+ data, err := p.readUntil('\n')
+ if err != nil {
+ return "", err
+ }
+ next := strings.TrimSpace(string(data))
+
+ if len(next) == 0 {
+ break
+ }
+ val += next
+ if val[len(val)-1] != '\\' {
+ break
+ }
+ val = val[:len(val)-1]
+ }
+ return val, nil
+}
+
+// hasSurroundedQuote check if and only if the first and last characters
+// are quotes \" or \'.
+// It returns false if any other parts also contain same kind of quotes.
+func hasSurroundedQuote(in string, quote byte) bool {
+ return len(in) >= 2 && in[0] == quote && in[len(in)-1] == quote &&
+ strings.IndexByte(in[1:], quote) == len(in)-2
+}
+
+func (p *parser) readValue(in []byte, bufferSize int) (string, error) {
+
+ line := strings.TrimLeftFunc(string(in), unicode.IsSpace)
+ if len(line) == 0 {
+ if p.options.AllowPythonMultilineValues && len(in) > 0 && in[len(in)-1] == '\n' {
+ return p.readPythonMultilines(line, bufferSize)
+ }
+ return "", nil
+ }
+
+ var valQuote string
+ if len(line) > 3 && string(line[0:3]) == `"""` {
+ valQuote = `"""`
+ } else if line[0] == '`' {
+ valQuote = "`"
+ } else if p.options.UnescapeValueDoubleQuotes && line[0] == '"' {
+ valQuote = `"`
+ }
+
+ if len(valQuote) > 0 {
+ startIdx := len(valQuote)
+ pos := strings.LastIndex(line[startIdx:], valQuote)
+ // Check for multi-line value
+ if pos == -1 {
+ return p.readMultilines(line, line[startIdx:], valQuote)
+ }
+
+ if p.options.UnescapeValueDoubleQuotes && valQuote == `"` {
+ return strings.Replace(line[startIdx:pos+startIdx], `\"`, `"`, -1), nil
+ }
+ return line[startIdx : pos+startIdx], nil
+ }
+
+ lastChar := line[len(line)-1]
+ // Won't be able to reach here if value only contains whitespace
+ line = strings.TrimSpace(line)
+ trimmedLastChar := line[len(line)-1]
+
+ // Check continuation lines when desired
+ if !p.options.IgnoreContinuation && trimmedLastChar == '\\' {
+ return p.readContinuationLines(line[:len(line)-1])
+ }
+
+ // Check if ignore inline comment
+ if !p.options.IgnoreInlineComment {
+ var i int
+ if p.options.SpaceBeforeInlineComment {
+ i = strings.Index(line, " #")
+ if i == -1 {
+ i = strings.Index(line, " ;")
+ }
+
+ } else {
+ i = strings.IndexAny(line, "#;")
+ }
+
+ if i > -1 {
+ p.comment.WriteString(line[i:])
+ line = strings.TrimSpace(line[:i])
+ }
+
+ }
+
+ // Trim single and double quotes
+ if (hasSurroundedQuote(line, '\'') ||
+ hasSurroundedQuote(line, '"')) && !p.options.PreserveSurroundedQuote {
+ line = line[1 : len(line)-1]
+ } else if len(valQuote) == 0 && p.options.UnescapeValueCommentSymbols {
+ if strings.Contains(line, `\;`) {
+ line = strings.Replace(line, `\;`, ";", -1)
+ }
+ if strings.Contains(line, `\#`) {
+ line = strings.Replace(line, `\#`, "#", -1)
+ }
+ } else if p.options.AllowPythonMultilineValues && lastChar == '\n' {
+ return p.readPythonMultilines(line, bufferSize)
+ }
+
+ return line, nil
+}
+
+func (p *parser) readPythonMultilines(line string, bufferSize int) (string, error) {
+ parserBufferPeekResult, _ := p.buf.Peek(bufferSize)
+ peekBuffer := bytes.NewBuffer(parserBufferPeekResult)
+
+ indentSize := 0
+ for {
+ peekData, peekErr := peekBuffer.ReadBytes('\n')
+ if peekErr != nil {
+ if peekErr == io.EOF {
+ p.debug("readPythonMultilines: io.EOF, peekData: %q, line: %q", string(peekData), line)
+ return line, nil
+ }
+
+ p.debug("readPythonMultilines: failed to peek with error: %v", peekErr)
+ return "", peekErr
+ }
+
+ p.debug("readPythonMultilines: parsing %q", string(peekData))
+
+ peekMatches := pythonMultiline.FindStringSubmatch(string(peekData))
+ p.debug("readPythonMultilines: matched %d parts", len(peekMatches))
+ for n, v := range peekMatches {
+ p.debug(" %d: %q", n, v)
+ }
+
+ // Return if not a Python multiline value.
+ if len(peekMatches) != 3 {
+ p.debug("readPythonMultilines: end of value, got: %q", line)
+ return line, nil
+ }
+
+ // Determine indent size and line prefix.
+ currentIndentSize := len(peekMatches[1])
+ if indentSize < 1 {
+ indentSize = currentIndentSize
+ p.debug("readPythonMultilines: indent size is %d", indentSize)
+ }
+
+ // Make sure each line is indented at least as far as first line.
+ if currentIndentSize < indentSize {
+ p.debug("readPythonMultilines: end of value, current indent: %d, expected indent: %d, line: %q", currentIndentSize, indentSize, line)
+ return line, nil
+ }
+
+ // Advance the parser reader (buffer) in-sync with the peek buffer.
+ _, err := p.buf.Discard(len(peekData))
+ if err != nil {
+ p.debug("readPythonMultilines: failed to skip to the end, returning error")
+ return "", err
+ }
+
+ // Handle indented empty line.
+ line += "\n" + peekMatches[1][indentSize:] + peekMatches[2]
+ }
+}
+
+// parse parses data through an io.Reader.
+func (f *File) parse(reader io.Reader) (err error) {
+ p := newParser(reader, parserOptions{
+ IgnoreContinuation: f.options.IgnoreContinuation,
+ IgnoreInlineComment: f.options.IgnoreInlineComment,
+ AllowPythonMultilineValues: f.options.AllowPythonMultilineValues,
+ SpaceBeforeInlineComment: f.options.SpaceBeforeInlineComment,
+ UnescapeValueDoubleQuotes: f.options.UnescapeValueDoubleQuotes,
+ UnescapeValueCommentSymbols: f.options.UnescapeValueCommentSymbols,
+ PreserveSurroundedQuote: f.options.PreserveSurroundedQuote,
+ DebugFunc: f.options.DebugFunc,
+ ReaderBufferSize: f.options.ReaderBufferSize,
+ })
+ if err = p.BOM(); err != nil {
+ return fmt.Errorf("BOM: %v", err)
+ }
+
+ // Ignore error because default section name is never empty string.
+ name := DefaultSection
+ if f.options.Insensitive {
+ name = strings.ToLower(DefaultSection)
+ }
+ section, _ := f.NewSection(name)
+
+ // This "last" is not strictly equivalent to "previous one" if current key is not the first nested key
+ var isLastValueEmpty bool
+ var lastRegularKey *Key
+
+ var line []byte
+ var inUnparseableSection bool
+
+ // NOTE: Iterate and increase `currentPeekSize` until
+ // the size of the parser buffer is found.
+ // TODO(unknwon): When Golang 1.10 is the lowest version supported, replace with `parserBufferSize := p.buf.Size()`.
+ parserBufferSize := 0
+ // NOTE: Peek 4kb at a time.
+ currentPeekSize := minReaderBufferSize
+
+ if f.options.AllowPythonMultilineValues {
+ for {
+ peekBytes, _ := p.buf.Peek(currentPeekSize)
+ peekBytesLength := len(peekBytes)
+
+ if parserBufferSize >= peekBytesLength {
+ break
+ }
+
+ currentPeekSize *= 2
+ parserBufferSize = peekBytesLength
+ }
+ }
+
+ for !p.isEOF {
+ line, err = p.readUntil('\n')
+ if err != nil {
+ return err
+ }
+
+ if f.options.AllowNestedValues &&
+ isLastValueEmpty && len(line) > 0 {
+ if line[0] == ' ' || line[0] == '\t' {
+ lastRegularKey.addNestedValue(string(bytes.TrimSpace(line)))
+ continue
+ }
+ }
+
+ line = bytes.TrimLeftFunc(line, unicode.IsSpace)
+ if len(line) == 0 {
+ continue
+ }
+
+ // Comments
+ if line[0] == '#' || line[0] == ';' {
+ // Note: we do not care ending line break,
+ // it is needed for adding second line,
+ // so just clean it once at the end when set to value.
+ p.comment.Write(line)
+ continue
+ }
+
+ // Section
+ if line[0] == '[' {
+ // Read to the next ']' (TODO: support quoted strings)
+ closeIdx := bytes.LastIndexByte(line, ']')
+ if closeIdx == -1 {
+ return fmt.Errorf("unclosed section: %s", line)
+ }
+
+ name := string(line[1:closeIdx])
+ section, err = f.NewSection(name)
+ if err != nil {
+ return err
+ }
+
+ comment, has := cleanComment(line[closeIdx+1:])
+ if has {
+ p.comment.Write(comment)
+ }
+
+ section.Comment = strings.TrimSpace(p.comment.String())
+
+ // Reset aotu-counter and comments
+ p.comment.Reset()
+ p.count = 1
+
+ inUnparseableSection = false
+ for i := range f.options.UnparseableSections {
+ if f.options.UnparseableSections[i] == name ||
+ (f.options.Insensitive && strings.ToLower(f.options.UnparseableSections[i]) == strings.ToLower(name)) {
+ inUnparseableSection = true
+ continue
+ }
+ }
+ continue
+ }
+
+ if inUnparseableSection {
+ section.isRawSection = true
+ section.rawBody += string(line)
+ continue
+ }
+
+ kname, offset, err := readKeyName(f.options.KeyValueDelimiters, line)
+ if err != nil {
+ // Treat as boolean key when desired, and whole line is key name.
+ if IsErrDelimiterNotFound(err) {
+ switch {
+ case f.options.AllowBooleanKeys:
+ kname, err := p.readValue(line, parserBufferSize)
+ if err != nil {
+ return err
+ }
+ key, err := section.NewBooleanKey(kname)
+ if err != nil {
+ return err
+ }
+ key.Comment = strings.TrimSpace(p.comment.String())
+ p.comment.Reset()
+ continue
+
+ case f.options.SkipUnrecognizableLines:
+ continue
+ }
+ }
+ return err
+ }
+
+ // Auto increment.
+ isAutoIncr := false
+ if kname == "-" {
+ isAutoIncr = true
+ kname = "#" + strconv.Itoa(p.count)
+ p.count++
+ }
+
+ value, err := p.readValue(line[offset:], parserBufferSize)
+ if err != nil {
+ return err
+ }
+ isLastValueEmpty = len(value) == 0
+
+ key, err := section.NewKey(kname, value)
+ if err != nil {
+ return err
+ }
+ key.isAutoIncrement = isAutoIncr
+ key.Comment = strings.TrimSpace(p.comment.String())
+ p.comment.Reset()
+ lastRegularKey = key
+ }
+ return nil
+}
diff --git a/vendor/gopkg.in/ini.v1/section.go b/vendor/gopkg.in/ini.v1/section.go
new file mode 100644
index 0000000000..0bd3e13015
--- /dev/null
+++ b/vendor/gopkg.in/ini.v1/section.go
@@ -0,0 +1,256 @@
+// Copyright 2014 Unknwon
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package ini
+
+import (
+ "errors"
+ "fmt"
+ "strings"
+)
+
+// Section represents a config section.
+type Section struct {
+ f *File
+ Comment string
+ name string
+ keys map[string]*Key
+ keyList []string
+ keysHash map[string]string
+
+ isRawSection bool
+ rawBody string
+}
+
+func newSection(f *File, name string) *Section {
+ return &Section{
+ f: f,
+ name: name,
+ keys: make(map[string]*Key),
+ keyList: make([]string, 0, 10),
+ keysHash: make(map[string]string),
+ }
+}
+
+// Name returns name of Section.
+func (s *Section) Name() string {
+ return s.name
+}
+
+// Body returns rawBody of Section if the section was marked as unparseable.
+// It still follows the other rules of the INI format surrounding leading/trailing whitespace.
+func (s *Section) Body() string {
+ return strings.TrimSpace(s.rawBody)
+}
+
+// SetBody updates body content only if section is raw.
+func (s *Section) SetBody(body string) {
+ if !s.isRawSection {
+ return
+ }
+ s.rawBody = body
+}
+
+// NewKey creates a new key to given section.
+func (s *Section) NewKey(name, val string) (*Key, error) {
+ if len(name) == 0 {
+ return nil, errors.New("error creating new key: empty key name")
+ } else if s.f.options.Insensitive {
+ name = strings.ToLower(name)
+ }
+
+ if s.f.BlockMode {
+ s.f.lock.Lock()
+ defer s.f.lock.Unlock()
+ }
+
+ if inSlice(name, s.keyList) {
+ if s.f.options.AllowShadows {
+ if err := s.keys[name].addShadow(val); err != nil {
+ return nil, err
+ }
+ } else {
+ s.keys[name].value = val
+ s.keysHash[name] = val
+ }
+ return s.keys[name], nil
+ }
+
+ s.keyList = append(s.keyList, name)
+ s.keys[name] = newKey(s, name, val)
+ s.keysHash[name] = val
+ return s.keys[name], nil
+}
+
+// NewBooleanKey creates a new boolean type key to given section.
+func (s *Section) NewBooleanKey(name string) (*Key, error) {
+ key, err := s.NewKey(name, "true")
+ if err != nil {
+ return nil, err
+ }
+
+ key.isBooleanType = true
+ return key, nil
+}
+
+// GetKey returns key in section by given name.
+func (s *Section) GetKey(name string) (*Key, error) {
+ if s.f.BlockMode {
+ s.f.lock.RLock()
+ }
+ if s.f.options.Insensitive {
+ name = strings.ToLower(name)
+ }
+ key := s.keys[name]
+ if s.f.BlockMode {
+ s.f.lock.RUnlock()
+ }
+
+ if key == nil {
+ // Check if it is a child-section.
+ sname := s.name
+ for {
+ if i := strings.LastIndex(sname, "."); i > -1 {
+ sname = sname[:i]
+ sec, err := s.f.GetSection(sname)
+ if err != nil {
+ continue
+ }
+ return sec.GetKey(name)
+ }
+ break
+ }
+ return nil, fmt.Errorf("error when getting key of section '%s': key '%s' not exists", s.name, name)
+ }
+ return key, nil
+}
+
+// HasKey returns true if section contains a key with given name.
+func (s *Section) HasKey(name string) bool {
+ key, _ := s.GetKey(name)
+ return key != nil
+}
+
+// Deprecated: Use "HasKey" instead.
+func (s *Section) Haskey(name string) bool {
+ return s.HasKey(name)
+}
+
+// HasValue returns true if section contains given raw value.
+func (s *Section) HasValue(value string) bool {
+ if s.f.BlockMode {
+ s.f.lock.RLock()
+ defer s.f.lock.RUnlock()
+ }
+
+ for _, k := range s.keys {
+ if value == k.value {
+ return true
+ }
+ }
+ return false
+}
+
+// Key assumes named Key exists in section and returns a zero-value when not.
+func (s *Section) Key(name string) *Key {
+ key, err := s.GetKey(name)
+ if err != nil {
+ // It's OK here because the only possible error is empty key name,
+ // but if it's empty, this piece of code won't be executed.
+ key, _ = s.NewKey(name, "")
+ return key
+ }
+ return key
+}
+
+// Keys returns list of keys of section.
+func (s *Section) Keys() []*Key {
+ keys := make([]*Key, len(s.keyList))
+ for i := range s.keyList {
+ keys[i] = s.Key(s.keyList[i])
+ }
+ return keys
+}
+
+// ParentKeys returns list of keys of parent section.
+func (s *Section) ParentKeys() []*Key {
+ var parentKeys []*Key
+ sname := s.name
+ for {
+ if i := strings.LastIndex(sname, "."); i > -1 {
+ sname = sname[:i]
+ sec, err := s.f.GetSection(sname)
+ if err != nil {
+ continue
+ }
+ parentKeys = append(parentKeys, sec.Keys()...)
+ } else {
+ break
+ }
+
+ }
+ return parentKeys
+}
+
+// KeyStrings returns list of key names of section.
+func (s *Section) KeyStrings() []string {
+ list := make([]string, len(s.keyList))
+ copy(list, s.keyList)
+ return list
+}
+
+// KeysHash returns keys hash consisting of names and values.
+func (s *Section) KeysHash() map[string]string {
+ if s.f.BlockMode {
+ s.f.lock.RLock()
+ defer s.f.lock.RUnlock()
+ }
+
+ hash := map[string]string{}
+ for key, value := range s.keysHash {
+ hash[key] = value
+ }
+ return hash
+}
+
+// DeleteKey deletes a key from section.
+func (s *Section) DeleteKey(name string) {
+ if s.f.BlockMode {
+ s.f.lock.Lock()
+ defer s.f.lock.Unlock()
+ }
+
+ for i, k := range s.keyList {
+ if k == name {
+ s.keyList = append(s.keyList[:i], s.keyList[i+1:]...)
+ delete(s.keys, name)
+ delete(s.keysHash, name)
+ return
+ }
+ }
+}
+
+// ChildSections returns a list of child sections of current section.
+// For example, "[parent.child1]" and "[parent.child12]" are child sections
+// of section "[parent]".
+func (s *Section) ChildSections() []*Section {
+ prefix := s.name + "."
+ children := make([]*Section, 0, 3)
+ for _, name := range s.f.sectionList {
+ if strings.HasPrefix(name, prefix) {
+ children = append(children, s.f.sections[name])
+ }
+ }
+ return children
+}
diff --git a/vendor/gopkg.in/ini.v1/struct.go b/vendor/gopkg.in/ini.v1/struct.go
new file mode 100644
index 0000000000..6bc70e4d4f
--- /dev/null
+++ b/vendor/gopkg.in/ini.v1/struct.go
@@ -0,0 +1,603 @@
+// Copyright 2014 Unknwon
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package ini
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "reflect"
+ "strings"
+ "time"
+ "unicode"
+)
+
+// NameMapper represents a ini tag name mapper.
+type NameMapper func(string) string
+
+// Built-in name getters.
+var (
+ // SnackCase converts to format SNACK_CASE.
+ SnackCase NameMapper = func(raw string) string {
+ newstr := make([]rune, 0, len(raw))
+ for i, chr := range raw {
+ if isUpper := 'A' <= chr && chr <= 'Z'; isUpper {
+ if i > 0 {
+ newstr = append(newstr, '_')
+ }
+ }
+ newstr = append(newstr, unicode.ToUpper(chr))
+ }
+ return string(newstr)
+ }
+ // TitleUnderscore converts to format title_underscore.
+ TitleUnderscore NameMapper = func(raw string) string {
+ newstr := make([]rune, 0, len(raw))
+ for i, chr := range raw {
+ if isUpper := 'A' <= chr && chr <= 'Z'; isUpper {
+ if i > 0 {
+ newstr = append(newstr, '_')
+ }
+ chr -= 'A' - 'a'
+ }
+ newstr = append(newstr, chr)
+ }
+ return string(newstr)
+ }
+)
+
+func (s *Section) parseFieldName(raw, actual string) string {
+ if len(actual) > 0 {
+ return actual
+ }
+ if s.f.NameMapper != nil {
+ return s.f.NameMapper(raw)
+ }
+ return raw
+}
+
+func parseDelim(actual string) string {
+ if len(actual) > 0 {
+ return actual
+ }
+ return ","
+}
+
+var reflectTime = reflect.TypeOf(time.Now()).Kind()
+
+// setSliceWithProperType sets proper values to slice based on its type.
+func setSliceWithProperType(key *Key, field reflect.Value, delim string, allowShadow, isStrict bool) error {
+ var strs []string
+ if allowShadow {
+ strs = key.StringsWithShadows(delim)
+ } else {
+ strs = key.Strings(delim)
+ }
+
+ numVals := len(strs)
+ if numVals == 0 {
+ return nil
+ }
+
+ var vals interface{}
+ var err error
+
+ sliceOf := field.Type().Elem().Kind()
+ switch sliceOf {
+ case reflect.String:
+ vals = strs
+ case reflect.Int:
+ vals, err = key.parseInts(strs, true, false)
+ case reflect.Int64:
+ vals, err = key.parseInt64s(strs, true, false)
+ case reflect.Uint:
+ vals, err = key.parseUints(strs, true, false)
+ case reflect.Uint64:
+ vals, err = key.parseUint64s(strs, true, false)
+ case reflect.Float64:
+ vals, err = key.parseFloat64s(strs, true, false)
+ case reflect.Bool:
+ vals, err = key.parseBools(strs, true, false)
+ case reflectTime:
+ vals, err = key.parseTimesFormat(time.RFC3339, strs, true, false)
+ default:
+ return fmt.Errorf("unsupported type '[]%s'", sliceOf)
+ }
+ if err != nil && isStrict {
+ return err
+ }
+
+ slice := reflect.MakeSlice(field.Type(), numVals, numVals)
+ for i := 0; i < numVals; i++ {
+ switch sliceOf {
+ case reflect.String:
+ slice.Index(i).Set(reflect.ValueOf(vals.([]string)[i]))
+ case reflect.Int:
+ slice.Index(i).Set(reflect.ValueOf(vals.([]int)[i]))
+ case reflect.Int64:
+ slice.Index(i).Set(reflect.ValueOf(vals.([]int64)[i]))
+ case reflect.Uint:
+ slice.Index(i).Set(reflect.ValueOf(vals.([]uint)[i]))
+ case reflect.Uint64:
+ slice.Index(i).Set(reflect.ValueOf(vals.([]uint64)[i]))
+ case reflect.Float64:
+ slice.Index(i).Set(reflect.ValueOf(vals.([]float64)[i]))
+ case reflect.Bool:
+ slice.Index(i).Set(reflect.ValueOf(vals.([]bool)[i]))
+ case reflectTime:
+ slice.Index(i).Set(reflect.ValueOf(vals.([]time.Time)[i]))
+ }
+ }
+ field.Set(slice)
+ return nil
+}
+
+func wrapStrictError(err error, isStrict bool) error {
+ if isStrict {
+ return err
+ }
+ return nil
+}
+
+// setWithProperType sets proper value to field based on its type,
+// but it does not return error for failing parsing,
+// because we want to use default value that is already assigned to struct.
+func setWithProperType(t reflect.Type, key *Key, field reflect.Value, delim string, allowShadow, isStrict bool) error {
+ vt := t
+ isPtr := t.Kind() == reflect.Ptr
+ if isPtr {
+ vt = t.Elem()
+ }
+ switch vt.Kind() {
+ case reflect.String:
+ stringVal := key.String()
+ if isPtr {
+ field.Set(reflect.ValueOf(&stringVal))
+ } else if len(stringVal) > 0 {
+ field.SetString(key.String())
+ }
+ case reflect.Bool:
+ boolVal, err := key.Bool()
+ if err != nil {
+ return wrapStrictError(err, isStrict)
+ }
+ if isPtr {
+ field.Set(reflect.ValueOf(&boolVal))
+ } else {
+ field.SetBool(boolVal)
+ }
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ // ParseDuration will not return err for `0`, so check the type name
+ if vt.Name() == "Duration" {
+ durationVal, err := key.Duration()
+ if err != nil {
+ return wrapStrictError(err, isStrict)
+ }
+ if isPtr {
+ field.Set(reflect.ValueOf(&durationVal))
+ } else if int64(durationVal) > 0 {
+ field.Set(reflect.ValueOf(durationVal))
+ }
+ return nil
+ }
+
+ intVal, err := key.Int64()
+ if err != nil {
+ return wrapStrictError(err, isStrict)
+ }
+ if isPtr {
+ pv := reflect.New(t.Elem())
+ pv.Elem().SetInt(intVal)
+ field.Set(pv)
+ } else {
+ field.SetInt(intVal)
+ }
+ // byte is an alias for uint8, so supporting uint8 breaks support for byte
+ case reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+ durationVal, err := key.Duration()
+ // Skip zero value
+ if err == nil && uint64(durationVal) > 0 {
+ if isPtr {
+ field.Set(reflect.ValueOf(&durationVal))
+ } else {
+ field.Set(reflect.ValueOf(durationVal))
+ }
+ return nil
+ }
+
+ uintVal, err := key.Uint64()
+ if err != nil {
+ return wrapStrictError(err, isStrict)
+ }
+ if isPtr {
+ pv := reflect.New(t.Elem())
+ pv.Elem().SetUint(uintVal)
+ field.Set(pv)
+ } else {
+ field.SetUint(uintVal)
+ }
+
+ case reflect.Float32, reflect.Float64:
+ floatVal, err := key.Float64()
+ if err != nil {
+ return wrapStrictError(err, isStrict)
+ }
+ if isPtr {
+ pv := reflect.New(t.Elem())
+ pv.Elem().SetFloat(floatVal)
+ field.Set(pv)
+ } else {
+ field.SetFloat(floatVal)
+ }
+ case reflectTime:
+ timeVal, err := key.Time()
+ if err != nil {
+ return wrapStrictError(err, isStrict)
+ }
+ if isPtr {
+ field.Set(reflect.ValueOf(&timeVal))
+ } else {
+ field.Set(reflect.ValueOf(timeVal))
+ }
+ case reflect.Slice:
+ return setSliceWithProperType(key, field, delim, allowShadow, isStrict)
+ default:
+ return fmt.Errorf("unsupported type '%s'", t)
+ }
+ return nil
+}
+
+func parseTagOptions(tag string) (rawName string, omitEmpty bool, allowShadow bool) {
+ opts := strings.SplitN(tag, ",", 3)
+ rawName = opts[0]
+ if len(opts) > 1 {
+ omitEmpty = opts[1] == "omitempty"
+ }
+ if len(opts) > 2 {
+ allowShadow = opts[2] == "allowshadow"
+ }
+ return rawName, omitEmpty, allowShadow
+}
+
+func (s *Section) mapTo(val reflect.Value, isStrict bool) error {
+ if val.Kind() == reflect.Ptr {
+ val = val.Elem()
+ }
+ typ := val.Type()
+
+ for i := 0; i < typ.NumField(); i++ {
+ field := val.Field(i)
+ tpField := typ.Field(i)
+
+ tag := tpField.Tag.Get("ini")
+ if tag == "-" {
+ continue
+ }
+
+ rawName, _, allowShadow := parseTagOptions(tag)
+ fieldName := s.parseFieldName(tpField.Name, rawName)
+ if len(fieldName) == 0 || !field.CanSet() {
+ continue
+ }
+
+ isStruct := tpField.Type.Kind() == reflect.Struct
+ isStructPtr := tpField.Type.Kind() == reflect.Ptr && tpField.Type.Elem().Kind() == reflect.Struct
+ isAnonymous := tpField.Type.Kind() == reflect.Ptr && tpField.Anonymous
+ if isAnonymous {
+ field.Set(reflect.New(tpField.Type.Elem()))
+ }
+
+ if isAnonymous || isStruct || isStructPtr {
+ if sec, err := s.f.GetSection(fieldName); err == nil {
+ // Only set the field to non-nil struct value if we have
+ // a section for it. Otherwise, we end up with a non-nil
+ // struct ptr even though there is no data.
+ if isStructPtr && field.IsNil() {
+ field.Set(reflect.New(tpField.Type.Elem()))
+ }
+ if err = sec.mapTo(field, isStrict); err != nil {
+ return fmt.Errorf("error mapping field(%s): %v", fieldName, err)
+ }
+ continue
+ }
+ }
+ if key, err := s.GetKey(fieldName); err == nil {
+ delim := parseDelim(tpField.Tag.Get("delim"))
+ if err = setWithProperType(tpField.Type, key, field, delim, allowShadow, isStrict); err != nil {
+ return fmt.Errorf("error mapping field(%s): %v", fieldName, err)
+ }
+ }
+ }
+ return nil
+}
+
+// MapTo maps section to given struct.
+func (s *Section) MapTo(v interface{}) error {
+ typ := reflect.TypeOf(v)
+ val := reflect.ValueOf(v)
+ if typ.Kind() == reflect.Ptr {
+ typ = typ.Elem()
+ val = val.Elem()
+ } else {
+ return errors.New("cannot map to non-pointer struct")
+ }
+
+ return s.mapTo(val, false)
+}
+
+// StrictMapTo maps section to given struct in strict mode,
+// which returns all possible error including value parsing error.
+func (s *Section) StrictMapTo(v interface{}) error {
+ typ := reflect.TypeOf(v)
+ val := reflect.ValueOf(v)
+ if typ.Kind() == reflect.Ptr {
+ typ = typ.Elem()
+ val = val.Elem()
+ } else {
+ return errors.New("cannot map to non-pointer struct")
+ }
+
+ return s.mapTo(val, true)
+}
+
+// MapTo maps file to given struct.
+func (f *File) MapTo(v interface{}) error {
+ return f.Section("").MapTo(v)
+}
+
+// StrictMapTo maps file to given struct in strict mode,
+// which returns all possible error including value parsing error.
+func (f *File) StrictMapTo(v interface{}) error {
+ return f.Section("").StrictMapTo(v)
+}
+
+// MapToWithMapper maps data sources to given struct with name mapper.
+func MapToWithMapper(v interface{}, mapper NameMapper, source interface{}, others ...interface{}) error {
+ cfg, err := Load(source, others...)
+ if err != nil {
+ return err
+ }
+ cfg.NameMapper = mapper
+ return cfg.MapTo(v)
+}
+
+// StrictMapToWithMapper maps data sources to given struct with name mapper in strict mode,
+// which returns all possible error including value parsing error.
+func StrictMapToWithMapper(v interface{}, mapper NameMapper, source interface{}, others ...interface{}) error {
+ cfg, err := Load(source, others...)
+ if err != nil {
+ return err
+ }
+ cfg.NameMapper = mapper
+ return cfg.StrictMapTo(v)
+}
+
+// MapTo maps data sources to given struct.
+func MapTo(v, source interface{}, others ...interface{}) error {
+ return MapToWithMapper(v, nil, source, others...)
+}
+
+// StrictMapTo maps data sources to given struct in strict mode,
+// which returns all possible error including value parsing error.
+func StrictMapTo(v, source interface{}, others ...interface{}) error {
+ return StrictMapToWithMapper(v, nil, source, others...)
+}
+
+// reflectSliceWithProperType does the opposite thing as setSliceWithProperType.
+func reflectSliceWithProperType(key *Key, field reflect.Value, delim string, allowShadow bool) error {
+ slice := field.Slice(0, field.Len())
+ if field.Len() == 0 {
+ return nil
+ }
+ sliceOf := field.Type().Elem().Kind()
+
+ if allowShadow {
+ var keyWithShadows *Key
+ for i := 0; i < field.Len(); i++ {
+ var val string
+ switch sliceOf {
+ case reflect.String:
+ val = slice.Index(i).String()
+ case reflect.Int, reflect.Int64:
+ val = fmt.Sprint(slice.Index(i).Int())
+ case reflect.Uint, reflect.Uint64:
+ val = fmt.Sprint(slice.Index(i).Uint())
+ case reflect.Float64:
+ val = fmt.Sprint(slice.Index(i).Float())
+ case reflect.Bool:
+ val = fmt.Sprint(slice.Index(i).Bool())
+ case reflectTime:
+ val = slice.Index(i).Interface().(time.Time).Format(time.RFC3339)
+ default:
+ return fmt.Errorf("unsupported type '[]%s'", sliceOf)
+ }
+
+ if i == 0 {
+ keyWithShadows = newKey(key.s, key.name, val)
+ } else {
+ keyWithShadows.AddShadow(val)
+ }
+ }
+ key = keyWithShadows
+ return nil
+ }
+
+ var buf bytes.Buffer
+ for i := 0; i < field.Len(); i++ {
+ switch sliceOf {
+ case reflect.String:
+ buf.WriteString(slice.Index(i).String())
+ case reflect.Int, reflect.Int64:
+ buf.WriteString(fmt.Sprint(slice.Index(i).Int()))
+ case reflect.Uint, reflect.Uint64:
+ buf.WriteString(fmt.Sprint(slice.Index(i).Uint()))
+ case reflect.Float64:
+ buf.WriteString(fmt.Sprint(slice.Index(i).Float()))
+ case reflect.Bool:
+ buf.WriteString(fmt.Sprint(slice.Index(i).Bool()))
+ case reflectTime:
+ buf.WriteString(slice.Index(i).Interface().(time.Time).Format(time.RFC3339))
+ default:
+ return fmt.Errorf("unsupported type '[]%s'", sliceOf)
+ }
+ buf.WriteString(delim)
+ }
+ key.SetValue(buf.String()[:buf.Len()-len(delim)])
+ return nil
+}
+
+// reflectWithProperType does the opposite thing as setWithProperType.
+func reflectWithProperType(t reflect.Type, key *Key, field reflect.Value, delim string, allowShadow bool) error {
+ switch t.Kind() {
+ case reflect.String:
+ key.SetValue(field.String())
+ case reflect.Bool:
+ key.SetValue(fmt.Sprint(field.Bool()))
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ key.SetValue(fmt.Sprint(field.Int()))
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+ key.SetValue(fmt.Sprint(field.Uint()))
+ case reflect.Float32, reflect.Float64:
+ key.SetValue(fmt.Sprint(field.Float()))
+ case reflectTime:
+ key.SetValue(fmt.Sprint(field.Interface().(time.Time).Format(time.RFC3339)))
+ case reflect.Slice:
+ return reflectSliceWithProperType(key, field, delim, allowShadow)
+ case reflect.Ptr:
+ if !field.IsNil() {
+ return reflectWithProperType(t.Elem(), key, field.Elem(), delim, allowShadow)
+ }
+ default:
+ return fmt.Errorf("unsupported type '%s'", t)
+ }
+ return nil
+}
+
+// CR: copied from encoding/json/encode.go with modifications of time.Time support.
+// TODO: add more test coverage.
+func isEmptyValue(v reflect.Value) bool {
+ switch v.Kind() {
+ case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
+ return v.Len() == 0
+ case reflect.Bool:
+ return !v.Bool()
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return v.Int() == 0
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ return v.Uint() == 0
+ case reflect.Float32, reflect.Float64:
+ return v.Float() == 0
+ case reflect.Interface, reflect.Ptr:
+ return v.IsNil()
+ case reflectTime:
+ t, ok := v.Interface().(time.Time)
+ return ok && t.IsZero()
+ }
+ return false
+}
+
+func (s *Section) reflectFrom(val reflect.Value) error {
+ if val.Kind() == reflect.Ptr {
+ val = val.Elem()
+ }
+ typ := val.Type()
+
+ for i := 0; i < typ.NumField(); i++ {
+ field := val.Field(i)
+ tpField := typ.Field(i)
+
+ tag := tpField.Tag.Get("ini")
+ if tag == "-" {
+ continue
+ }
+
+ rawName, omitEmpty, allowShadow := parseTagOptions(tag)
+ if omitEmpty && isEmptyValue(field) {
+ continue
+ }
+
+ fieldName := s.parseFieldName(tpField.Name, rawName)
+ if len(fieldName) == 0 || !field.CanSet() {
+ continue
+ }
+
+ if (tpField.Type.Kind() == reflect.Ptr && tpField.Anonymous) ||
+ (tpField.Type.Kind() == reflect.Struct && tpField.Type.Name() != "Time") {
+ // Note: The only error here is section doesn't exist.
+ sec, err := s.f.GetSection(fieldName)
+ if err != nil {
+ // Note: fieldName can never be empty here, ignore error.
+ sec, _ = s.f.NewSection(fieldName)
+ }
+
+ // Add comment from comment tag
+ if len(sec.Comment) == 0 {
+ sec.Comment = tpField.Tag.Get("comment")
+ }
+
+ if err = sec.reflectFrom(field); err != nil {
+ return fmt.Errorf("error reflecting field (%s): %v", fieldName, err)
+ }
+ continue
+ }
+
+ // Note: Same reason as secion.
+ key, err := s.GetKey(fieldName)
+ if err != nil {
+ key, _ = s.NewKey(fieldName, "")
+ }
+
+ // Add comment from comment tag
+ if len(key.Comment) == 0 {
+ key.Comment = tpField.Tag.Get("comment")
+ }
+
+ if err = reflectWithProperType(tpField.Type, key, field, parseDelim(tpField.Tag.Get("delim")), allowShadow); err != nil {
+ return fmt.Errorf("error reflecting field (%s): %v", fieldName, err)
+ }
+
+ }
+ return nil
+}
+
+// ReflectFrom reflects secion from given struct.
+func (s *Section) ReflectFrom(v interface{}) error {
+ typ := reflect.TypeOf(v)
+ val := reflect.ValueOf(v)
+ if typ.Kind() == reflect.Ptr {
+ typ = typ.Elem()
+ val = val.Elem()
+ } else {
+ return errors.New("cannot reflect from non-pointer struct")
+ }
+
+ return s.reflectFrom(val)
+}
+
+// ReflectFrom reflects file from given struct.
+func (f *File) ReflectFrom(v interface{}) error {
+ return f.Section("").ReflectFrom(v)
+}
+
+// ReflectFromWithMapper reflects data sources from given struct with name mapper.
+func ReflectFromWithMapper(cfg *File, v interface{}, mapper NameMapper) error {
+ cfg.NameMapper = mapper
+ return cfg.ReflectFrom(v)
+}
+
+// ReflectFrom reflects data sources from given struct.
+func ReflectFrom(cfg *File, v interface{}) error {
+ return ReflectFromWithMapper(cfg, v, nil)
+}
diff --git a/vendor/gopkg.in/yaml.v2/scannerc.go b/vendor/gopkg.in/yaml.v2/scannerc.go
index b33bdbaece..0b9bb6030a 100644
--- a/vendor/gopkg.in/yaml.v2/scannerc.go
+++ b/vendor/gopkg.in/yaml.v2/scannerc.go
@@ -626,32 +626,18 @@ func trace(args ...interface{}) func() {
func yaml_parser_fetch_more_tokens(parser *yaml_parser_t) bool {
// While we need more tokens to fetch, do it.
for {
- // Check if we really need to fetch more tokens.
- need_more_tokens := false
-
- if parser.tokens_head == len(parser.tokens) {
- // Queue is empty.
- need_more_tokens = true
- } else {
- // Check if any potential simple key may occupy the head position.
- for i := len(parser.simple_keys) - 1; i >= 0; i-- {
- simple_key := &parser.simple_keys[i]
- if simple_key.token_number < parser.tokens_parsed {
- break
- }
- if valid, ok := yaml_simple_key_is_valid(parser, simple_key); !ok {
- return false
- } else if valid && simple_key.token_number == parser.tokens_parsed {
- need_more_tokens = true
- break
- }
+ if parser.tokens_head != len(parser.tokens) {
+ // If queue is non-empty, check if any potential simple key may
+ // occupy the head position.
+ head_tok_idx, ok := parser.simple_keys_by_tok[parser.tokens_parsed]
+ if !ok {
+ break
+ } else if valid, ok := yaml_simple_key_is_valid(parser, &parser.simple_keys[head_tok_idx]); !ok {
+ return false
+ } else if !valid {
+ break
}
}
-
- // We are finished.
- if !need_more_tokens {
- break
- }
// Fetch the next token.
if !yaml_parser_fetch_next_token(parser) {
return false
@@ -883,6 +869,7 @@ func yaml_parser_save_simple_key(parser *yaml_parser_t) bool {
return false
}
parser.simple_keys[len(parser.simple_keys)-1] = simple_key
+ parser.simple_keys_by_tok[simple_key.token_number] = len(parser.simple_keys) - 1
}
return true
}
@@ -897,9 +884,10 @@ func yaml_parser_remove_simple_key(parser *yaml_parser_t) bool {
"while scanning a simple key", parser.simple_keys[i].mark,
"could not find expected ':'")
}
+ // Remove the key from the stack.
+ parser.simple_keys[i].possible = false
+ delete(parser.simple_keys_by_tok, parser.simple_keys[i].token_number)
}
- // Remove the key from the stack.
- parser.simple_keys[i].possible = false
return true
}
@@ -930,7 +918,9 @@ func yaml_parser_increase_flow_level(parser *yaml_parser_t) bool {
func yaml_parser_decrease_flow_level(parser *yaml_parser_t) bool {
if parser.flow_level > 0 {
parser.flow_level--
- parser.simple_keys = parser.simple_keys[:len(parser.simple_keys)-1]
+ last := len(parser.simple_keys) - 1
+ delete(parser.simple_keys_by_tok, parser.simple_keys[last].token_number)
+ parser.simple_keys = parser.simple_keys[:last]
}
return true
}
@@ -1007,6 +997,8 @@ func yaml_parser_fetch_stream_start(parser *yaml_parser_t) bool {
// Initialize the simple key stack.
parser.simple_keys = append(parser.simple_keys, yaml_simple_key_t{})
+ parser.simple_keys_by_tok = make(map[int]int)
+
// A simple key is allowed at the beginning of the stream.
parser.simple_key_allowed = true
@@ -1310,6 +1302,7 @@ func yaml_parser_fetch_value(parser *yaml_parser_t) bool {
// Remove the simple key.
simple_key.possible = false
+ delete(parser.simple_keys_by_tok, simple_key.token_number)
// A simple key cannot follow another simple key.
parser.simple_key_allowed = false
diff --git a/vendor/gopkg.in/yaml.v2/yamlh.go b/vendor/gopkg.in/yaml.v2/yamlh.go
index e25cee563b..f6a9c8e34b 100644
--- a/vendor/gopkg.in/yaml.v2/yamlh.go
+++ b/vendor/gopkg.in/yaml.v2/yamlh.go
@@ -579,6 +579,7 @@ type yaml_parser_t struct {
simple_key_allowed bool // May a simple key occur at the current position?
simple_keys []yaml_simple_key_t // The stack of simple keys.
+ simple_keys_by_tok map[int]int // possible simple_key indexes indexed by token_number
// Parser stuff
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 4bb9ee0c6d..1d1e98186e 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -147,6 +147,8 @@ github.com/insolar/go-actors/actor
github.com/insolar/go-actors/actor/errors
github.com/insolar/go-actors/actor/system
github.com/insolar/go-actors/actor/mailbox
+# github.com/insolar/insconfig v0.0.0-20200227134411-011eca6dc866
+github.com/insolar/insconfig
# github.com/insolar/rpc v1.2.2-0.20190812143745-c27e1d218f1f
github.com/insolar/rpc/v2
github.com/insolar/rpc/v2/json2
@@ -251,7 +253,7 @@ github.com/ory/dockertest/v3/docker/types/strslice
github.com/ory/dockertest/v3/docker/types/versions
# github.com/pelletier/go-toml v1.4.0
github.com/pelletier/go-toml
-# github.com/pkg/errors v0.8.1
+# github.com/pkg/errors v0.9.1
github.com/pkg/errors
# github.com/pmezard/go-difflib v1.0.0
github.com/pmezard/go-difflib/difflib
@@ -286,14 +288,16 @@ github.com/spf13/cast
github.com/spf13/cobra
# github.com/spf13/jwalterweatherman v1.1.0
github.com/spf13/jwalterweatherman
-# github.com/spf13/pflag v1.0.3
+# github.com/spf13/pflag v1.0.5
github.com/spf13/pflag
-# github.com/spf13/viper v1.4.0
+# github.com/spf13/viper v1.6.2
github.com/spf13/viper
# github.com/stretchr/testify v1.4.0
github.com/stretchr/testify/require
github.com/stretchr/testify/assert
github.com/stretchr/testify/suite
+# github.com/subosito/gotenv v1.2.0
+github.com/subosito/gotenv
# github.com/tylerb/gls v0.0.0-20150407001822-e606233f194d
github.com/tylerb/gls
# github.com/uber/jaeger-client-go v2.19.0+incompatible
@@ -449,5 +453,7 @@ google.golang.org/grpc/balancer/base
google.golang.org/grpc/credentials/internal
google.golang.org/grpc/binarylog/grpc_binarylog_v1
google.golang.org/grpc/internal/syscall
-# gopkg.in/yaml.v2 v2.2.7
+# gopkg.in/ini.v1 v1.51.0
+gopkg.in/ini.v1
+# gopkg.in/yaml.v2 v2.2.8
gopkg.in/yaml.v2
diff --git a/virtual/integration/main_test.go b/virtual/integration/main_test.go
index bfa7a2d0ff..841f226616 100644
--- a/virtual/integration/main_test.go
+++ b/virtual/integration/main_test.go
@@ -69,10 +69,10 @@ type Server struct {
ExternalPubSub, IncomingPubSub *gochannel.GoChannel
}
-func DefaultVMConfig() configuration.Configuration {
- cfg := configuration.Configuration{}
+func DefaultVMConfig() configuration.VirtualConfig {
+ cfg := configuration.VirtualConfig{}
cfg.KeysPath = "testdata/bootstrap_keys.json"
- cfg.Ledger.LightChainLimit = math.MaxInt32
+ cfg.LightChainLimit = math.MaxInt32
cfg.LogicRunner = configuration.NewLogicRunner()
cfg.Bus.ReplyTimeout = 5 * time.Second
cfg.Log = configuration.NewLog()
@@ -114,7 +114,7 @@ func init() {
func NewServer(
t *testing.T,
ctx context.Context,
- cfg configuration.Configuration,
+ cfg configuration.VirtualConfig,
receiveCallback func(meta payload.Meta, pl payload.Payload) []payload.Payload,
mManager machinesmanager.MachinesManager) (*Server, error) {
@@ -168,7 +168,7 @@ func NewServer(
Pulses = pulse.NewStorageMem()
Jets = jet.NewStore()
- Coordinator = jetcoordinator.NewJetCoordinator(cfg.Ledger.LightChainLimit, virtual.ref)
+ Coordinator = jetcoordinator.NewJetCoordinator(cfg.LightChainLimit, virtual.ref)
Coordinator.PulseCalculator = Pulses
Coordinator.PulseAccessor = Pulses
Coordinator.JetAccessor = Jets
@@ -200,7 +200,7 @@ func NewServer(
ExternalPubSub = pubsub
IncomingPubSub = pubsub
- c := jetcoordinator.NewJetCoordinator(cfg.Ledger.LightChainLimit, virtual.ref)
+ c := jetcoordinator.NewJetCoordinator(cfg.LightChainLimit, virtual.ref)
c.PulseCalculator = Pulses
c.PulseAccessor = Pulses
c.JetAccessor = Jets