-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: steviebps <stephenwodecki@gmail.com>
- Loading branch information
Showing
13 changed files
with
353 additions
and
135 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
package cmd | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
"path/filepath" | ||
"sync" | ||
|
||
"github.com/spf13/cobra" | ||
"github.com/steviebps/rein/internal/logger" | ||
rein "github.com/steviebps/rein/pkg" | ||
"github.com/steviebps/rein/utils" | ||
) | ||
|
||
var chamberName string | ||
var toStdout bool | ||
|
||
var buildCmdError = logger.ErrorWithPrefix("Error running build command: ") | ||
|
||
// buildCmd represents the build command | ||
var buildCmd = &cobra.Command{ | ||
Use: "build", | ||
Short: "Build chambers with inherited toggles", | ||
Long: `Build command will take your chamber configs and compile them with their inherited values`, | ||
Example: "rein build -o /path/to/your/directory", | ||
Run: func(cmd *cobra.Command, args []string) { | ||
var err error | ||
outputDir, _ := cmd.Flags().GetString("output-dir") | ||
forceCreateDir, _ := cmd.Flags().GetBool("force") | ||
chamberName, _ = cmd.Flags().GetString("chamber") | ||
toStdout, _ = cmd.Flags().GetBool("to-stdout") | ||
|
||
// defaults to working directory | ||
if outputDir == "" { | ||
outputDir, err = os.Getwd() | ||
if err != nil { | ||
buildCmdError(err.Error()) | ||
os.Exit(1) | ||
} | ||
} | ||
|
||
outputDir, _ = filepath.Abs(outputDir) | ||
|
||
if _, err := os.Stat(outputDir); os.IsNotExist(err) { | ||
if forceCreateDir { | ||
os.Mkdir(outputDir, 0700) | ||
} else { | ||
buildCmdError(fmt.Sprintf("Directory %v does not exist", outputDir)) | ||
logger.InfoString(fmt.Sprintf("\nTry running: \"rein build --output-dir %v --force\" to force create the directory", outputDir)) | ||
os.Exit(1) | ||
} | ||
} | ||
|
||
var wg sync.WaitGroup | ||
build(&globalChamber, &wg, outputDir) | ||
wg.Wait() | ||
os.Exit(0) | ||
}, | ||
} | ||
|
||
func build(parent *rein.Chamber, wg *sync.WaitGroup, outputDir string) { | ||
|
||
parent.TraverseAndBuild(func(c *rein.Chamber) bool { | ||
|
||
searchingByName := chamberName != "" | ||
foundByName := chamberName == c.Name | ||
|
||
if foundByName || (!searchingByName && (c.IsBuildable || c.IsApp)) { | ||
|
||
fileName := outputDir + "/" + c.Name + ".json" | ||
|
||
wg.Add(1) | ||
go func() { | ||
defer wg.Done() | ||
if toStdout { | ||
if err := utils.WriteInterfaceWith(os.Stdout, c.Toggles, true); err != nil { | ||
buildCmdError(err.Error()) | ||
os.Exit(1) | ||
} | ||
} else { | ||
if err := utils.WriteInterfaceToFile(fileName, c.Toggles, true); err != nil { | ||
buildCmdError(err.Error()) | ||
os.Exit(1) | ||
} | ||
fmt.Println(fileName) | ||
} | ||
}() | ||
} | ||
return foundByName | ||
}) | ||
} | ||
|
||
func init() { | ||
rootCmd.AddCommand(buildCmd) | ||
buildCmd.Flags().StringP("output-dir", "o", "", "sets the output directory of the built files") | ||
buildCmd.Flags().BoolP("force", "f", false, "force create directory (used with output-dir)") | ||
buildCmd.Flags().StringP("chamber", "c", "", "builds the selected chamber only") | ||
buildCmd.Flags().Bool("to-stdout", false, "prints the built files to stdout (overrides output-dir flag)") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package cmd | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
|
||
"github.com/spf13/cobra" | ||
"github.com/spf13/viper" | ||
"github.com/steviebps/rein/internal/logger" | ||
rein "github.com/steviebps/rein/pkg" | ||
) | ||
|
||
var getCmdError = logger.ErrorWithPrefix("Error running get command: ") | ||
|
||
// getCmd represents the get command | ||
var getCmd = &cobra.Command{ | ||
Use: "get", | ||
Short: "get a value of a toggle", | ||
Long: "retrieves and prints the value of the specified toggle within the specified chamber", | ||
Run: func(cmd *cobra.Command, args []string) { | ||
var value interface{} | ||
version := viper.GetString("version") | ||
toggle, _ := cmd.Flags().GetString("toggle") | ||
chamberName, _ = cmd.Flags().GetString("chamber") | ||
|
||
globalChamber.TraverseAndBuild(func(c *rein.Chamber) bool { | ||
if c.Name == chamberName { | ||
value = c.GetToggleValue(toggle, version) | ||
} | ||
|
||
return value != nil | ||
}) | ||
|
||
if value == nil { | ||
getCmdError(fmt.Sprintf("Could not find toggle value %q inside chamber %q", toggle, chamberName)) | ||
os.Exit(1) | ||
} | ||
|
||
fmt.Println(value) | ||
}, | ||
} | ||
|
||
func init() { | ||
rootCmd.AddCommand(getCmd) | ||
|
||
getCmd.Flags().StringP("chamber", "c", "", "chamber to retrieve toggle from") | ||
getCmd.Flags().StringP("toggle", "t", "", "toggle name to retrieve") | ||
|
||
getCmd.MarkFlagRequired("toggle") | ||
getCmd.MarkFlagRequired("chamber") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package cmd | ||
|
||
import ( | ||
"os" | ||
|
||
"github.com/spf13/cobra" | ||
"github.com/steviebps/rein/internal/logger" | ||
"github.com/steviebps/rein/utils" | ||
) | ||
|
||
var printCmdError = logger.ErrorWithPrefix("Error running print command: ") | ||
|
||
// printCmd represents the print command | ||
var printCmd = &cobra.Command{ | ||
Use: "print", | ||
Short: "Print all Chambers", | ||
Run: func(cmd *cobra.Command, args []string) { | ||
pretty, _ := cmd.Flags().GetBool("pretty") | ||
output, _ := cmd.Flags().GetString("output") | ||
|
||
if output != "" { | ||
if err := utils.WriteInterfaceToFile(output, globalChamber, pretty); err != nil { | ||
printCmdError(err.Error()) | ||
os.Exit(1) | ||
} | ||
} else { | ||
if err := utils.WriteInterfaceWith(cmd.OutOrStdout(), globalChamber, pretty); err != nil { | ||
printCmdError(err.Error()) | ||
os.Exit(1) | ||
} | ||
} | ||
|
||
os.Exit(0) | ||
}, | ||
} | ||
|
||
func init() { | ||
rootCmd.AddCommand(printCmd) | ||
printCmd.Flags().BoolP("pretty", "p", false, "prints in pretty format") | ||
printCmd.Flags().StringP("output", "o", "", "sets the output file of the printed content") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
package cmd | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"io" | ||
"net/http" | ||
"os" | ||
|
||
"github.com/spf13/cobra" | ||
|
||
homedir "github.com/mitchellh/go-homedir" | ||
"github.com/spf13/viper" | ||
"github.com/steviebps/rein/internal/logger" | ||
rein "github.com/steviebps/rein/pkg" | ||
utils "github.com/steviebps/rein/utils" | ||
) | ||
|
||
var home string | ||
var cfgFile string | ||
var chamber string | ||
var globalChamber = rein.Chamber{Toggles: map[string]*rein.Toggle{}, Children: []*rein.Chamber{}} | ||
|
||
// Version the version of rein | ||
var Version = "development" | ||
|
||
// rootCmd represents the base command when called without any subcommands | ||
var rootCmd = &cobra.Command{ | ||
Use: "rein", | ||
Short: "Local and remote configuration management", | ||
Long: `CLI for managing application configuration of local and remote JSON files`, | ||
PersistentPreRun: configPreRun, | ||
DisableAutoGenTag: true, | ||
Version: Version, | ||
} | ||
|
||
// Execute adds all child commands to the root command and sets flags appropriately. | ||
// This is called by main.main(). It only needs to happen once to the rootCmd. | ||
func Execute() { | ||
if err := rootCmd.Execute(); err != nil { | ||
logger.ErrorString(fmt.Sprintf("Error while starting rein: %v", err)) | ||
os.Exit(1) | ||
} | ||
} | ||
|
||
func init() { | ||
cobra.OnInitialize(initConfig) | ||
|
||
var err error | ||
home, err = homedir.Dir() | ||
if err != nil { | ||
logger.ErrorString(err.Error()) | ||
os.Exit(1) | ||
} | ||
|
||
rootCmd.SetVersionTemplate(`{{printf "%s\n" .Version}}`) | ||
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "rein configuration file") | ||
rootCmd.PersistentFlags().String("app-version", "", "runs all commands with a specified version") | ||
viper.BindPFlag("app-version", rootCmd.PersistentFlags().Lookup("app-version")) | ||
} | ||
|
||
// initConfig reads in config file and ENV variables if set. | ||
func initConfig() { | ||
if cfgFile != "" { | ||
// Use config file from the flag. | ||
viper.SetConfigFile(cfgFile) | ||
} else { | ||
viper.AddConfigPath(".") | ||
viper.AddConfigPath(home + "/.rein") | ||
viper.SetConfigName("rein") | ||
} | ||
|
||
viper.AutomaticEnv() // read in environment variables that match | ||
|
||
// If a config file is found, read it in. | ||
if err := viper.ReadInConfig(); err != nil { | ||
|
||
if configFileUsed := viper.ConfigFileUsed(); configFileUsed != "" { | ||
logger.ErrorString(fmt.Sprintf("Error reading config file: %v", configFileUsed)) | ||
} else { | ||
logger.ErrorString(err.Error()) | ||
} | ||
|
||
os.Exit(1) | ||
} | ||
} | ||
|
||
func retrieveRemoteConfig(url string) (*http.Response, error) { | ||
return http.Get(url) | ||
} | ||
|
||
func retrieveLocalConfig(fileName string) (io.ReadCloser, error) { | ||
if !utils.Exists(fileName) { | ||
return nil, fmt.Errorf("Could not find file %q", fileName) | ||
} | ||
|
||
file, err := os.Open(fileName) | ||
if err != nil { | ||
return nil, fmt.Errorf("Could not open file %q: %w", fileName, err) | ||
} | ||
|
||
return file, nil | ||
} | ||
|
||
// sets up the config for all sub-commands | ||
func configPreRun(cmd *cobra.Command, args []string) { | ||
var jsonFile io.ReadCloser | ||
var err error | ||
chamberFile := viper.GetString("chamber") | ||
|
||
validURL, url := utils.IsURL(chamberFile) | ||
if validURL { | ||
res, err := retrieveRemoteConfig(url.String()) | ||
|
||
if err != nil { | ||
logger.ErrorString(fmt.Sprintf("Error trying to GET this resource %q: %v", chamberFile, err)) | ||
os.Exit(1) | ||
} | ||
jsonFile = res.Body | ||
} else { | ||
jsonFile, err = retrieveLocalConfig(chamberFile) | ||
if err != nil { | ||
logger.ErrorString(fmt.Sprintf("Error retrieving local config: %v", err)) | ||
os.Exit(1) | ||
} | ||
} | ||
defer jsonFile.Close() | ||
|
||
byteValue, err := io.ReadAll(jsonFile) | ||
if err != nil { | ||
logger.ErrorString(fmt.Sprintf("Error reading file %q: %v", chamberFile, err)) | ||
os.Exit(1) | ||
} | ||
|
||
if err := json.Unmarshal(byteValue, &globalChamber); err != nil { | ||
logger.ErrorString(fmt.Sprintf("Error reading %q: %v", chamberFile, err)) | ||
os.Exit(1) | ||
} | ||
} |
Oops, something went wrong.