MCPcopy Index your code
hub / github.com/BoRuDar/configuration

github.com/BoRuDar/configuration @v5.0.1

Chat with this repo
repository ↗ · DeepWiki ↗ · release v5.0.1 ↗ · + Follow
139 symbols 415 edges 17 files 26 documented · 19%
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

Go Report Card codecov OpenSSF Best Practices GoDoc Mentioned in Awesome Go

Configuration

is a library for injecting values recursively into structs - a convenient way of setting up a configuration object. Available features: - setting default values for struct fields - NewDefaultProvider() - setting values from environment variables - NewEnvProvider() - setting values from command line flags - NewFlagProvider() - setting values from a JSON file - NewJSONFileProvider("./testdata/input.json")

Supported types:

  • string, *string, []string, []*string
  • bool, *bool, []bool, []*bool
  • int, int8, int16, int32, int64 + slices of these types
  • *int, *int8, *int16, *int32, *int64 + slices of these types
  • uint, uint8, uint16, uint32, uint64 + slices of these types
  • *uint, *uint8, *uint16, *uint32, *uint64 + slices of these types
  • float32, float64 + slices of these types
  • *float32, *float64 + slices of these types
  • time.Duration from strings like 12ms, 2s etc.
  • embedded structs and pointers to structs
  • any custom type which satisfies FieldSetter interface

Why?

  • your entire configuration can be defined in one model
  • all metadata is in your model (defined with tags)
  • easy to set/change a source of data for your configuration
  • easy to set a priority of sources to fetch data from (e.g., 1.flags, 2.env, 3.default or another order)
  • you can implement your custom provider
  • no external dependencies
  • complies with 12-factor app

Quick start

Import path github.com/BoRuDar/configuration/v5

// defining a struct
type Conf struct {
    Name     string `flag:"name"`
    LastName string `default:"defaultLastName"`
    Age      byte   `env:"AGE_ENV"               default:"-1"`
    BoolPtr  *bool  `default:"false"`
    ObjPtr   *struct {
        F32       float32       `default:"32"`
        StrPtr    *string       `default:"str_ptr_test"`
        HundredMS time.Duration `default:"100ms"` // nolint:stylecheck
    }
    Obj struct {
        IntPtr     *int16   `default:"123"`
        Beta       int      `file_json:"inside.beta"   default:"24"`
        StrSlice   []string `default:"one;two"`
        IntSlice   []int64  `default:"3; 4"`
        unexported string   // ignored
    }
    URLs   []*string `default:"http://localhost:3000;1.2.3.4:8080"`
    HostIP ipTest    `default:"127.0.0.3"`
}

cfg, err := New[Conf](  // specify the [T] of the structure to be returned
    // order of execution will be preserved:
    NewFlagProvider(),             // 1st
    NewEnvProvider(),              // 2nd
    NewJSONFileProvider(fileName), // 3rd
    NewDefaultProvider(),          // 4th
)
if err != nil {
    t.Fatalf("unexpected error: %v", err)
}

If you need only ENV variables and default values you can use a shorter form:

cfg, err := configuration.FromEnvAndDefault[T]()

Providers

You can specify one or more providers. They will be executed in order of definition:

[]Provider{
    NewFlagProvider(),     // 1
    NewEnvProvider(),      // 2
    NewDefaultProvider(),  // 3
} 

IMPORTANT: If provider sets value successfully next ones will NOT be executed (if flag provider from the sample above finds the value - then the env and default providers are skipped). The value of the first successfully executed provider will be set. If none of providers can set value - an error will be returned.

Custom provider

You can define a custom provider which should satisfy this interface:

type Provider interface {
    Name() string
    Tag() string
    Init(ptr any) error
    Provide(field reflect.StructField, v reflect.Value) error
}

Default provider

Looks for default tag and set value from it:

struct {
    // ...
    Name string `default:"defaultName"`
    // ...
}

So Name will be set to "defaultName".

Env provider

Looks for env tag and tries to find an ENV variable with the name from the tag (AGE in this example):

struct {
    // ...
    Age      byte   `env:"AGE"`
    // ...
}

Name inside tag env:"<name>" must be unique for each field. Only strings in UPPER register for ENV vars are accepted:

bad_env_var_name=bad
Also_Bad_Env_Var_Name=bad
GOOD_ENV_VAR_NAME=good

Flag provider

Looks for flag tag and tries to set the value from the command line flag -first_name

struct {
    // ...
    Name     string `flag:"first_name|default_value|Description"`
    // ...
}

Name inside tag flag:"<name>" must be unique for each field. default_value and description sections are optional and may be omitted.

Note: if program is executed with -help or -h flag you will see all available flags with description:

Flags: 
    -first_name     "Description (default: default_value)"

And program execution will be terminated.

Options for NewFlagProvider

  • WithFlagSet(s FlagSet) - sets a custom FlagSet

JSON File provider

Requires file_json:"<path_to_json_field>" tag.

NewJSONFileProvider("./testdata/input.json")

For example, tag file_json:"cache.retention" will assume that you have this structure of your JSON file:

{
  "cache": {
    "retention": 1
  }
}

Additional providers

FieldSetter interface

You can define how to set fields with any custom types:

type FieldSetter interface {
    SetField(field reflect.StructField, val reflect.Value, valStr string) error
}

Example:

type ipTest net.IP

func (it *ipTest) SetField(_ reflect.StructField, val reflect.Value, valStr string) error {
    i := ipTest(net.ParseIP(valStr))

    if val.Kind() == reflect.Pointer {
        val.Set(reflect.ValueOf(&i))
    } else {
        val.Set(reflect.ValueOf(i))
    }

    return nil
}

Contribution

  1. Open a feature request or a bug report in issues
  2. Fork and create a PR into dev branch

Extension points exported contracts — how you extend this code

Provider (Interface)
Provider defines interface for existing and future custom providers. [5 implementers]
provider.go
FlagSet (Interface)
FlagSet is the part of flag.FlagSet that NewFlagProvider uses [1 implementers]
flagProvider.go
FieldSetter (Interface)
FieldSetter interface
fieldSetter.go
FlagProviderOption (FuncType)
(no doc)
flagProvider.go

Core symbols most depended-on inside this repo

String
called by 20
flagProvider.go
setPtrValue
called by 17
fieldSetter.go
setValue
called by 16
fieldSetter.go
NewDefaultProvider
called by 15
defaultProvider.go
Provide
called by 14
provider.go
NewFlagProvider
called by 12
flagProvider.go
Init
called by 9
provider.go
NewJSONFileProvider
called by 7
jsonProvider.go

Shape

Function 74
Method 37
Struct 22
Interface 3
TypeAlias 2
FuncType 1

Languages

Go100%

Modules by API surface

fieldStetter_test.go28 symbols
configurator_test.go26 symbols
flagProvider.go15 symbols
flagProvider_test.go12 symbols
fieldSetter.go9 symbols
jsonProvider_test.go8 symbols
jsonProvider.go7 symbols
envProvider.go6 symbols
defaultProvider.go6 symbols
configurator.go6 symbols
provider.go5 symbols
envProvider_test.go4 symbols

For agents

$ claude mcp add configuration \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact