Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 6 additions & 7 deletions go/conclave.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (

core "dappco.re/go"
coreio "dappco.re/go/io"
coreerr "dappco.re/go/log"
)

// conclaveRootFn is swapped in by go-session or a similar session-scoped
Expand Down Expand Up @@ -58,14 +57,14 @@ func ForConclave(name string, opts ...Option) core.Result {

rootResult := resolver(name)
if !rootResult.OK {
return core.Fail(coreerr.E(callerForConclave, "failed to resolve conclave root: "+name, resultCause(rootResult).(error)))
return core.Fail(core.E(callerForConclave, "failed to resolve conclave root: "+name, resultCause(rootResult).(error)))
}
root := rootResult.Value.(string)
if root == "" {
return core.Fail(coreerr.E(callerForConclave, "failed to resolve conclave root: "+name, nil))
return core.Fail(core.E(callerForConclave, "failed to resolve conclave root: "+name, nil))
}
if isSymlinkedCoreDir(coreio.Local, core.Path(root, ".core")) {
return core.Fail(coreerr.E(callerForConclave, "symlinked conclave .core directory rejected: "+root, nil))
return core.Fail(core.E(callerForConclave, "symlinked conclave .core directory rejected: "+root, nil))
}

conclaveOpts := append([]Option{}, opts...)
Expand All @@ -77,13 +76,13 @@ func ForConclave(name string, opts ...Option) core.Result {
// the final fallback layer.
baseResult := Discover(opts...)
if !baseResult.OK {
return core.Fail(coreerr.E(callerForConclave, "failed to discover base config: "+name, resultCause(baseResult).(error)))
return core.Fail(core.E(callerForConclave, "failed to discover base config: "+name, resultCause(baseResult).(error)))
}
base := baseResult.Value.(*Config)

conclaveResult := New(conclaveOpts...)
if !conclaveResult.OK {
return core.Fail(coreerr.E(callerForConclave, "failed to load conclave config: "+name, resultCause(conclaveResult).(error)))
return core.Fail(core.E(callerForConclave, "failed to load conclave config: "+name, resultCause(conclaveResult).(error)))
}
conclaveCfg := conclaveResult.Value.(*Config)

Expand All @@ -94,7 +93,7 @@ func ForConclave(name string, opts ...Option) core.Result {

func defaultConclaveRoot(name string) core.Result {
if !isSafePathElement(name) {
return core.Fail(coreerr.E("config.defaultConclaveRoot", "invalid conclave name: "+name, nil))
return core.Fail(core.E("config.defaultConclaveRoot", "invalid conclave name: "+name, nil))
}
return core.Ok(core.Path(XDG().Config(), "conclaves", name))
}
47 changes: 23 additions & 24 deletions go/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import (

core "dappco.re/go"
coreio "dappco.re/go/io"
coreerr "dappco.re/go/log"
"github.com/spf13/viper"
"gopkg.in/yaml.v3"
)
Expand Down Expand Up @@ -206,7 +205,7 @@ func newConfig(loadFromPath bool, opts ...Option) core.Result {
if c.path == "" {
home := core.Env("DIR_HOME")
if home == "" {
return core.Fail(coreerr.E(callerConfigNew, "failed to determine home directory", nil))
return core.Fail(core.E(callerConfigNew, "failed to determine home directory", nil))
}
c.path = core.Path(home, ".core", "config.yaml")
}
Expand All @@ -216,12 +215,12 @@ func newConfig(loadFromPath bool, opts ...Option) core.Result {
// Load existing config file if it exists.
if loadFromPath && c.medium.Exists(c.path) {
if r := c.loadFile(c.medium, c.path, false); !r.OK {
return core.Fail(coreerr.E(callerConfigNew, "failed to load config file", resultCause(r).(error)))
return core.Fail(core.E(callerConfigNew, "failed to load config file", resultCause(r).(error)))
}
}
if loadFromPath {
if r := c.loadStoreState(); !r.OK {
return core.Fail(coreerr.E(callerConfigNew, "failed to load config store state", resultCause(r).(error)))
return core.Fail(core.E(callerConfigNew, "failed to load config store state", resultCause(r).(error)))
}
}

Expand All @@ -247,7 +246,7 @@ func configTypeForPath(path string) core.Result {
case ".env":
return core.Ok("env")
default:
return core.Fail(coreerr.E("config.configTypeForPath", "unsupported config file type: "+path, nil))
return core.Fail(core.E("config.configTypeForPath", "unsupported config file type: "+path, nil))
}
}

Expand Down Expand Up @@ -289,19 +288,19 @@ func (c *Config) loadFile(m coreio.Medium, path string, notify bool) core.Result
func readConfigSettings(m coreio.Medium, path string) core.Result {
configTypeResult := configTypeForPath(path)
if !configTypeResult.OK {
return core.Fail(coreerr.E(callerConfigLoadFile, "failed to determine config file type: "+path, resultCause(configTypeResult).(error)))
return core.Fail(core.E(callerConfigLoadFile, "failed to determine config file type: "+path, resultCause(configTypeResult).(error)))
}
configType := configTypeResult.Value.(string)

content, err := m.Read(path)
if err != nil {
return core.Fail(coreerr.E(callerConfigLoadFile, "failed to read config file: "+path, err))
return core.Fail(core.E(callerConfigLoadFile, "failed to read config file: "+path, err))
}

parsed := viper.New()
parsed.SetConfigType(configType)
if err := parsed.MergeConfig(core.NewReader(content)); err != nil {
return core.Fail(coreerr.E(callerConfigLoadFile, core.Sprintf("failed to parse config file: %s", path), err))
return core.Fail(core.E(callerConfigLoadFile, core.Sprintf("failed to parse config file: %s", path), err))
}

settings := parsed.AllSettings()
Expand All @@ -313,10 +312,10 @@ func readConfigSettings(m coreio.Medium, path string) core.Result {

func (c *Config) mergeConfigSettingsLocked(settings map[string]any) core.Result {
if err := c.file.MergeConfigMap(settings); err != nil {
return core.Fail(coreerr.E(callerConfigLoadFile, "failed to merge config into file settings", err))
return core.Fail(core.E(callerConfigLoadFile, "failed to merge config into file settings", err))
}
if err := c.full.MergeConfigMap(settings); err != nil {
return core.Fail(coreerr.E(callerConfigLoadFile, "failed to merge config into full settings", err))
return core.Fail(core.E(callerConfigLoadFile, "failed to merge config into full settings", err))
}
return core.Ok(nil)
}
Expand Down Expand Up @@ -358,17 +357,17 @@ func (c *Config) Get(key string, out any) core.Result {

if key == "" {
if err := c.full.Unmarshal(out); err != nil {
return core.Fail(coreerr.E(callerConfigGet, "failed to unmarshal full config", err))
return core.Fail(core.E(callerConfigGet, "failed to unmarshal full config", err))
}
return core.Ok(nil)
}

if !c.full.IsSet(key) {
return core.Fail(coreerr.E(callerConfigGet, core.Sprintf("key not found: %s", key), nil))
return core.Fail(core.E(callerConfigGet, core.Sprintf("key not found: %s", key), nil))
}

if err := c.full.UnmarshalKey(key, out); err != nil {
return core.Fail(coreerr.E(callerConfigGet, core.Sprintf("failed to unmarshal key: %s", key), err))
return core.Fail(core.E(callerConfigGet, core.Sprintf("failed to unmarshal key: %s", key), err))
}
return core.Ok(nil)
}
Expand Down Expand Up @@ -426,7 +425,7 @@ func (c *Config) Commit() core.Result {
c.mu.Unlock()

if r := Save(medium, path, settings); !r.OK {
return core.Fail(coreerr.E("config.Commit", "failed to save config", resultCause(r).(error)))
return core.Fail(core.E("config.Commit", "failed to save config", resultCause(r).(error)))
}
if attached != nil {
_ = attached.ACTION(ConfigChanged{Key: "", Value: nil, Source: configChangeSourceCommit})
Expand All @@ -441,7 +440,7 @@ func (c *Config) Commit() core.Result {
// (so CORE_CONFIG_DEV_EDITOR shows up as "dev.editor").
//
// for key, value := range cfg.All() {
// fmt.Println(key, value) // "dev.editor" "vim"
// core.Println(key, value) // "dev.editor" "vim"
// }
func (c *Config) All() iter.Seq2[string, any] {
c.mu.RLock()
Expand Down Expand Up @@ -607,7 +606,7 @@ func joinConfigPath(prefix, key string) string {
//
// cfg.OnChange(func(key string, value any) {
// if key == "dev.editor" {
// fmt.Println("editor changed to", value)
// core.Println("editor changed to", value)
// }
// })
func (c *Config) OnChange(fn func(key string, value any)) {
Expand All @@ -634,13 +633,13 @@ func Load(m coreio.Medium, path string) core.Result {
// dotenv sources are also supported by the RFC contract.
default:
if core.PathBase(path) != ".env" {
return core.Fail(coreerr.E(callerConfigLoad, unsupportedConfigFileType+": "+path, nil))
return core.Fail(core.E(callerConfigLoad, unsupportedConfigFileType+": "+path, nil))
}
}

content, err := m.Read(path)
if err != nil {
return core.Fail(coreerr.E(callerConfigLoad, "failed to read config file: "+path, err))
return core.Fail(core.E(callerConfigLoad, "failed to read config file: "+path, err))
}

v := viper.New()
Expand All @@ -651,7 +650,7 @@ func Load(m coreio.Medium, path string) core.Result {
v.SetConfigType("yaml")
}
if err := v.ReadConfig(core.NewReader(content)); err != nil {
return core.Fail(coreerr.E(callerConfigLoad, "failed to parse config file: "+path, err))
return core.Fail(core.E(callerConfigLoad, "failed to parse config file: "+path, err))
}

return core.Ok(v.AllSettings())
Expand All @@ -667,7 +666,7 @@ func Save(m coreio.Medium, path string, data map[string]any) core.Result {
case "", ".yaml", ".yml":
// These paths are safe to treat as YAML destinations.
default:
return core.Fail(coreerr.E(callerConfigSave, unsupportedConfigFileType+": "+path, nil))
return core.Fail(core.E(callerConfigSave, unsupportedConfigFileType+": "+path, nil))
}

payload := make(map[string]any, len(data)+1)
Expand All @@ -679,16 +678,16 @@ func Save(m coreio.Medium, path string, data map[string]any) core.Result {

out, err := yaml.Marshal(payload)
if err != nil {
return core.Fail(coreerr.E(callerConfigSave, "failed to marshal config", err))
return core.Fail(core.E(callerConfigSave, "failed to marshal config", err))
}

dir := core.PathDir(path)
if err := m.EnsureDir(dir); err != nil {
return core.Fail(coreerr.E(callerConfigSave, "failed to create config directory: "+dir, err))
return core.Fail(core.E(callerConfigSave, "failed to create config directory: "+dir, err))
}

if err := m.WriteMode(path, string(out), 0600); err != nil {
return core.Fail(coreerr.E(callerConfigSave, "failed to write config file: "+path, err))
return core.Fail(core.E(callerConfigSave, "failed to write config file: "+path, err))
}

return core.Ok(nil)
Expand All @@ -711,7 +710,7 @@ func (c *Config) loadStoreState() core.Result {

entries, err := reader.GetAll("config")
if err != nil {
return core.Fail(coreerr.E("config.loadStoreState", "failed to read config entries from store", err))
return core.Fail(core.E("config.loadStoreState", "failed to read config entries from store", err))
}

for key, raw := range entries {
Expand Down
9 changes: 4 additions & 5 deletions go/discover.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package config
import (
core "dappco.re/go"
coreio "dappco.re/go/io"
coreerr "dappco.re/go/log"
)

const callerDiscoverFrom = "config.DiscoverFrom"
Expand All @@ -18,7 +17,7 @@ const callerDiscoverFrom = "config.DiscoverFrom"
func Discover(opts ...Option) core.Result {
r := core.Getwd()
if !r.OK {
return core.Fail(coreerr.E("config.Discover", "failed to read working directory", resultCause(r).(error)))
return core.Fail(core.E("config.Discover", "failed to read working directory", resultCause(r).(error)))
}
return DiscoverFrom(r.Value.(string), opts...)
}
Expand All @@ -30,7 +29,7 @@ func Discover(opts ...Option) core.Result {
func DiscoverFrom(start string, opts ...Option) core.Result {
baseResult := newConfig(false, opts...)
if !baseResult.OK {
return core.Fail(coreerr.E(callerDiscoverFrom, "failed to initialise base config", resultCause(baseResult).(error)))
return core.Fail(core.E(callerDiscoverFrom, "failed to initialise base config", resultCause(baseResult).(error)))
}
base := baseResult.Value.(*Config)
medium := base.medium
Expand All @@ -49,13 +48,13 @@ func DiscoverFrom(start string, opts ...Option) core.Result {
}
layerResult := New(layerOpts...)
if !layerResult.OK {
return core.Fail(coreerr.E(callerDiscoverFrom, "failed to load discovered config: "+p, resultCause(layerResult).(error)))
return core.Fail(core.E(callerDiscoverFrom, "failed to load discovered config: "+p, resultCause(layerResult).(error)))
}
layer := layerResult.Value.(*Config)
base.MergeFrom(layer)
}
if r := base.loadStoreState(); !r.OK {
return core.Fail(coreerr.E(callerDiscoverFrom, "failed to load config store state", resultCause(r).(error)))
return core.Fail(core.E(callerDiscoverFrom, "failed to load config store state", resultCause(r).(error)))
}

return core.Ok(base)
Expand Down
2 changes: 1 addition & 1 deletion go/feature.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@
// registry. Environment overrides are not included in the returned slice.
//
// for _, flag := range config.Features() {
// fmt.Println(flag)
// core.Println(flag)
// }
func Features() []string {
featureMu.RLock()
Expand Down Expand Up @@ -142,7 +142,7 @@

// resetFeatureRegistry clears process-level feature state. Test-only helper;
// the exported Feature/SetFeature API is the public contract.
func resetFeatureRegistry() {

Check failure on line 145 in go/feature.go

View workflow job for this annotation

GitHub Actions / golangci-lint

func resetFeatureRegistry is unused (unused)

Check failure on line 145 in go/feature.go

View workflow job for this annotation

GitHub Actions / golangci-lint

func resetFeatureRegistry is unused (unused)
featureMu.Lock()
defer featureMu.Unlock()
featureDefault = &featureRegistry{values: map[string]bool{}}
Expand Down
21 changes: 10 additions & 11 deletions go/images_manifest.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (

core "dappco.re/go"
coreio "dappco.re/go/io"
coreerr "dappco.re/go/log"
"github.com/xeipuuv/gojsonschema"
)

Expand Down Expand Up @@ -70,18 +69,18 @@ func LoadImagesManifest(medium coreio.Medium, path string) core.Result {
if core.Is(err, fs.ErrNotExist) {
return core.Ok(manifest)
}
return core.Fail(coreerr.E(callerLoadImagesManifest, "failed to read images manifest: "+path, err))
return core.Fail(core.E(callerLoadImagesManifest, "failed to read images manifest: "+path, err))
}

var raw map[string]any
if r := core.JSONUnmarshalString(content, &raw); !r.OK {
return core.Fail(coreerr.E(callerLoadImagesManifest, "failed to parse images manifest: "+path, resultCause(r).(error)))
return core.Fail(core.E(callerLoadImagesManifest, "failed to parse images manifest: "+path, resultCause(r).(error)))
}
if r := validateImagesSchema(path, raw); !r.OK {
return r
}
if r := core.JSONUnmarshalString(content, manifest); !r.OK {
return core.Fail(coreerr.E(callerLoadImagesManifest, "failed to decode images manifest: "+path, resultCause(r).(error)))
return core.Fail(core.E(callerLoadImagesManifest, "failed to decode images manifest: "+path, resultCause(r).(error)))
}
if manifest.Images == nil {
manifest.Images = map[string]ImageInfo{}
Expand All @@ -103,16 +102,16 @@ func SaveImagesManifest(medium coreio.Medium, path string, manifest *ImagesManif

payloadResult := core.JSONMarshal(manifest)
if !payloadResult.OK {
return core.Fail(coreerr.E(callerSaveImagesManifest, "failed to marshal images manifest", resultCause(payloadResult).(error)))
return core.Fail(core.E(callerSaveImagesManifest, "failed to marshal images manifest", resultCause(payloadResult).(error)))
}
payload := payloadResult.Value.([]byte)

dir := core.PathDir(path)
if err := medium.EnsureDir(dir); err != nil {
return core.Fail(coreerr.E(callerSaveImagesManifest, "failed to create images manifest directory: "+dir, err))
return core.Fail(core.E(callerSaveImagesManifest, "failed to create images manifest directory: "+dir, err))
}
if err := medium.WriteMode(path, string(payload), 0o600); err != nil {
return core.Fail(coreerr.E(callerSaveImagesManifest, "failed to write images manifest: "+path, err))
return core.Fail(core.E(callerSaveImagesManifest, "failed to write images manifest: "+path, err))
}
return core.Ok(nil)
}
Expand All @@ -124,12 +123,12 @@ func validateImagesSchema(path string, raw map[string]any) core.Result {

schemaBody, err := schemaFS.ReadFile("schema/images.schema.json")
if err != nil {
return core.Fail(coreerr.E(callerValidateImagesSchema, "failed to read embedded schema: schema/images.schema.json", err))
return core.Fail(core.E(callerValidateImagesSchema, "failed to read embedded schema: schema/images.schema.json", err))
}

documentResult := core.JSONMarshal(raw)
if !documentResult.OK {
return core.Fail(coreerr.E(callerValidateImagesSchema, "failed to encode images manifest for schema validation: "+path, resultCause(documentResult).(error)))
return core.Fail(core.E(callerValidateImagesSchema, "failed to encode images manifest for schema validation: "+path, resultCause(documentResult).(error)))
}
documentBody := documentResult.Value.([]byte)

Expand All @@ -138,7 +137,7 @@ func validateImagesSchema(path string, raw map[string]any) core.Result {
gojsonschema.NewBytesLoader(documentBody),
)
if err != nil {
return core.Fail(coreerr.E(callerValidateImagesSchema, "schema validation failed: "+path, err))
return core.Fail(core.E(callerValidateImagesSchema, "schema validation failed: "+path, err))
}
if result.Valid() {
return core.Ok(nil)
Expand All @@ -148,5 +147,5 @@ func validateImagesSchema(path string, raw map[string]any) core.Result {
for _, issue := range result.Errors() {
problems = append(problems, issue.String())
}
return core.Fail(coreerr.E(callerValidateImagesSchema, "schema validation failed: "+path+": "+core.Join("; ", problems...), nil))
return core.Fail(core.E(callerValidateImagesSchema, "schema validation failed: "+path+": "+core.Join("; ", problems...), nil))
}
Loading
Loading