github.com/hanks177/podman/v4@v4.1.3-0.20220613032544-16d90015bc83/pkg/env/env.go (about)

     1  // Package for processing environment variables.
     2  package env
     3  
     4  // TODO: we need to add tests for this package.
     5  
     6  import (
     7  	"bufio"
     8  	"fmt"
     9  	"os"
    10  	"strings"
    11  
    12  	"github.com/pkg/errors"
    13  )
    14  
    15  const whiteSpaces = " \t"
    16  
    17  // DefaultEnvVariables returns a default environment, with $PATH and $TERM set.
    18  func DefaultEnvVariables() map[string]string {
    19  	return map[string]string{
    20  		"PATH":      "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
    21  		"TERM":      "xterm",
    22  		"container": "podman",
    23  	}
    24  }
    25  
    26  // Slice transforms the specified map of environment variables into a
    27  // slice. If a value is non-empty, the key and value are joined with '='.
    28  func Slice(m map[string]string) []string {
    29  	env := make([]string, 0, len(m))
    30  	for k, v := range m {
    31  		var s string
    32  		if len(v) > 0 {
    33  			s = fmt.Sprintf("%s=%s", k, v)
    34  		} else {
    35  			s = k
    36  		}
    37  		env = append(env, s)
    38  	}
    39  	return env
    40  }
    41  
    42  // Join joins the two environment maps with override overriding base.
    43  func Join(base map[string]string, override map[string]string) map[string]string {
    44  	if len(base) == 0 {
    45  		return override
    46  	}
    47  	for k, v := range override {
    48  		base[k] = v
    49  	}
    50  	return base
    51  }
    52  
    53  // ParseFile parses the specified path for environment variables and returns them
    54  // as a map.
    55  func ParseFile(path string) (_ map[string]string, err error) {
    56  	env := make(map[string]string)
    57  	defer func() {
    58  		if err != nil {
    59  			err = errors.Wrapf(err, "error parsing env file %q", path)
    60  		}
    61  	}()
    62  
    63  	fh, err := os.Open(path)
    64  	if err != nil {
    65  		return nil, err
    66  	}
    67  	defer fh.Close()
    68  
    69  	scanner := bufio.NewScanner(fh)
    70  	for scanner.Scan() {
    71  		// trim the line from all leading whitespace first
    72  		line := strings.TrimLeft(scanner.Text(), whiteSpaces)
    73  		// line is not empty, and not starting with '#'
    74  		if len(line) > 0 && !strings.HasPrefix(line, "#") {
    75  			if err := parseEnv(env, line); err != nil {
    76  				return nil, err
    77  			}
    78  		}
    79  	}
    80  	return env, scanner.Err()
    81  }
    82  
    83  func parseEnv(env map[string]string, line string) error {
    84  	data := strings.SplitN(line, "=", 2)
    85  
    86  	// catch invalid variables such as "=" or "=A"
    87  	if data[0] == "" {
    88  		return errors.Errorf("invalid environment variable: %q", line)
    89  	}
    90  	// trim the front of a variable, but nothing else
    91  	name := strings.TrimLeft(data[0], whiteSpaces)
    92  	if strings.ContainsAny(name, whiteSpaces) {
    93  		return errors.Errorf("name %q has white spaces, poorly formatted name", name)
    94  	}
    95  
    96  	if len(data) > 1 {
    97  		env[name] = data[1]
    98  	} else {
    99  		if strings.HasSuffix(name, "*") {
   100  			name = strings.TrimSuffix(name, "*")
   101  			for _, e := range os.Environ() {
   102  				part := strings.SplitN(e, "=", 2)
   103  				if len(part) < 2 {
   104  					continue
   105  				}
   106  				if strings.HasPrefix(part[0], name) {
   107  					env[part[0]] = part[1]
   108  				}
   109  			}
   110  		} else if val, ok := os.LookupEnv(name); ok {
   111  			// if only a pass-through variable is given, clean it up.
   112  			env[name] = val
   113  		}
   114  	}
   115  	return nil
   116  }