github.com/awesome-flow/flow@v0.0.3-0.20190918184116-508d75d68a2c/pkg/cfg/env_provider.go (about)

     1  package cfg
     2  
     3  import (
     4  	"os"
     5  	"strings"
     6  
     7  	"github.com/awesome-flow/flow/pkg/types"
     8  )
     9  
    10  // Redefined in tests
    11  var envVars = func() []string {
    12  	return os.Environ()
    13  }
    14  
    15  func canonise(key string) string {
    16  	k := strings.Replace(key, "_", ".", -1)
    17  	k = strings.Replace(k, "..", "_", -1)
    18  	return strings.ToLower(k)
    19  }
    20  
    21  // EnvProvider reads special FLOW_ preffixed environment variables.
    22  // The contract is:
    23  // * Underscores are being transformed to dots in key part (before the first =).
    24  // * There must be exactly 1 `=` sign.
    25  // * Double underscores are converted to singulars and preserved with no dot-conversion.
    26  type EnvProvider struct {
    27  	weight   int
    28  	registry map[string]types.Value
    29  	ready    chan struct{}
    30  }
    31  
    32  var _ Provider = (*EnvProvider)(nil)
    33  
    34  // NewEnvProvider returns a new instance of EnvProvider.
    35  func NewEnvProvider(repo *Repository, weight int) (*EnvProvider, error) {
    36  	prov := &EnvProvider{
    37  		weight: weight,
    38  		ready:  make(chan struct{}),
    39  	}
    40  	repo.RegisterProvider(prov)
    41  
    42  	return prov, nil
    43  }
    44  
    45  // Name returns provider name: env
    46  func (ep *EnvProvider) Name() string { return "env" }
    47  
    48  // Depends returns provider dependencies: default
    49  func (ep *EnvProvider) Depends() []string { return []string{"default"} }
    50  
    51  // Weight returns provider weight
    52  func (ep *EnvProvider) Weight() int { return ep.weight }
    53  
    54  // SetUp takes the list of env vars and canonizes them before registration in
    55  // repo. Env vars are expected to be in form FLOW_<K>=<v>. FLOW_ preffix
    56  // would be cleared out.
    57  func (ep *EnvProvider) SetUp(repo *Repository) error {
    58  	defer close(ep.ready)
    59  	registry := make(map[string]types.Value)
    60  	var k string
    61  	var v interface{}
    62  
    63  	for _, kv := range envVars() {
    64  		if !strings.HasPrefix(kv, "FLOW_") {
    65  			continue
    66  		}
    67  		// Clear out "FLOW_"
    68  		kv = kv[5:]
    69  		if ix := strings.Index(kv, "="); ix != -1 {
    70  			k, v = kv[:ix], kv[ix+1:]
    71  		} else {
    72  			k, v = kv, true
    73  		}
    74  		k = canonise(k)
    75  		registry[k] = v
    76  		if repo != nil {
    77  			if err := repo.RegisterKey(types.NewKey(k), ep); err != nil {
    78  				return err
    79  			}
    80  		}
    81  	}
    82  
    83  	ep.registry = registry
    84  
    85  	return nil
    86  }
    87  
    88  // TearDown is a no-op operation for CliProvider
    89  func (ep *EnvProvider) TearDown(_ *Repository) error { return nil }
    90  
    91  // Get is the primary method to fetch values from the provider registry.
    92  func (ep *EnvProvider) Get(key types.Key) (*types.KeyValue, bool) {
    93  	<-ep.ready
    94  	if val, ok := ep.registry[key.String()]; ok {
    95  		return &types.KeyValue{Key: key, Value: val}, ok
    96  	}
    97  	return nil, false
    98  }