120 lines
4.3 KiB
Go
120 lines
4.3 KiB
Go
package consumers
|
|
|
|
import (
|
|
"embed"
|
|
"errors"
|
|
"io/fs"
|
|
"path"
|
|
|
|
configkit "gitea.maximumdirect.net/eric/ConfigKit"
|
|
)
|
|
|
|
//go:embed testdata/native-source testdata/layered-bundle testdata/collection-bundle testdata/ordinary-imports testdata/source-version
|
|
var bundledFiles embed.FS
|
|
|
|
// BundledConfig is a small configuration loaded directly from an embedded file.
|
|
type BundledConfig struct {
|
|
Name string `yaml:"name"`
|
|
Enabled bool `yaml:"enabled"`
|
|
}
|
|
|
|
type PromptBundleConfig struct {
|
|
Name string `yaml:"name"`
|
|
Version string `yaml:"version"`
|
|
Description string `yaml:"description"`
|
|
Prompts map[string]BundlePrompt `yaml:"prompts"`
|
|
}
|
|
|
|
type BundlePrompt struct {
|
|
Summary string `yaml:"summary"`
|
|
}
|
|
|
|
// LoadPromptBundle demonstrates ordinary Load with opt-in imports whose
|
|
// destinations are declared relative to the entry document.
|
|
func LoadPromptBundle() (*configkit.Result[PromptBundleConfig], error) {
|
|
files, err := fs.Sub(bundledFiles, "testdata/ordinary-imports")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return configkit.Load[PromptBundleConfig](
|
|
configkit.NewFilesystem("prompt bundle", files).File("config.yml"),
|
|
configkit.Options[PromptBundleConfig]{Imports: true},
|
|
)
|
|
}
|
|
|
|
// LoadBundled demonstrates a native filesystem source without layered options.
|
|
func LoadBundled() (*configkit.Result[BundledConfig], error) {
|
|
files, err := fs.Sub(bundledFiles, "testdata/native-source")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return configkit.Load[BundledConfig](configkit.NewFilesystem("bundled", files).File("config.yml"))
|
|
}
|
|
|
|
// CatalogConfig keeps resource names and domain rules in the application.
|
|
type CatalogConfig struct {
|
|
Mode string `yaml:"mode"`
|
|
Enabled bool `yaml:"enabled"`
|
|
Workers int `yaml:"workers"`
|
|
Templates map[string]string `yaml:"templates"`
|
|
Labels map[string]string `yaml:"labels"`
|
|
}
|
|
|
|
// LoadCatalog combines two underlay tiers beneath an independently located
|
|
// host main file. ConfigKit assembles and validates the complete result once.
|
|
func LoadCatalog(mainPath string) (*configkit.Result[CatalogConfig], error) {
|
|
files, err := fs.Sub(bundledFiles, "testdata/layered-bundle")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
bundle := configkit.NewFilesystem("catalog bundle", files)
|
|
return configkit.LoadLayered(configkit.Input{Source: configkit.File(mainPath)},
|
|
configkit.LayeredOptions[CatalogConfig]{
|
|
Underlays: []configkit.Underlay{
|
|
{Inputs: []configkit.Input{{Source: bundle.File("defaults/config.yml"), Imports: true}}},
|
|
{Inputs: []configkit.Input{{Source: configkit.Mapping("local policy", map[string]any{
|
|
"workers": 2,
|
|
"labels": map[string]any{"tenant": "example"},
|
|
})}}},
|
|
},
|
|
Definition: configkit.Definition[CatalogConfig]{
|
|
Defaults: func() CatalogConfig { return CatalogConfig{Mode: "demo"} },
|
|
Validate: validateCatalog,
|
|
},
|
|
})
|
|
}
|
|
|
|
func validateCatalog(configuration *CatalogConfig, validation *configkit.Validation) {
|
|
if configuration.Mode != "demo" && configuration.Mode != "production" {
|
|
validation.Error(configkit.Keys("mode"), "must be demo or production")
|
|
}
|
|
if configuration.Workers < 0 {
|
|
validation.Error(configkit.Keys("workers"), "must be nonnegative")
|
|
}
|
|
if name := configuration.Templates["welcome"]; name == "." || !fs.ValidPath(name) {
|
|
validation.Error(configkit.Keys("templates", "welcome"), "must be a relative resource name")
|
|
}
|
|
}
|
|
|
|
// ReadWelcome follows the effective template field's one declaring source to
|
|
// its retained resource context. Opening and interpreting the resource remain
|
|
// application work; this does not reopen configuration or change metadata.
|
|
func ReadWelcome(result *configkit.Result[CatalogConfig]) (string, error) {
|
|
if result == nil {
|
|
return "", errors.New("catalog result is nil")
|
|
}
|
|
info, found := result.Metadata().Lookup(configkit.Keys("templates", "welcome"))
|
|
if !found || len(info.Origin.Locations) != 1 {
|
|
return "", errors.New("welcome template has no single declaring source")
|
|
}
|
|
context, found := result.SourceContext(info.Origin.Locations[0].SourceID)
|
|
if !found {
|
|
return "", errors.New("welcome template has no resource context")
|
|
}
|
|
data, err := fs.ReadFile(context.FS, path.Join(context.BaseDir, result.Config.Templates["welcome"]))
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return string(data), nil
|
|
}
|