diff options
author | Flu0r1ne <flur01ne@flu0r1ne.net> | 2021-08-03 02:02:40 -0500 |
---|---|---|
committer | Flu0r1ne <flur01ne@flu0r1ne.net> | 2021-08-03 02:02:40 -0500 |
commit | a0b020a78eb0b33965c59460fc093c6959216e44 (patch) | |
tree | 3b2722388ea6b312e927b6066b0831524ba4ed6b /config.go | |
download | deb-planr-a0b020a78eb0b33965c59460fc093c6959216e44.tar.xz deb-planr-a0b020a78eb0b33965c59460fc093c6959216e44.zip |
Initial commit with basic build structure
Diffstat (limited to 'config.go')
-rw-r--r-- | config.go | 172 |
1 files changed, 172 insertions, 0 deletions
diff --git a/config.go b/config.go new file mode 100644 index 0000000..6dd264b --- /dev/null +++ b/config.go @@ -0,0 +1,172 @@ +package planr + +import ( + // "fmt" + "log" + "github.com/BurntSushi/toml" +) + + +/* + TODO: Every property defined within the defaults currently + has to implement the "inherit" method to conditionally inherit a + property in relation to a parent. (Ostensibly so that test cases + can override default configuration.) This is pedantic because + most properties will end up writing boilerplate amounting to: + + parent.inherit() + ... + if config.property == nil { + config.property = config.parent.property + } + + This library provides copying behavior between structs + with common properties using reflection. It seems like + a slight abuse of reflection... But, it could be + retro-fitted to implement this behavior if a "onlyCopyZeroFields" + option was provided. + + > "github.com/jinzhu/copier" +*/ + +// Inheritable configuration can inherit properties defined in a +// defaults file. This happens on a per-directory basis so multiple +// tests can share common configuration. +// +// The parent will always be of the same type as the child and an +// assertion is required to define the proper behavior. +type InheritableConfig interface { + Inherit(parent interface{}) +} + +// A parser function takes a blob of TOML and decodes it into +// configuration relevant to an adapter +type TomlParser func (toml.Primitive) InheritableConfig + +// The name under which an adapter registers corresponds +// to a table under the super-table adapters. All corresponding +// TOML will be passed to the ParseConfig method or ParseDefaultConfig +// for parsing. The ParseConfig file parses options in test case files. +// The ParseDefaultConfig is parsed by `defaults.toml` files and can +// be used to establish default configuration that will be inherited +// by all units in a common directory (collection) +type AdapterConfig struct { + Name string + ParseConfig TomlParser + ParseDefaultConfig TomlParser +} + +// Program-wide configuration which is recognized +// in defaults.toml +type Defaults struct { + Points *float32 + + /* + The TOML library only parses exported fields. + The Adapters field is an intermediate mapping + individual adapters to their locally defined + configuration. After they individually process + the configuration, it is mapped to the adapters_ + field. + + See: decodeAdapters() + */ + Adapters *map[string] toml.Primitive + adapters_ map[string] InheritableConfig + + /* + The configs_ field is necessary to property + implement the Inherit method using a common + interface. + */ + configs_ *[]AdapterConfig +} + +// Program-wide testcase config +type TestCaseConfig struct { + Defaults + Title *string + Description *string +} + +// The default configuration must be able in inherit from +// other defaults further up the tree +// +// This provides multiple levels of configurability +func (child *Defaults) Inherit(p interface{}) { + parent := p.(Defaults) + + // Inherit properties which haven't been configured + if child.Points == nil { + child.Points = parent.Points; + } + + // Call the inherit method as defined by the adapters + // If an adapter is undefined, inherit the parent configuration + // + // _configs represents all adapters (registered to a runner) + for _, adapter := range *child.configs_ { + parent_adapter, parent_exists := parent.adapters_[adapter.Name] + child_adapter, child_exists := child.adapters_[adapter.Name] + + if parent_exists { + if child_exists { + child_adapter.Inherit(parent_adapter) + } else { + child.adapters_[adapter.Name] = parent_adapter + } + } + } +} + +// Parses the intermediate adapters Adapters containing TOML primitives +// according to methods registered with the runner +// Once parsed, they are stored alongside the registered name to determine +// which adapter will receive the configuration +func (defaults *Defaults) decodeAdapters(adapters []AdapterConfig, asDefault bool) { + defaults.configs_ = &adapters + defaults.adapters_ = make(map[string]InheritableConfig) + + if defaults.Adapters != nil { + for _, config := range adapters { + primitive, exists := (*defaults.Adapters)[config.Name] + + if exists { + var parsed InheritableConfig + if asDefault { + parsed = config.ParseDefaultConfig(primitive) + } else { + parsed = config.ParseConfig(primitive) + } + + defaults.adapters_[config.Name] = parsed + } + } + } +} + +// Decode defaults.toml +func DecodeDefaults(path string, adapterCfg []AdapterConfig) Defaults { + defaults := Defaults { } + + if _, err := toml.DecodeFile(path, &defaults); err != nil { + log.Fatal(err) + } + + defaults.decodeAdapters(adapterCfg, true) + + return defaults +} + +// Decode an individual unit +func DecodeConfig(path string, adapterCfg []AdapterConfig) TestCaseConfig { + config := TestCaseConfig { } + + if _, err := toml.DecodeFile(path, &config); err != nil { + log.Fatal(err) + } + + config.decodeAdapters(adapterCfg, false) + + return config +} |