[config] support for env bundles

This commit is contained in:
Alex Quick
2017-04-22 15:58:03 -04:00
parent fd27d90303
commit c20fbfccf6
4 changed files with 62 additions and 32 deletions

View File

@@ -6,36 +6,23 @@ source "$PLUGIN_AVAILABLE_PATH/config/functions"
build_env_pre_build_buildpack() {
declare desc="build-env pre-build-buildpack plugin trigger"
local trigger="build_env_pre_build_buildpack"
local APP="$1"; local IMAGE=$(get_app_image_name "$APP"); local BUILD_ENV=""
local APP="$1"; local IMAGE=$(get_app_image_name "$APP");
verify_app_name "$APP"
[[ -z $(config_get --global CURL_CONNECT_TIMEOUT) ]] && config_set --global CURL_CONNECT_TIMEOUT=90
[[ -z $(config_get --global CURL_TIMEOUT) ]] && config_set --global CURL_TIMEOUT=60
if [[ -n $(config_export global) ]]; then
local BUILD_ENV+=$'\n'
local BUILD_ENV+=$(config_export global)
local BUILD_ENV+=$'\n'
fi
if [[ -n $(config_export app "$APP") ]]; then
local BUILD_ENV+=$'\n'
local BUILD_ENV+=$(config_export app "$APP")
local BUILD_ENV+=$'\n'
fi
dokku_log_info1 "Adding BUILD_ENV to build environment..."
# create build env files for use in buildpacks like this:
# https://github.com/niteoweb/heroku-buildpack-buildout/blob/5879fa3418f7d8e079f1aa5816ba1adde73f4948/bin/compile#L34
local id=$(config_export app "$APP" --merged --bundle | docker run "$DOKKU_GLOBAL_RUN_ARGS" -i -a stdin "$IMAGE" /bin/bash -c "mkdir -p /tmp/env; cat | tar -x -C /tmp/env")
test "$(docker wait "$id")" -eq 0
docker commit "$id" "$IMAGE" > /dev/null
if [[ ! -z "$BUILD_ENV" ]]; then
dokku_log_info1 "Adding BUILD_ENV to build environment..."
# create build env files for use in buildpacks like this:
# https://github.com/niteoweb/heroku-buildpack-buildout/blob/5879fa3418f7d8e079f1aa5816ba1adde73f4948/bin/compile#L34
local id=$(echo $BUILD_ENV | sed -e 's@export @@g' -e 's@\\n@ @g' | docker run "$DOKKU_GLOBAL_RUN_ARGS" -i -a stdin "$IMAGE" /bin/bash -c "mkdir -p /tmp/env; for ENV_VAR in $(cat); do echo \$ENV_VAR | cut -d'=' -f2- > /tmp/env/\$(echo \$ENV_VAR | cut -d'=' -f1); done " )
test "$(docker wait "$id")" -eq 0
docker commit "$id" "$IMAGE" > /dev/null
# create build env for 'old style' buildpacks and dokku plugins
local id=$(echo -e "$BUILD_ENV" | docker run "$DOKKU_GLOBAL_RUN_ARGS" -i -a stdin "$IMAGE" /bin/bash -c "cat >> /app/.env")
test "$(docker wait "$id")" -eq 0
docker commit "$id" "$IMAGE" > /dev/null
fi
# create build env for 'old style' buildpacks and dokku plugins
local id=$(config_export app "$APP" --envfile --merged --escape-newlines | docker run "$DOKKU_GLOBAL_RUN_ARGS" -i -a stdin "$IMAGE" /bin/bash -c "cat >> /app/.env")
test "$(docker wait "$id")" -eq 0
docker commit "$id" "$IMAGE" > /dev/null
}
build_env_pre_build_buildpack "$@"

View File

@@ -3,19 +3,23 @@ package configenv
import (
"errors"
"fmt"
"io"
"os"
"path/filepath"
"sort"
"strings"
"archive/tar"
common "github.com/dokku/dokku/plugins/common"
)
//Env is a representation for global or app environment
type Env struct {
name string
env map[string]string
filename string
name string
env map[string]string
filename string
EscapeNewlines bool
}
func (e *Env) String() string {
@@ -38,7 +42,11 @@ func (e *Env) StringWithPrefixAndSeparator(prefix string, separator string) stri
keys := e.Keys()
entries := make([]string, len(keys))
for i, k := range keys {
entries[i] = fmt.Sprintf("%s%s='%s'", prefix, k, SingleQuoteEscape(e.env[k]))
v := SingleQuoteEscape(e.env[k])
if e.EscapeNewlines {
v = strings.Replace(v, "\n", "'$'\\n''", -1)
}
entries[i] = fmt.Sprintf("%s%s='%s'", prefix, k, v)
}
return strings.Join(entries, separator)
}
@@ -48,7 +56,29 @@ func SingleQuoteEscape(value string) string { // so that 'esc'apped' -> 'esc'\''
return strings.Replace(value, "'", "'\\''", -1)
}
//NewFromTarget creates an env from the given target. Tareget is either "--global" or an app name
//ExportBundle writes a tarfile of the environmnet to the given io.Writer.
// for every environment variable there is a file with the variable's key
// with its content set to the variable's value
func (e *Env) ExportBundle(dest io.Writer) error {
tarfile := tar.NewWriter(dest)
defer tarfile.Close()
for _, k := range e.Keys() {
val, _ := e.Get(k)
valbin := []byte(val)
header := &tar.Header{
Name: k,
Mode: 0600,
Size: int64(len(valbin)),
}
tarfile.WriteHeader(header)
tarfile.Write(valbin)
}
return nil
}
//NewFromTarget creates an env from the given target. Target is either "--global" or an app name
func NewFromTarget(target string) (*Env, error) {
if target == "--global" {
return LoadGlobal()

View File

@@ -36,7 +36,7 @@ func parseEnvFromReader(name string, filename string, reader io.Reader) (*Env, e
StateKey = iota
StateValue = iota
)
env := &Env{name, map[string]string{}, filename}
env := &Env{name, map[string]string{}, filename, false}
var buffer bytes.Buffer
var state = StateKey
var quoted = false

View File

@@ -12,13 +12,16 @@ import (
// print the environment to stdout
func main() {
const defaultPrefix = "export "
const defaultSeparator = "\n"
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")
bundle := args.Bool("bundle", false, "--bundle: export as tar bundle")
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")
prefix := args.String("prefix", defaultPrefix, "--prefix: prefix")
separator := args.String("separator", defaultSeparator, "--separator: separator")
escapeNewlines := args.Bool("escape-newlines", false, "--escape-newlines: replace literal newlines with $'\n'")
args.Parse(os.Args[2:])
appName := args.Arg(0)
@@ -57,6 +60,16 @@ func main() {
return
}
if *escapeNewlines {
env.EscapeNewlines = true
}
if *bundle {
if *prefix != defaultPrefix || *separator != defaultSeparator || *envfile {
common.LogFail("--bundle cannot be given with --envfile, --prefix, or --separator")
}
env.ExportBundle(os.Stdout)
}
if *envfile {
if *prefix != defaultPrefix {
common.LogFail("--prefix and --envfile cannot both be given")