grim/convey

closing merged branch
hostnames
2017-10-13, Gary Kramlich
33eae19fcbbe
closing merged branch
/*
* Convey
* Copyright 2016-2017 Gary Kramlich <grim@reaperworld.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package environment
import (
"fmt"
"os"
"strings"
)
type envMapper struct {
env []string
}
func (e *envMapper) Map(name string) string {
for _, item := range e.env {
if parts := strings.SplitN(item, "=", 2); parts[0] == name {
if len(parts) == 2 {
return parts[1]
}
return os.Getenv(name)
}
}
return "$" + name
}
// Map will return the value matching a KEY=VAL pair in the given environment.
func Map(key string, env []string) string {
mapper := envMapper{env}
return mapper.Map(key)
}
// Mapper will replace ${TEMPLATE} patterns in the string with the KEY=VAL pairs
// in the given environment. This function will replace patterns recursively, so
// if VAL has the form ${TEMPLATE}, it will be replaced again.
func Mapper(str string, env []string) (string, error) {
mapper := envMapper{env}
last := str
next := os.Expand(last, mapper.Map)
prev := map[string]struct{}{}
for last != next {
if _, ok := prev[next]; ok {
return "", fmt.Errorf("infinite environment mapping loop while expanding '%s'", next)
}
last = next
next = os.Expand(last, mapper.Map)
prev[last] = struct{}{}
}
return next, nil
}
// SliceMapper calls Mapper for each item in a slice and returns a new slice.
func SliceMapper(slice []string, env []string) ([]string, error) {
mapped := []string{}
for _, template := range slice {
expanded, err := Mapper(template, env)
if err != nil {
return nil, err
}
mapped = append(mapped, expanded)
}
return mapped, nil
}