2017-01-16 23:13:32 -05:00
|
|
|
package configenv
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"errors"
|
|
|
|
|
"fmt"
|
|
|
|
|
"os"
|
|
|
|
|
"path/filepath"
|
|
|
|
|
"sort"
|
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (e *Env) String() string {
|
|
|
|
|
return e.EnvfileString()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//EnvfileString returns the contents of this Env in ENVFILE format
|
|
|
|
|
func (e *Env) EnvfileString() string {
|
2017-02-18 15:58:32 -05:00
|
|
|
return e.StringWithPrefixAndSeparator("", "\n")
|
2017-01-16 23:13:32 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//ExportfileString returns the contents of this Env as bash exports
|
|
|
|
|
func (e *Env) ExportfileString() string {
|
2017-02-18 15:58:32 -05:00
|
|
|
return e.StringWithPrefixAndSeparator("export ", "\n")
|
2017-01-16 23:13:32 -05:00
|
|
|
}
|
|
|
|
|
|
2017-02-18 15:58:32 -05:00
|
|
|
//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 {
|
2017-01-16 23:13:32 -05:00
|
|
|
keys := e.Keys()
|
|
|
|
|
entries := make([]string, len(keys))
|
|
|
|
|
for i, k := range keys {
|
2017-01-30 22:20:39 -05:00
|
|
|
entries[i] = fmt.Sprintf("%s%s='%s'", prefix, k, SingleQuoteEscape(e.env[k]))
|
2017-01-16 23:13:32 -05:00
|
|
|
}
|
2017-02-18 15:58:32 -05:00
|
|
|
return strings.Join(entries, separator)
|
2017-01-16 23:13:32 -05:00
|
|
|
}
|
|
|
|
|
|
2017-01-30 22:20:39 -05:00
|
|
|
//SingleQuoteEscape escapes the value as if it were shell-quoted in single quotes
|
|
|
|
|
func SingleQuoteEscape(value string) string { // so that 'esc'apped' -> 'esc'\''aped'
|
2017-01-19 00:02:56 -05:00
|
|
|
return strings.Replace(value, "'", "'\\''", -1)
|
2017-01-16 23:13:32 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//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" {
|
2017-02-18 15:58:32 -05:00
|
|
|
return LoadGlobal()
|
2017-01-16 23:13:32 -05:00
|
|
|
}
|
2017-02-18 15:58:32 -05:00
|
|
|
return LoadApp(target)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//LoadApp loads an environment for the given app
|
|
|
|
|
func LoadApp(appName string) (*Env, error) {
|
|
|
|
|
appfile, err := getAppFile(appName)
|
2017-01-16 23:13:32 -05:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2017-02-18 15:58:32 -05:00
|
|
|
return parseEnv(appName, appfile)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//LoadGlobal loads the global environmen
|
|
|
|
|
func LoadGlobal() (*Env, error) {
|
|
|
|
|
return parseEnv("global", getGlobalFile())
|
2017-01-16 23:13:32 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//NewFromString creates an env from the given ENVFILE contents representation
|
|
|
|
|
func NewFromString(rep string) (*Env, error) {
|
|
|
|
|
return parseEnvFromReader("<unknown>", "", strings.NewReader(rep))
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-18 15:58:32 -05:00
|
|
|
//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, ""))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-16 23:13:32 -05:00
|
|
|
//Set an environment variable
|
|
|
|
|
func (e *Env) Set(key string, value string) {
|
|
|
|
|
e.env[key] = value
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Unset an environment variable
|
|
|
|
|
func (e *Env) Unset(key string) {
|
|
|
|
|
delete(e.env, key)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Keys gets the keys in this environment
|
|
|
|
|
func (e *Env) Keys() []string {
|
|
|
|
|
keys := make([]string, 0, len(e.env))
|
|
|
|
|
for k := range e.env {
|
|
|
|
|
keys = append(keys, k)
|
|
|
|
|
}
|
2017-02-18 15:58:32 -05:00
|
|
|
sort.Strings(keys)
|
2017-01-16 23:13:32 -05:00
|
|
|
return keys
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Get an environment variable
|
|
|
|
|
func (e *Env) Get(key string) (string, bool) {
|
|
|
|
|
v, ok := e.env[key]
|
|
|
|
|
return v, ok
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//GetDefault an environment variable or a default if it doesnt exist
|
|
|
|
|
func (e *Env) GetDefault(key string, defaultValue string) string {
|
|
|
|
|
v, ok := e.env[key]
|
|
|
|
|
if !ok {
|
|
|
|
|
return defaultValue
|
|
|
|
|
}
|
|
|
|
|
return v
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//GetBoolDefault gets the bool value of the given key with the given default
|
|
|
|
|
//right now that is evaluated as `value != "0"`
|
|
|
|
|
func (e *Env) GetBoolDefault(key string, defaultValue bool) bool {
|
|
|
|
|
v, ok := e.Get(key)
|
|
|
|
|
if !ok {
|
|
|
|
|
return defaultValue
|
|
|
|
|
}
|
|
|
|
|
return v != "0"
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-18 15:58:32 -05:00
|
|
|
//Len return the number of items in this environment
|
|
|
|
|
func (e *Env) Len() int {
|
|
|
|
|
return len(e.env)
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-16 23:13:32 -05:00
|
|
|
//Map return the Env as a map
|
|
|
|
|
func (e *Env) Map() map[string]string {
|
|
|
|
|
return e.env
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Write an Env back to the file it was read from as an exportfile
|
|
|
|
|
func (e *Env) Write() error {
|
|
|
|
|
if e.filename == "" {
|
|
|
|
|
return errors.New("this Env was created unbound to a file")
|
|
|
|
|
}
|
|
|
|
|
file, err := os.Create(e.filename)
|
|
|
|
|
defer file.Close()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
_, err = file.WriteString(e.ExportfileString())
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func getAppFile(appName string) (string, error) {
|
|
|
|
|
err := common.VerifyAppName(appName)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return "", err
|
|
|
|
|
}
|
|
|
|
|
return filepath.Join(common.MustGetEnv("DOKKU_ROOT"), appName, "ENV"), nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func getGlobalFile() string {
|
|
|
|
|
return filepath.Join(common.MustGetEnv("DOKKU_ROOT"), "ENV")
|
|
|
|
|
}
|