Skip to content

Commit

Permalink
goroutines for env files generation; general code reorganization; imp…
Browse files Browse the repository at this point in the history
…roved log and missing vars info
  • Loading branch information
s1moe2 committed Jun 1, 2020
1 parent 55dc6cc commit 7da2b5d
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 69 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
.DS_Store
.idea
.bin
test.sh
test.sh
.*env
130 changes: 80 additions & 50 deletions cmd/envgen.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,49 +2,51 @@ package cmd

import (
"fmt"
"gopkg.in/yaml.v2"
"io/ioutil"
"os"
"strings"
"sync"

"github.com/joho/godotenv"
"github.com/spf13/cobra"

"gopkg.in/yaml.v2"
)

const DefaultEnvFileName = ".env"

type ConfBranches struct {
type ConfBranch struct {
Name string `yaml:"name"`
Suffix string `yaml:"suffix"`
}

type ConfPackages struct {
type ConfPackage struct {
Package string `yaml:"package"`
EnvFile string `yaml:"envFile"`
Variables []string `yaml:"variables"`
}

type GeneratorConfig struct {
BranchVarName string `yaml:"branchVarName"`
BranchVarDefault string `yaml:"branchVarDefault"`
Branches []ConfBranches `yaml:"branches"`
Packages []ConfPackages `yaml:"packages"`
Globals []string `yaml:"globals"`
BranchVarName string `yaml:"branchVarName"`
BranchVarDefault string `yaml:"branchVarDefault"`
Branches []ConfBranch `yaml:"branches"`
Packages []ConfPackage `yaml:"packages"`
Globals []string `yaml:"globals"`
}

type Generator struct {
conf GeneratorConfig
branchSuffix string
globals []string
}

var rootCmd = &cobra.Command{
Version: "1.0.0",
Version: "2.1.0",
SilenceErrors: true,
Use: "envgen <configFilePath> [envFile1] ... [envFileN]",
Short: "envgen generates env files for sub packages",
Long: "envgen is CLI tool that generates .env files for subpackages in your project based on a configuration file",
Args: cobra.MinimumNArgs(1),
RunE: generateEnvFiles,
RunE: runGenerator,
}

func Execute() {
Expand All @@ -64,63 +66,64 @@ func Execute() {
}
}

func generateEnvFiles(cmd *cobra.Command, args []string) error {
gen := &Generator{}
err := gen.loadConfig(args[0])
func runGenerator(cmd *cobra.Command, args []string) error {
gen, err := newGenerator(args[0])
if err != nil {
return err
}

logInfo("Starting env files generation")
fmt.Println()
logInfo("Starting env files generation\n")
gen.loadGlobals()
gen.generateEnvFiles()
logInfo("Finished env files generation!\n")

globals, err := getVariablesValues(gen.conf.Globals, "")
return nil
}

func newGenerator(filepath string) (*Generator, error) {
gen := &Generator{}
err := gen.loadConfig(filepath)
if err != nil {
return err
return nil, err
}

for _, p := range gen.conf.Packages {
logInfo("> Loading variables for " + p.Package)
return gen, nil
}

packageVars, err := getVariablesValues(p.Variables, gen.branchSuffix)
if err != nil {
return err
}
func (g *Generator) generateEnvFiles() {
var wg sync.WaitGroup
for _, p := range g.conf.Packages {
wg.Add(1)
go g.generatePackageEnvFile(p, &wg)
}

packageVars = append(packageVars, globals...)
wg.Wait()
}

logInfo("> Writing env file for " + p.Package)
envFile := p.EnvFile
if envFile == "" {
envFile = DefaultEnvFileName
}
genEnvFilePath := fmt.Sprintf("%s/%s", p.Package, envFile)
err = writeFile(genEnvFilePath, packageVars)
if err != nil {
return err
}
func (g *Generator) generatePackageEnvFile(pckg ConfPackage, wg *sync.WaitGroup) {
defer wg.Done()
logInfo(fmt.Sprintf("[%s] loading variables", pckg.Package))

logInfo("> Done generating env file for " + p.Package)
fmt.Println()
packageVars, missing := getVariablesValues(pckg.Variables, g.branchSuffix)
if len(missing) > 0 {
// TODO create flag to break execution as error
logWarn(fmt.Sprintf("[%s] missing env vars: %s\n", pckg.Package, strings.Join(missing, ", ")))
}

logInfo("Finished env files generation!")
return nil
}
logInfo(fmt.Sprintf("[%s] writing env file", pckg.Package))

func getVariablesValues(envVars []string, suffix string) ([]string, error) {
vars := []string{}
for _, v := range envVars {
val, ok := os.LookupEnv(v + suffix)
if !ok {
err := fmt.Errorf("missing variable %s", v)
return nil, err
}
envFile := pckg.EnvFile
if envFile == "" {
envFile = DefaultEnvFileName
}

vars = append(vars, fmt.Sprintf("%s=%s", v, val))
genEnvFilePath := fmt.Sprintf("%s/%s", pckg.Package, envFile)
err := writeFile(genEnvFilePath, append(packageVars, g.globals...))
if err != nil {
logError(err)
}

return vars, nil
logInfo(fmt.Sprintf("[%s] generated env file\n", pckg.Package))
}

// loadConfig loads the configuration from the provided yaml file
Expand Down Expand Up @@ -157,6 +160,33 @@ func (g *Generator) findBranchSuffix() string {
return ""
}

// loads global env variables (to be added on all packages)
func (g *Generator) loadGlobals() {
globals, missing := getVariablesValues(g.conf.Globals, "")
if len(missing) > 0 {
logWarn(fmt.Sprintf("[globals] missing env vars: %s\n", strings.Join(missing, ", ")))
}

g.globals = globals
}

// returns a string slice loaded with the env var declarations
// and an array with those not found in the environment
func getVariablesValues(envVars []string, suffix string) ([]string, []string) {
vars := []string{}
missing := []string{}
for _, v := range envVars {
val, ok := os.LookupEnv(v + suffix)
if !ok {
missing = append(missing, v)
}

vars = append(vars, fmt.Sprintf("%s=%s", v, val))
}

return vars, missing
}

// getEnv looks up for a loaded environment variable.
// An optional suffix may be passed, as well as a default value to return if the env var is not loaded.
func getEnv(key string, suffix string, defaultVal string) string {
Expand Down
18 changes: 14 additions & 4 deletions cmd/log.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ import (
)

const (
InfoColor = "\033[1;34m%s\033[0m\n"
ErrorColor = "\033[1;31m%s\033[0m\n"
InfoColor = "\033[1;34m%s\033[0m\n"
WarnColor = "\033[1;33m%s\033[0m"
ErrorColor = "\033[1;31m%s\033[0m\n"
)

func printLog(color string, msg interface{}) {
Expand All @@ -18,7 +19,16 @@ func logInfo(msg interface{}) {
printLog(InfoColor, msg)
}

type errorWriter struct {}
func logWarn(msg interface{}) {
printLog(WarnColor, msg)
}

func logError(msg interface{}) {
printLog(ErrorColor, msg)
}

type errorWriter struct{}

func (w errorWriter) Write(p []byte) (n int, err error) {
return fmt.Fprintf(os.Stdout, ErrorColor, p)
}
}
34 changes: 20 additions & 14 deletions sample-config.yaml
Original file line number Diff line number Diff line change
@@ -1,22 +1,28 @@
branchVarName: CIRCLE_BRANCH
branchVarDefault: develop
#branchVarName: CIRCLE_BRANCH
#branchVarDefault: develop

branches:
- name: develop
suffix: _DEV
- name: staging
suffix: _STG
#branches:
# - name: develop
# suffix: _DEV
# - name: staging
# suffix: _STG

packages:
- package: awesome-crawler
envFile: .crawler.env
- package: api
envFile: .api.env
variables:
- AC_ENDPOINT
- AC_THRESHOLD
- package: web-server
- API_ENDPOINT
- API_TIMEOUT

- package: api/db
variables:
- DB_PORT
- DB_SCHEMA

- package: crawler
variables:
- WS_PORT
- WS_ADDRESS
- C_CRON
- C_DB_URI

globals:
- V_DATABASE

0 comments on commit 7da2b5d

Please sign in to comment.