yacl

package module
v0.0.0-...-3dbd443 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 5, 2024 License: MIT Imports: 10 Imported by: 5

README

YACL

Yet another config loader

features

  • overrides for multiple configurations (for example local, dev, deployment) by ordered names
  • configurable basedir (relative, absolute, homedir, config dir) and sub dirs
  • config migration support (you need to change the config structure?)
  • supports yaml and json by default. also together.
  • configurable behavior
    • parse a single config file
    • parse a couple files one after another (value override)
    • parse all files (they matching readers files extension) in the config folder and any subfolder
    • ... but exclude a list of folders ...
    • ... or exclude any foldername that s not matching a path-pattern...
    • parse all files in the config dir, but ignore subfolder
    • exclude files by regex match
    • case depending Init callback
      • config folder not exists
      • no config files
  • simple usage like an json.Marshall

Example

simple example

goal load a existing configuration that is stored as yaml file named config.yaml in the same directory as the executable.

config file config.yaml:
name: "bugs bunny"
age: 102
example code:
package main

import (
	"fmt"

	"github.com/swaros/contxt/module/yacl"
	"github.com/swaros/contxt/module/yamc"
)

type Config struct {
	Name string `yaml:"name"`
	Age  int    `yaml:"age"`
}

func main() {
	// create a new yacl instance
	config := Config{}
	cfgApp := yacl.New(
		&config,
		yamc.NewYamlReader(),
	)
	// load the config file. must be done before the linter can be used
	// in this case, the config is loaded from the current directory
	if err := cfgApp.LoadFile("config.yaml"); err != nil {
		panic(err)
	}
	// now any entry in the config file is mapped to the config struct
    // and we can use them
	if config.Age < 6 {
		panic("age must be greater than 5")
	}
	fmt.Println(" hello ", config.Name, ", age of  ", config.Age, " is correct?")
}
overwriting values

goal instead of loading the configuration from a single file, we want to load the configuration from a couple of files. the order of the files is important. the last file in the list will overwrite any value from the previous files.

main config file 01-main.yml:

the first configuraion file is named 01-main.yml and is located config folder. the config folder is located in the same directory as the executable.

this file contains the main configuration. it is the base for all other configurations.

for oure example, we assume that if the user is guest, then the user has no password. if the user is not guest, then the user has a password. so we do not set the password in the main config file.

authurl: company.com/auth
username: guest

now we want to overwrite the username and the password. we create a second file named 02-local.yml in the same folder as the 01-main.yml.

because it is in order after the 01-main.yml, the values in this file will overwrite the values from the 01-main.yml.

local config file 02-local.yml:
username: testuser
password: "ghhnj44582#%$^"
example code:
package main

import (
	"fmt"

	"github.com/swaros/contxt/module/yacl"
	"github.com/swaros/contxt/module/yamc"
)

type Config struct {
	AuthUrl  string `yaml:"authurl"`
	UserName string `yaml:"username"`
	Password string `yaml:"password"`
}

func main() {
	// create a new yacl instance
	config := Config{}
	cfgApp := yacl.New(
		&config,
		yamc.NewYamlReader(),
	)

	// define the subdirectory where the config files are located
	cfgApp.SetSubDirs("config")

	// load all config files from the config directory
	if err := cfgApp.Load(); err != nil {
		panic(err)
	}

	// just print the overwritten values
	fmt.Println(
		" connecting: ", config.AuthUrl,
		", user: ", config.UserName,
		", password: ", config.Password,
	)

}
short example

for any example, we assume that the config is created already like

config := Config{}
cfgApp := yacl.New(
   &config,
   yamc.NewYamlReader(), // yamc.NewJsonReader() for json
)
how to use a absolute path for the config file
cfgApp.SetFileAndPathsByFullFilePath("/etc/myapp/configuraion.json")

this is an shortcut for a couple of settings that ends up reading the file from the given path.

how to allow not existing config files
cfgApp.SetExpectNoConfigFiles()

now the loader will not complain if the config file does not exists. it will just do nothing.

how to use the home directory as base for the config file
cfgApp.UseHomeDir()

now the users home directory is used as base for the config file. the config file must be located in the home directory. if you like to have your config file in a subdirectory, you can use the SetSubDirs() function.

cfgApp.UseHomeDir().SetSubDirs(".config","myapp")
blacklist
cfgApp.SetSubDirs("data", "v2").
  SetFolderBlackList([]string{"data/v2/deploy", "data/v2/backup"})

here we use a blacklist to exclude the folders data/v2/deploy and data/v2/backup from the config file search.

regex

depends on lists, only blacklists supported. but we can use a regex to limit the folders that are searched for config files. like if we want to exclude all folders that are not matching the pattern _data/v2/.*_.

cfgApp.SetSubDirs("data", "v2").
  AllowSubdirsByRegex("_data/v2/.*_.)

Documentation

Overview

Copyright (c) 2022 Thomas Ziegler <thomas.zglr@googlemail.com>. All rights reserved.

Licensed under the MIT License

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Copyright (c) 2022 Thomas Ziegler <thomas.zglr@googlemail.com>. All rights reserved.

Licensed under the MIT License

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Index

Constants

View Source
const (
	PATH_UNSET            = 0
	PATH_HOME             = 1
	PATH_CONFIG           = 2
	PATH_ABSOLUTE         = 3
	ERROR_PATH_NOT_EXISTS = 101
	NO_CONFIG_FILES_FOUND = 102

	// Flags to get config entries
	ConfigUseSpecialDir    = 1
	ConfigAllowSubDirs     = 2
	ConfigExpectNoFiles    = 4
	ConfigAllowDirPattern  = 8
	ConfigFilesPattern     = 16
	ConfigTrackFiles       = 32
	ConfigDirBlackList     = 64
	ConfigSupportMigrate   = 128
	ConfigHaveCustomLoader = 256
)

Variables

This section is empty.

Functions

This section is empty.

Types

type ConfigModel

type ConfigModel struct {
	// contains filtered or unexported fields
}

func New

func New(structure any, read ...yamc.DataReader) *ConfigModel

New creates a New yacl ConfigModel with default properties

func (*ConfigModel) AllowSubdirs

func (c *ConfigModel) AllowSubdirs() *ConfigModel

AllowSubdirs enables scanning subdirectories to find configuration files

func (*ConfigModel) AllowSubdirsByRegex

func (c *ConfigModel) AllowSubdirsByRegex(regex string) *ConfigModel

AllowSubdirsByRegex same as AllowSubDirs but set a regex pattern to Whitelist folder names

func (*ConfigModel) CreateYamc

func (c *ConfigModel) CreateYamc(reader yamc.DataReader) (*yamc.Yamc, error)

CreateYamc creates a Yamc container. it has no caching because this is needed only for some content creation, like saving or parsing. so there is no need to keep them.

func (*ConfigModel) Empty

func (c *ConfigModel) Empty() *ConfigModel

Empty initialize the configuration without any configuration files loading.

func (*ConfigModel) GetAllParsedFiles

func (c *ConfigModel) GetAllParsedFiles() []string

GetAllParsedFiles returns all parsed configuration filenames

func (*ConfigModel) GetAsYmac

func (c *ConfigModel) GetAsYmac() (*yamc.Yamc, error)

GetAsYmac creates a Yamc map from the configuration. we use Json here as Reader

func (*ConfigModel) GetConfig

func (c *ConfigModel) GetConfig(what int) interface{}

GetConfig returns the value of the given config entry

func (*ConfigModel) GetConfigPath

func (c *ConfigModel) GetConfigPath() string

GetConfigPath compose the current used Configuration folder and returns them. anything what can go wrong will end up in a panic

func (*ConfigModel) GetFileContent

func (c *ConfigModel) GetFileContent(path string) ([]byte, error)

GetFileContent returns the file content of the given file path if trackFiles is not enabled, this will return an error

func (*ConfigModel) GetLastUsedReader

func (c *ConfigModel) GetLastUsedReader() yamc.DataReader

return the last used reader for loading the configuration this is nil, if no configuration was loaded

func (*ConfigModel) GetLoadedFile

func (c *ConfigModel) GetLoadedFile() string

GetLoadedFile returns the used configuration filename

func (*ConfigModel) GetValue

func (c *ConfigModel) GetValue(dotedPath string) (any, error)

GetValue parsing a string with dots, to use any part of them to build a route to a specific entry. This is a very basic path building, without any magic. so even a key with dots will be an issue. so the use case depends on the actual structure. Also DO NOT USE THIS FOR READING CONFIG VALUES. use the structure itself. this method is a simple helper for verify data while testing (for example)

func (*ConfigModel) Init

func (c *ConfigModel) Init(initFn func(strct *any), noConfigFn func(errCode int) error) *ConfigModel

Init sets the initialization Callbacks. initFn will be executed to initialize the configuration structure. can be nil noConfigFn is the callback for the cases, the configuration directory is not exists, there are no configurations files found

func (*ConfigModel) Load

func (c *ConfigModel) Load() error

Load start loading all configuration files depends the configured behavior.

func (*ConfigModel) LoadFile

func (c *ConfigModel) LoadFile(path string) error

LoadFile loads and parses a single configuration file. this can be called multiple times with different files. the content is merged (no deep copy, so no list merge for example)

func (*ConfigModel) NoSubdirs

func (c *ConfigModel) NoSubdirs() *ConfigModel

NoSubdirs disables scanning sub folders while looking for configuration files

func (*ConfigModel) Reset

func (c *ConfigModel) Reset()

Reset the configuration. this will clear the usedFile and loadedFiles. this is useful for testing

func (*ConfigModel) Save

func (c *ConfigModel) Save() error

Save is try to write the current configuration on disk. IF we successfully loaded content at least from one configuration file, the last one is used IF we have setup a SingleFile and do not have a usage while loading, then this will be used instead. anything else will report an error

func (*ConfigModel) SetCustomFileLoader

func (c *ConfigModel) SetCustomFileLoader(fn func(path string) ([]byte, error)) *ConfigModel

sets a custome file loader they will be used instead of the default file loader to load the configuration files and return the content as byte array. so some template engines can be used to load the configuration files

func (*ConfigModel) SetExpectNoConfigFiles

func (c *ConfigModel) SetExpectNoConfigFiles() *ConfigModel

SetExpectNoConfigFiles disable the behavior, not existing config files will be handled as error. this also means, it should just ignore this issue. so if this is enabled, it will also not reported to the noConfigFn that might be setup in the Init handler

func (*ConfigModel) SetFileAndPathsByFullFilePath

func (c *ConfigModel) SetFileAndPathsByFullFilePath(fullPath string) *ConfigModel

SetFileAndPathsByFullFilePath sets the file and the path to the file. so the file will be loaded and the path will be used to scan for sub directories. so this is the same as SetSingleFile and SetSubDirs but in one call.

func (*ConfigModel) SetFilePattern

func (c *ConfigModel) SetFilePattern(regex string) *ConfigModel

SetFilePattern defines a regex-pattern for any configuration file any file that is not matching, will be ignored.

func (*ConfigModel) SetFolderBlackList

func (c *ConfigModel) SetFolderBlackList(blackListedDirs []string) *ConfigModel

SetFolderBlackList defines a simple list of sub directories, they should being ignored, while looking for configuration files

func (*ConfigModel) SetSingleFile

func (c *ConfigModel) SetSingleFile(filename string) *ConfigModel

Limits looking for the configurations to one file (base) name. so do not add any path to filename argument. this is not equal to the usage of LoadFile, because if this is combined with scanning sub dirs, any configuration with this file basename will be accepted. if you like to load one specific file so use LoadFile instead. if you like more flexible, depending what files should load, define a regex-pattern and use SetFilePattern

func (*ConfigModel) SetSubDirs

func (c *ConfigModel) SetSubDirs(dirs ...string) *ConfigModel

add the names of the sub directories starting from the base directory. it will be set as string arguments. add any subdirectory separate as argument. do not add "this-dir/next-dir".

func (*ConfigModel) SetTrackFiles

func (c *ConfigModel) SetTrackFiles() *ConfigModel

SetTrackFiles enables the tracking of loaded files. so the file content will be stored in the ConfigModel and can be accessed by GetFileContent

func (*ConfigModel) SupportMigrate

func (c *ConfigModel) SupportMigrate(fileHandelFn func(path string, cfg interface{})) *ConfigModel

func (*ConfigModel) ToString

func (c *ConfigModel) ToString(reader yamc.DataReader) (string, error)

ToString converts the current configuration into a string, depending the submitted reader.

func (*ConfigModel) UseConfigDir

func (c *ConfigModel) UseConfigDir() *ConfigModel

UseConfigDir sets the default config dir as entrypoint (basedir)

func (*ConfigModel) UseHomeDir

func (c *ConfigModel) UseHomeDir() *ConfigModel

UseHomeDir sets the User Home-dir as entrypoint (basedir)

func (*ConfigModel) UseRelativeDir

func (c *ConfigModel) UseRelativeDir() *ConfigModel

UseRelativeDir is just defines no special path usage. mostly it means the current folder is used (relative) but depending on the usage of the lib, it can also still a absolute path.

Directories

Path Synopsis
example

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL