From 5f18d778e3db53bb94319141d2f8f5ddf0b95b82 Mon Sep 17 00:00:00 2001 From: Fabian Siegel Date: Tue, 31 Aug 2021 22:32:49 +0200 Subject: [PATCH] config: add config command (#18) Closes #18 --- cmd/commands/auth/login/login.go | 3 +- cmd/commands/config/config.go | 171 +++++++++++++++++++++++++++++++ cmd/commands/repo/clone/clone.go | 1 + cmd/root.go | 2 + 4 files changed, 176 insertions(+), 1 deletion(-) create mode 100644 cmd/commands/config/config.go diff --git a/cmd/commands/auth/login/login.go b/cmd/commands/auth/login/login.go index 32c3b83..236a80a 100644 --- a/cmd/commands/auth/login/login.go +++ b/cmd/commands/auth/login/login.go @@ -63,7 +63,8 @@ func Add(authCmd *cobra.Command, globalOpts *options.GlobalOptions) { viper.Set("username", answers.Username) viper.Set("password", answers.Password) - + + // TODO: fix err = viper.WriteConfig() if err != nil { logging.Error(err) diff --git a/cmd/commands/config/config.go b/cmd/commands/config/config.go new file mode 100644 index 0000000..4e53257 --- /dev/null +++ b/cmd/commands/config/config.go @@ -0,0 +1,171 @@ +package config + +import ( + "fmt" + "io" + "io/ioutil" + "os" + "path/filepath" + "strings" + + "github.com/craftamap/bb/cmd/options" + bbgit "github.com/craftamap/bb/git" + "github.com/craftamap/bb/util/logging" + "github.com/kirsle/configdir" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +var ( + Local bool + Get bool +) + +func Add(rootCmd *cobra.Command, _ *options.GlobalOptions) { + configCommand := cobra.Command{ + Use: "config", + Short: "configure bb", + Long: "configure bb", + Args: func(cmd *cobra.Command, args []string) error { + if Get { + return cobra.ExactArgs(1)(cmd, args) + } else { + return cobra.ExactArgs(2)(cmd, args) + } + }, + Run: func(_ *cobra.Command, args []string) { + if Get { + // TODO: code here + } else { + var configDirectory string + var filename string + if Local { + var err error + configDirectory, filename, err = GetLocalConfigurationPath() + if err != nil { + logging.Error(err) + return + } + } else { + configDirectory, filename = GetGlobalConfigurationPath() + } + + // If the directory does not exist, something is off: + // - The global configuration directory get's created in root + // - The local configuration directory is a repository, which always exists + if _, err := os.Stat(configDirectory); os.IsNotExist(err) { + logging.Error(fmt.Sprintf("Expected directory \"%s\", but the directory does not exist", configDirectory)) + return + } + path := filepath.Join(configDirectory, filename) + // If the config itself does not exist, it's fine (although wierd for global) - we create it now + if _, err := os.Stat(path); os.IsNotExist(err) { + logging.Note(fmt.Sprintf("Creating config file %s", path)) + fh, err := os.Create(path) + if err != nil { + logging.Error(fmt.Sprintf("Unable to create file %s", path)) + } + fh.Close() + } + + logging.Debugf("Config file path: %s", path) + + tmpVp := viper.New() + tmpVp.SetConfigType("toml") + tmpVp.SetConfigFile(path) + tmpVp.ReadInConfig() + + key := args[0] + newValue := args[1] + + isSetAlready := tmpVp.IsSet(key) + oldValue := tmpVp.Get(key) + + if isSetAlready { + // Don't print old password values + if strings.ToLower(key) == "password" { + oldValue = "(truncated)" + } + logging.Warning(fmt.Sprintf("\"%s\" is already set. This will overwrite the value of \"%s\" from \"%s\" to \"%s\".", key, key, oldValue, newValue)) + } + + logging.Note(fmt.Sprintf("Setting \"%s\" to \"%s\" in %s", key, newValue, path)) + logging.Debugf("%+v", tmpVp.AllSettings()) + + // This will most likely save everything as a string + // TODO: find this out and find a way to save bools and numbers + tmpVp.Set(key, newValue) + logging.Debugf("%+v", tmpVp.AllSettings()) + + // WORKAROUND: currently, WriteConfig does not support writing to `.bb`-files despite setting SetConfigType. + // Therefore, we create a temporary file, write there, and try to copy the file over. + tmpFh, err := ioutil.TempFile(os.TempDir(), "bb-tmpconfig.*.toml") + if err != nil { + logging.Error("Failed to create temporary configuration file") + return + } + tmpFilename := tmpFh.Name() + logging.Debugf("tmpFilename: %s", tmpFilename) + err = tmpFh.Close() + if err != nil { + logging.Error("Failed to create temporary configuration file") + return + } + err = tmpVp.WriteConfigAs(tmpFilename) + if err != nil { + logging.Error(fmt.Sprintf("Failed to write temporary config %s: %s", path, err)) + return + } + err = copyFileContent(tmpFilename, path) + if err != nil { + logging.Error(fmt.Sprintf("Failed to write config %s -> %s: %s", tmpFilename, path, err)) + return + } + + + logging.SuccessExclamation(fmt.Sprintf("Successfully updated configuration %s", path)) + } + }, + } + + configCommand.Flags().BoolVar(&Local, "local", false, "local allows to modify the local configuration") + configCommand.Flags().BoolVar(&Get, "get", false, "gets a configuration value instead of setting it") + + rootCmd.AddCommand(&configCommand) +} + +func copyFileContent(src string, dst string) error { + sourceFileStat, err := os.Stat(src) + if err != nil { + return err + } + + if !sourceFileStat.Mode().IsRegular() { + return fmt.Errorf("%s is not a regular file", src) + } + + source, err := os.Open(src) + if err != nil { + return err + } + defer source.Close() + + destination, err := os.Create(dst) // Create or trunicate + if err != nil { + return err + } + defer destination.Close() + _, err = io.Copy(destination, source) + return err +} + +// TODO: Extract to util +func GetGlobalConfigurationPath() (configDirectory string, filename string) { + configDirectory = configdir.LocalConfig("bb") + return configDirectory, "configuration.toml" +} + +func GetLocalConfigurationPath() (configDirectory, filename string, err error) { + configDirectory, err = bbgit.RepoPath() + return configDirectory, ".bb", err +} diff --git a/cmd/commands/repo/clone/clone.go b/cmd/commands/repo/clone/clone.go index 57afc91..2287818 100644 --- a/cmd/commands/repo/clone/clone.go +++ b/cmd/commands/repo/clone/clone.go @@ -35,6 +35,7 @@ func Add(repoCmd *cobra.Command, globalOpts *options.GlobalOptions) { return } viper.Set("git_protocol", gitProtocol) + // TODO: fix viper.WriteConfig() } diff --git a/cmd/root.go b/cmd/root.go index 3aca2ce..7844b5f 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -10,6 +10,7 @@ import ( "github.com/craftamap/bb/client" "github.com/craftamap/bb/cmd/commands/api" "github.com/craftamap/bb/cmd/commands/auth" + "github.com/craftamap/bb/cmd/commands/config" "github.com/craftamap/bb/cmd/commands/downloads" "github.com/craftamap/bb/cmd/commands/issue" "github.com/craftamap/bb/cmd/commands/pipelines" @@ -106,6 +107,7 @@ func init() { auth.Add(rootCmd, &globalOpts) repo.Add(rootCmd, &globalOpts) pipelines.Add(rootCmd, &globalOpts) + config.Add(rootCmd, &globalOpts) if CommitSHA != "" { vt := rootCmd.VersionTemplate()