From 258f7a0d7d74407195149859c5ff8b3d0a7b67ed Mon Sep 17 00:00:00 2001 From: jdkato Date: Sat, 25 Nov 2023 20:06:34 -0800 Subject: [PATCH] feat: config I/O --- cmd/vale/api.go | 2 +- cmd/vale/command.go | 60 +++++++++++++++++++++++++++++++++-------- cmd/vale/info.go | 2 ++ cmd/vale/main.go | 2 +- internal/core/ini.go | 26 +++++++++--------- internal/core/source.go | 26 ++++++++++-------- 6 files changed, 81 insertions(+), 37 deletions(-) diff --git a/cmd/vale/api.go b/cmd/vale/api.go index da6824aa..9935ec61 100644 --- a/cmd/vale/api.go +++ b/cmd/vale/api.go @@ -84,7 +84,7 @@ func fetch(src, dst string) error { } func install(args []string, flags *core.CLIFlags) error { - cfg, err := core.ReadPipeline("ini", flags, false) + cfg, _, err := core.ReadPipeline("ini", flags, false) if err != nil { return err } diff --git a/cmd/vale/command.go b/cmd/vale/command.go index 737632bd..7675edab 100644 --- a/cmd/vale/command.go +++ b/cmd/vale/command.go @@ -1,6 +1,7 @@ package main import ( + "bytes" "errors" "fmt" "os" @@ -36,14 +37,16 @@ var commandInfo = map[string]string{ // Actions are the available CLI commands. var Actions = map[string]func(args []string, flags *core.CLIFlags) error{ - "ls-config": printConfig, - "ls-metrics": printMetrics, - "dc": printConfig, - "tag": runTag, - "compile": compileRule, - "run": runRule, - "sync": sync, - "fix": fix, + "ls-config": printConfig, + "ls-metrics": printMetrics, + "get-config": getConfig, + "write-config": writeConfig, + "dc": printConfig, + "tag": runTag, + "compile": compileRule, + "run": runRule, + "sync": sync, + "fix": fix, } func fix(args []string, flags *core.CLIFlags) error { @@ -60,7 +63,7 @@ func fix(args []string, flags *core.CLIFlags) error { alert = string(b) } - cfg, err := core.ReadPipeline("ini", flags, false) + cfg, _, err := core.ReadPipeline("ini", flags, false) if err != nil { return err } @@ -74,7 +77,7 @@ func fix(args []string, flags *core.CLIFlags) error { } func sync(_ []string, flags *core.CLIFlags) error { - cfg, err := core.ReadPipeline("ini", flags, true) + cfg, _, err := core.ReadPipeline("ini", flags, true) if err != nil { return err } else if err = initPath(cfg); err != nil { @@ -107,7 +110,7 @@ func sync(_ []string, flags *core.CLIFlags) error { } func printConfig(_ []string, flags *core.CLIFlags) error { - cfg, err := core.ReadPipeline("ini", flags, false) + cfg, _, err := core.ReadPipeline("ini", flags, false) if err != nil { return err } @@ -115,6 +118,41 @@ func printConfig(_ []string, flags *core.CLIFlags) error { return nil } +func getConfig(_ []string, flags *core.CLIFlags) error { + var out bytes.Buffer + + _, sourced, err := core.ReadPipeline("ini", flags, false) + if err != nil { + return err + } + + // Remove empty sections. + for _, section := range sourced.Sections() { + if len(section.Keys()) == 0 { + sourced.DeleteSection(section.Name()) + } + } + + if _, err = sourced.WriteTo(&out); err != nil { + return err + } + + return printJSON(out.String()) +} + +func writeConfig(ini []string, flags *core.CLIFlags) error { + cfg, _, err := core.ReadPipeline("ini", flags, false) + if err != nil { + return err + } + + if len(ini) == 0 { + return errors.New("no data provided") + } + + return os.WriteFile(cfg.RootINI, []byte(ini[0]), os.ModePerm) +} + func printMetrics(args []string, _ *core.CLIFlags) error { if len(args) != 1 { return core.NewE100("ls-metrics", errors.New("one argument expected")) diff --git a/cmd/vale/info.go b/cmd/vale/info.go index e08d4826..be6c8b6e 100644 --- a/cmd/vale/info.go +++ b/cmd/vale/info.go @@ -64,6 +64,8 @@ var hidden = []string{ "compile", "run", "fix", + "get-config", + "write-config", } // PrintIntro shows basic usage / getting started info. diff --git a/cmd/vale/main.go b/cmd/vale/main.go index 54946cfa..b24e1682 100755 --- a/cmd/vale/main.go +++ b/cmd/vale/main.go @@ -105,7 +105,7 @@ func main() { } } - config, err := core.ReadPipeline("ini", &Flags, false) + config, _, err := core.ReadPipeline("ini", &Flags, false) if err != nil { handleError(err) } diff --git a/internal/core/ini.go b/internal/core/ini.go index be61d880..f878e408 100644 --- a/internal/core/ini.go +++ b/internal/core/ini.go @@ -161,13 +161,13 @@ func shadowLoad(source interface{}, others ...interface{}) (*ini.File, error) { SpaceBeforeInlineComment: true}, source, others...) } -func loadINI(cfg *Config, dry bool) error { +func loadINI(cfg *Config, dry bool) (*ini.File, error) { var uCfg *ini.File var sources []string base, err := loadConfig(configNames) if err != nil { - return NewE100("loadINI/homedir", err) + return nil, NewE100("loadINI/homedir", err) } cfg.RootINI = base @@ -186,20 +186,20 @@ func loadINI(cfg *Config, dry bool) error { // changed since Vale Server was deprecated. uCfg, err = processSources(cfg, sources) if err != nil { - return NewE100("config pipeline failed", err) + return nil, NewE100("config pipeline failed", err) } } else if cfg.Flags.Path != "" { // We've been given a value through `--config`. uCfg, err = shadowLoad(cfg.Flags.Path) if err != nil { - return NewE100("invalid --config", err) + return nil, NewE100("invalid --config", err) } cfg.Root = filepath.Dir(cfg.Flags.Path) } else if hasEnv { // We've been given a value through `VALE_CONFIG_PATH`. uCfg, err = shadowLoad(fromEnv) if err != nil { - return NewE100("invalid VALE_CONFIG_PATH", err) + return nil, NewE100("invalid VALE_CONFIG_PATH", err) } cfg.Root = filepath.Dir(fromEnv) cfg.Flags.Path = fromEnv @@ -207,7 +207,7 @@ func loadINI(cfg *Config, dry bool) error { // We're using a config file found using a local search process. uCfg, err = shadowLoad(base) if err != nil { - return NewE100(".vale.ini not found", err) + return nil, NewE100(".vale.ini not found", err) } cfg.Root = filepath.Dir(base) cfg.Flags.Path = base @@ -287,7 +287,7 @@ func processSources(cfg *Config, sources []string) (*ini.File, error) { return uCfg, err } -func processConfig(uCfg *ini.File, cfg *Config, paths []string, dry bool) error { +func processConfig(uCfg *ini.File, cfg *Config, paths []string, dry bool) (*ini.File, error) { core := uCfg.Section("") global := uCfg.Section("*") @@ -298,11 +298,11 @@ func processConfig(uCfg *ini.File, cfg *Config, paths []string, dry bool) error for _, k := range core.KeyStrings() { if f, found := coreOpts[k]; found { if err := f(core, cfg, paths); err != nil && !dry { - return err + return nil, err } } else if _, found = syntaxOpts[k]; found { msg := fmt.Sprintf("'%s' is a syntax-specific option", k) - return NewE201FromTarget(msg, k, cfg.RootINI) + return nil, NewE201FromTarget(msg, k, cfg.RootINI) } } @@ -322,7 +322,7 @@ func processConfig(uCfg *ini.File, cfg *Config, paths []string, dry bool) error f(global, cfg, paths) } else if _, found = syntaxOpts[k]; found { msg := fmt.Sprintf("'%s' is a syntax-specific option", k) - return NewE201FromTarget(msg, k, cfg.RootINI) + return nil, NewE201FromTarget(msg, k, cfg.RootINI) } else { cfg.GChecks[k] = validateLevel(k, global.Key(k).String(), cfg) cfg.Checks = append(cfg.Checks, k) @@ -337,7 +337,7 @@ func processConfig(uCfg *ini.File, cfg *Config, paths []string, dry bool) error pat, err := glob.Compile(sec) if err != nil { - return err + return nil, err } cfg.SecToPat[sec] = pat @@ -345,7 +345,7 @@ func processConfig(uCfg *ini.File, cfg *Config, paths []string, dry bool) error for _, k := range uCfg.Section(sec).KeyStrings() { if f, found := syntaxOpts[k]; found { if err = f(sec, uCfg.Section(sec), cfg); err != nil && !dry { - return err + return nil, err } } else { syntaxMap[k] = validateLevel(k, uCfg.Section(sec).Key(k).String(), cfg) @@ -356,5 +356,5 @@ func processConfig(uCfg *ini.File, cfg *Config, paths []string, dry bool) error cfg.SChecks[sec] = syntaxMap } - return nil + return uCfg, nil } diff --git a/internal/core/source.go b/internal/core/source.go index 309cc851..c2c38279 100644 --- a/internal/core/source.go +++ b/internal/core/source.go @@ -4,6 +4,8 @@ import ( "fmt" "path/filepath" "strings" + + "github.com/errata-ai/ini" ) func validateFlags(cfg *Config) error { @@ -15,44 +17,46 @@ func validateFlags(cfg *Config) error { return nil } -func ReadPipeline(provider string, flags *CLIFlags, dry bool) (*Config, error) { +func ReadPipeline(provider string, flags *CLIFlags, dry bool) (*Config, *ini.File, error) { + var sourced *ini.File + config, err := NewConfig(flags) if err != nil { - return config, err + return config, nil, err } else if err = validateFlags(config); err != nil { - return config, err + return config, nil, err } - err = from(provider, config, dry) + sourced, err = from(provider, config, dry) if err != nil { - return config, err + return config, nil, err } sources, err := pipeConfig(config) if err != nil { - return config, err + return config, nil, err } if len(sources) > 0 { config.Flags.Sources = strings.Join(sources, ",") - err = from(provider, config, dry) + sourced, err = from(provider, config, dry) if err != nil { - return config, err + return config, nil, err } } - return config, nil + return config, sourced, nil } // from updates an existing configuration with values from a user-provided // source. -func from(provider string, cfg *Config, dry bool) error { +func from(provider string, cfg *Config, dry bool) (*ini.File, error) { switch provider { case "ini": return loadINI(cfg, dry) default: - return NewE100( + return nil, NewE100( "source/From", fmt.Errorf("unknown provider '%s'", provider)) } }