[config] config:export --merge, --prefix, & --suffix

This commit is contained in:
Alex Quick
2017-02-18 15:58:32 -05:00
parent 686428a41a
commit fd27d90303
4 changed files with 73 additions and 35 deletions

View File

@@ -10,29 +10,8 @@ config_docker_args() {
verify_app_name "$APP"
if ! is_image_herokuish_based "$IMAGE"; then
shopt -s extglob
local ENV_ARGS
declare -A ENV_ARGS
for key in $(config_keys global); do
VAR="$(config_get --global "$key")"
printf -vVAR '%q' "${VAR%%*( )}"
ENV_ARGS[$key]="$VAR"
done
for key in $(config_keys app "$APP"); do
VAR="$(config_get "$APP" "$key")"
printf -vVAR '%q' "${VAR%%*( )}"
ENV_ARGS[$key]="$VAR"
done
shopt -u extglob
local ALL_ENV_ARGS
declare -a ALL_ENV_ARGS
for key in "${!ENV_ARGS[@]}"; do
local ARG="$key=${ENV_ARGS[$key]}"
ALL_ENV_ARGS+=("--env")
ALL_ENV_ARGS+=("$ARG")
done
echo -n "$STDIN ${ALL_ENV_ARGS[@]}"
local ENV_ARGS="$(config_export app $APP --prefix="-e" --separator=" " --merged)"
echo -n "$STDIN $ENV_ARGS"
else
echo -n "$STDIN"
fi

View File

@@ -24,22 +24,23 @@ func (e *Env) String() string {
//EnvfileString returns the contents of this Env in ENVFILE format
func (e *Env) EnvfileString() string {
return e.stringWithEntryPrefix("")
return e.StringWithPrefixAndSeparator("", "\n")
}
//ExportfileString returns the contents of this Env as bash exports
func (e *Env) ExportfileString() string {
return e.stringWithEntryPrefix("export ")
return e.StringWithPrefixAndSeparator("export ", "\n")
}
func (e *Env) stringWithEntryPrefix(prefix string) string {
//StringWithPrefixAndSeparator makes a string of the environment
// with the given prefix and separator for each entry
func (e *Env) StringWithPrefixAndSeparator(prefix string, separator string) string {
keys := e.Keys()
sort.Strings(keys)
entries := make([]string, len(keys))
for i, k := range keys {
entries[i] = fmt.Sprintf("%s%s='%s'", prefix, k, SingleQuoteEscape(e.env[k]))
}
return strings.Join(entries, "\n")
return strings.Join(entries, separator)
}
//SingleQuoteEscape escapes the value as if it were shell-quoted in single quotes
@@ -50,13 +51,23 @@ func SingleQuoteEscape(value string) string { // so that 'esc'apped' -> 'esc'\''
//NewFromTarget creates an env from the given target. Tareget is either "--global" or an app name
func NewFromTarget(target string) (*Env, error) {
if target == "--global" {
return parseEnv("global", getGlobalFile())
return LoadGlobal()
}
appfile, err := getAppFile(target)
return LoadApp(target)
}
//LoadApp loads an environment for the given app
func LoadApp(appName string) (*Env, error) {
appfile, err := getAppFile(appName)
if err != nil {
return nil, err
}
return parseEnv(target, appfile)
return parseEnv(appName, appfile)
}
//LoadGlobal loads the global environmen
func LoadGlobal() (*Env, error) {
return parseEnv("global", getGlobalFile())
}
//NewFromString creates an env from the given ENVFILE contents representation
@@ -64,6 +75,13 @@ func NewFromString(rep string) (*Env, error) {
return parseEnvFromReader("<unknown>", "", strings.NewReader(rep))
}
//Merge merges the given environment on top of the reciever
func (e *Env) Merge(other *Env) {
for _, k := range other.Keys() {
e.Set(k, other.GetDefault(k, ""))
}
}
//Set an environment variable
func (e *Env) Set(key string, value string) {
e.env[key] = value
@@ -80,6 +98,7 @@ func (e *Env) Keys() []string {
for k := range e.env {
keys = append(keys, k)
}
sort.Strings(keys)
return keys
}
@@ -108,6 +127,11 @@ func (e *Env) GetBoolDefault(key string, defaultValue bool) bool {
return v != "0"
}
//Len return the number of items in this environment
func (e *Env) Len() int {
return len(e.env)
}
//Map return the Env as a map
func (e *Env) Map() map[string]string {
return e.env

View File

@@ -44,6 +44,21 @@ func TestExportfileErrors(t *testing.T) {
Expect(err).To(HaveOccurred())
}
func TestMerge(t *testing.T) {
RegisterTestingT(t)
e, _ := NewFromString("FOO='bar'")
e2, _ := NewFromString("BAR='baz'")
e.Merge(e2)
Expect(e.Map()).To(Equal(pairs("BAR", "baz", "FOO", "bar")))
}
func TestArrayExport(t *testing.T) {
RegisterTestingT(t)
e, _ := NewFromString("BAR='BAZ'\nFOO='b'\\''ar '")
Expect(e.StringWithPrefixAndSeparator("", " ")).To(Equal("BAR='BAZ' FOO='b'\\''ar '"))
Expect(e.StringWithPrefixAndSeparator("-e", " ")).To(Equal("-eBAR='BAZ' -eFOO='b'\\''ar '"))
}
func pairs(vars ...string) map[string]string {
res := map[string]string{}
var i = 0

View File

@@ -11,10 +11,14 @@ import (
// print the environment to stdout
func main() {
const defaultPrefix = "export "
args := flag.NewFlagSet("config:export", flag.ExitOnError)
global := args.Bool("global", false, "--global: use the global environment")
merged := args.Bool("merged", false, "--merged: merge app environment and global environment")
keys := args.Bool("keys", false, "--keys: export keys only")
envfile := args.Bool("envfile", false, "--envfile: export as envfile rather than bash exports")
envfile := args.Bool("envfile", false, "--envfile: export as envfile rather than bash exports (--prefix='')")
prefix := args.String("prefix", "export ", "--prefix: prefix")
separator := args.String("separator", "\n", "--separator: separator")
args.Parse(os.Args[2:])
appName := args.Arg(0)
@@ -26,6 +30,9 @@ func main() {
if appName != "" {
common.LogFail("Trailing argument: " + appName)
}
if *merged == true {
common.LogFail("Only app environments can be merged")
}
appName = "--global"
}
@@ -33,6 +40,16 @@ func main() {
if err != nil {
common.LogFail(err.Error())
}
if *merged {
global, err := configenv.LoadGlobal()
if err != nil {
common.LogFail(err.Error())
}
global.Merge(env)
env = global
}
if *keys {
for _, k := range env.Keys() {
fmt.Println(k)
@@ -41,8 +58,11 @@ func main() {
}
if *envfile {
fmt.Println(env.EnvfileString())
} else {
fmt.Println(env.ExportfileString())
if *prefix != defaultPrefix {
common.LogFail("--prefix and --envfile cannot both be given")
return
}
*prefix = ""
}
fmt.Println(env.StringWithPrefixAndSeparator(*prefix, *separator))
}