Skip to content
Open
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
79 changes: 55 additions & 24 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"os"
"path/filepath"

"github.com/kitops-ml/kitops/pkg/cmd/config"
"github.com/kitops-ml/kitops/pkg/cmd/dev"
"github.com/kitops-ml/kitops/pkg/cmd/diff"
"github.com/kitops-ml/kitops/pkg/cmd/info"
Expand Down Expand Up @@ -73,33 +74,44 @@ func RunCommand() *cobra.Command {
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
output.SetOut(cmd.OutOrStdout())
output.SetErr(cmd.ErrOrStderr())
if err := output.SetLogLevelFromString(opts.loglevel); err != nil {
return output.Fatalln(err)
}
output.SetProgressBars(opts.progressBars)

switch opts.verbosity {
case 0:
break
case 1:
output.Debugf("Setting verbosity to %s", output.LogLevelDebug)
output.SetLogLevel(output.LogLevelDebug)
case 2:
output.Debugf("Setting verbosity to %s", output.LogLevelTrace)
output.SetLogLevel(output.LogLevelTrace)
default:
output.Debugf("Setting verbosity to %s and disabling progress bars", output.LogLevelTrace)
output.SetLogLevel(output.LogLevelTrace)
output.SetProgressBars("none")
}

configHome, err := getConfigHome(opts)
configHome, err := getConfigHomePath(opts)
if err != nil {
output.Errorf("Failed to read base config directory")
output.Infof("Use the --config flag or set the $%s environment variable to provide a default", constants.KitopsHomeEnvVar)
output.Debugf("Error: %s", err)
return errors.New("exit")
}

configYamlPath := constants.ConfigYamlPath(configHome)
configStruct, loadErr := config.LoadConfigFileHelper(configYamlPath)
if loadErr != nil && !errors.Is(loadErr, os.ErrNotExist) {
return loadErr
}

if cmd.Flags().Changed("log-level") || configStruct.LogLevel == "" {
if err := output.SetLogLevelFromString(opts.loglevel); err != nil {
return output.Fatalln(err)
}
} else {
if err := output.SetLogLevelFromString(configStruct.LogLevel); err != nil {
output.Errorf("Invalid log level: %s", err)
output.SetLogLevelFromString(opts.loglevel)
}
}

if cmd.Flags().Changed("progress") || configStruct.ProgressBars == "" {
output.SetProgressBars(opts.progressBars)
} else {
output.SetProgressBars(configStruct.ProgressBars)
}

if cmd.Flags().Changed("verbose") || configStruct.Verbosity == 0 {
setVerbosity(opts.verbosity)
} else {
setVerbosity(configStruct.Verbosity)
}

ctx := context.WithValue(cmd.Context(), constants.ConfigKey{}, configHome)
cache.SetCacheHome(constants.CachePath(configHome))
cmd.SetContext(ctx)
Expand Down Expand Up @@ -167,6 +179,7 @@ func addSubcommands(rootCmd *cobra.Command) {
rootCmd.AddCommand(diff.DiffCommand())
rootCmd.AddCommand(kitimport.ImportCommand())
rootCmd.AddCommand(kitcache.CacheCommand())
rootCmd.AddCommand(config.ConfigCommand())
}

// Execute adds all child commands to the root command and sets flags appropriately.
Expand All @@ -178,7 +191,7 @@ func Execute() {
}
}

func getConfigHome(opts *rootOptions) (string, error) {
func getConfigHomePath(opts *rootOptions) (string, error) {
if opts.configHome != "" {
output.Debugf("Using config directory from flag: %s", opts.configHome)
absHome, err := filepath.Abs(opts.configHome)
Expand All @@ -198,10 +211,28 @@ func getConfigHome(opts *rootOptions) (string, error) {
return absHome, nil
}

defaultHome, err := constants.DefaultConfigPath()
if err != nil {
return "", err
defaultHome, defaultHomeErr := constants.DefaultConfigPath()
if defaultHomeErr != nil {
return "", defaultHomeErr
}

output.Debugf("Using default config directory: %s", defaultHome)
return defaultHome, nil
}

func setVerbosity(verbosity int) {
switch verbosity {
case 0:
break
case 1:
output.Debugf("Setting verbosity to %s", output.LogLevelDebug)
output.SetLogLevel(output.LogLevelDebug)
case 2:
output.Debugf("Setting verbosity to %s", output.LogLevelTrace)
output.SetLogLevel(output.LogLevelTrace)
default:
output.Debugf("Setting verbosity to %s and disabling progress bars", output.LogLevelTrace)
output.SetLogLevel(output.LogLevelTrace)
output.SetProgressBars("none")
}
}
150 changes: 150 additions & 0 deletions pkg/cmd/config/cmd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
package config

import (
"encoding/json"

"fmt"

"github.com/kitops-ml/kitops/pkg/lib/constants"
"github.com/kitops-ml/kitops/pkg/lib/util"
"github.com/kitops-ml/kitops/pkg/output"
"github.com/spf13/cobra"
"strings"
)

type Config struct {
Verbosity int `yaml:"verbosity" json:"verbosity"`
LogLevel string `yaml:"logLevel" json:"logLevel"`
ProgressBars string `yaml:"progressBars" json:"progressBars"`
}

func ConfigCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "config",
Short: configShortDesc,
Long: configLongDesc,
}
cmd.AddCommand(configSetCommand())
cmd.AddCommand(configGetCommand())
cmd.AddCommand(configListCommand())
cmd.AddCommand(configResetCommand())

return cmd
}

func configSetCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "set KEY VALUE",
Short: setConfigShortDesc,
Long: setConfigLongDesc,
RunE: runSetCommand,
}
cmd.Args = cobra.ExactArgs(2)

return cmd
}

func runSetCommand(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
path, ok := ctx.Value(constants.ConfigKey{}).(string)
if !ok {
return fmt.Errorf("failed to retrieve config path from context")
}
if err := setConfig(args[0], args[1], path); err != nil {
return output.Fatalf("%s", err)
}
return nil
}

func configGetCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "get KEY",
Short: getConfigShortDesc,
Long: getConfigLongDesc,
RunE: runGetCommand,
}
cmd.Args = cobra.ExactArgs(1)

return cmd
}

func runGetCommand(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
path, ok := ctx.Value(constants.ConfigKey{}).(string)
if !ok {
return fmt.Errorf("failed to retrieve config path from context")
}
val, err := getConfig(args[0], path)
if err != nil {
return output.Fatalf("%s", err)
}
fmt.Fprintln(output.GetOut(), val)
return nil
}

func configListCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "list",
Short: listConfigShortDesc,
Long: listConfigLongDesc,
RunE: runListCommand,
}
cmd.Args = cobra.NoArgs

return cmd
}

func runListCommand(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
path, ok := ctx.Value(constants.ConfigKey{}).(string)
if !ok {
return fmt.Errorf("failed to retrieve config path from context")
}
configStruct, err := listConfig(path)
if err != nil {
return output.Fatalf("%s", err)
}

list, jsonErr := json.MarshalIndent(configStruct, "", " ")

if jsonErr != nil {
return jsonErr
}

output.Infoln(string(list))

return nil
}

func configResetCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "reset",
Short: resetConfigShortDesc,
Long: resetConfigLongDesc,
RunE: runResetCommand,
}
cmd.Args = cobra.NoArgs

return cmd
}

func runResetCommand(cmd *cobra.Command, args []string) error {
warning := "Warning: this action is destructive and cannot be undone.Proceed? (y/N): "

choice, choiceErr := util.PromptForInput(warning, false)
if choiceErr != nil {
return choiceErr
}

if !strings.EqualFold(choice, "y") && !strings.EqualFold(choice, "yes") {
return nil
}

ctx := cmd.Context()
path, ok := ctx.Value(constants.ConfigKey{}).(string)
if !ok {
return fmt.Errorf("failed to retrieve config path from context")
}

return resetConfig(path)
}
122 changes: 122 additions & 0 deletions pkg/cmd/config/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package config

import (
"errors"
"fmt"
"os"
"path/filepath"
"strconv"

"github.com/kitops-ml/kitops/pkg/lib/constants"
"gopkg.in/yaml.v3"
)

func setConfig(key, value, path string) error {

configYamlPath := constants.ConfigYamlPath(path)

configStruct, loadConfigErr := LoadConfigFileHelper(configYamlPath)
if loadConfigErr != nil && !errors.Is(loadConfigErr, os.ErrNotExist) {
return loadConfigErr
}

switch key {
case "logLevel":
configStruct.LogLevel = value
case "progressBars":
configStruct.ProgressBars = value
case "verbosity":
intValue, err := strconv.Atoi(value)
if err != nil {
return err
}
configStruct.Verbosity = intValue
default:
return fmt.Errorf("invalid config key: %s", key)
}

if err := saveConfigFile(configStruct, configYamlPath); err != nil {
return fmt.Errorf("failed to save setting: %w", err)
}

return nil
}

func getConfig(key, path string) (string, error) {
configYamlPath := constants.ConfigYamlPath(path)

configStruct, loadErr := LoadConfigFileHelper(configYamlPath)
if loadErr != nil {
return "", loadErr
}

switch key {
case "logLevel":
return configStruct.LogLevel, nil
case "progressBars":
return configStruct.ProgressBars, nil
case "verbosity":
stringValue := strconv.Itoa(configStruct.Verbosity)
return stringValue, nil
default:
return "", fmt.Errorf("invalid config key: %s", key)
}

}

func listConfig(path string) (Config, error) {
configYamlPath := constants.ConfigYamlPath(path)

configStruct, loadErr := LoadConfigFileHelper(configYamlPath)
if loadErr != nil {
return Config{}, loadErr
}

return configStruct, nil
}

func resetConfig(path string) error {
configYamlPath := constants.ConfigYamlPath(path)

if err := os.Remove(configYamlPath); err != nil && !errors.Is(err, os.ErrNotExist) {
return err
}

return nil
}

func LoadConfigFileHelper(configYamlPath string) (Config, error) {
data, readErr := os.ReadFile(configYamlPath)
var cfg Config

if readErr != nil {
if !errors.Is(readErr, os.ErrNotExist) {
return cfg, readErr
}
return cfg, fmt.Errorf("config file does not exist: %w", readErr)
}

unmarshErr := yaml.Unmarshal(data, &cfg)
if unmarshErr != nil {
return cfg, fmt.Errorf("failed to unmarshal data: %w", unmarshErr)
}

return cfg, nil
}

func saveConfigFile(configStruct Config, configYamlPath string) error {
yamlconfigStruct, marshErr := yaml.Marshal(configStruct)
if marshErr != nil {
return fmt.Errorf("failed to marshal data: %w", marshErr)
}

configDir := filepath.Dir(configYamlPath)
if err := os.MkdirAll(configDir, 0755); err != nil {
return fmt.Errorf("failed to create config directory: %w", err)
}

if writeErr := os.WriteFile(configYamlPath, yamlconfigStruct, 0644); writeErr != nil {
return fmt.Errorf("failed to set to config file: %w", writeErr)
}
return nil
}
Loading